Commit c2990b58 authored by David Sveningsson's avatar David Sveningsson

feat(event): new event config:ready

parent b44567b6
Pipeline #82523405 passed with stages
in 7 minutes and 48 seconds
......@@ -5,6 +5,17 @@
# Events
## `config:ready`
```typescript
{
config: ConfigData;
rules: { [ruleId: string]: Rule };
}
```
Emitted after after configuration is ready but before DOM is initialized.
## `dom:load`
```typescript
......
......@@ -240,9 +240,13 @@ export class Config {
public get(): ConfigData {
const config = Object.assign({}, this.config);
if (config.elements) {
config.elements = config.elements.map((cur: string) =>
cur.replace(this.rootDir, "<rootDir>")
);
config.elements = config.elements.map((cur: string | object) => {
if (typeof cur === "string") {
return cur.replace(this.rootDir, "<rootDir>");
} else {
return cur;
}
});
}
return config;
}
......
......@@ -37,11 +37,6 @@ class MockParser extends Parser {
return super.parseHtml(source);
}
}
/* exposed for testing */
public trigger(event: any, data: any): void {
return super.trigger(event, data);
}
}
class ExposedEngine<T extends Parser> extends Engine<T> {
......@@ -113,6 +108,21 @@ describe("Engine", () => {
expect(report).toBeInvalid();
expect(report).toHaveError("close-order", expect.any(String));
});
it("should generate config:ready event", () => {
const source: Source[] = [inline("<div></div>")];
const parser = new Parser(config);
const spy = jest.fn();
parser.on("config:ready", spy);
jest.spyOn(engine, "instantiateParser").mockReturnValue(parser);
engine.lint(source);
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith("config:ready", {
location: null,
config: config.get(),
rules: expect.anything(),
});
});
});
describe("directive", () => {
......@@ -368,7 +378,7 @@ describe("Engine", () => {
engine.requireRule = jest.fn(() => null);
engine.loadRule("void", Severity.ERROR, {}, parser, reporter);
const add = jest.spyOn(reporter, "add");
parser.trigger("dom:load", { location: {} });
parser.trigger("dom:load", { location: null });
expect(add).toHaveBeenCalledWith(
expect.any(Rule),
"Definition for rule 'void' was not found",
......
import { Config, Severity } from "../config";
import { Location, Source } from "../context";
import { HtmlElement } from "../dom";
import { DirectiveEvent, TagCloseEvent, TagOpenEvent } from "../event";
import {
ConfigReadyEvent,
DirectiveEvent,
TagCloseEvent,
TagOpenEvent,
} from "../event";
import { InvalidTokenError, Lexer, TokenType } from "../lexer";
import { Parser } from "../parser";
import { Report, Reporter } from "../reporter";
......@@ -45,11 +50,19 @@ export class Engine<T extends Parser = Parser> {
public lint(sources: Source[]): Report {
for (const source of sources) {
/* create parser for source */
const parser = new this.ParserClass(this.config);
const parser = this.instantiateParser();
/* setup plugins and rules */
const { rules } = this.setupPlugins(source, this.config, parser);
/* trigger configuration ready event */
const event: ConfigReadyEvent = {
location: null,
config: this.config.get(),
rules,
};
parser.trigger("config:ready", event);
/* setup directive handling */
parser.on("directive", (_: string, event: DirectiveEvent) => {
this.processDirective(event, parser, rules);
......@@ -154,6 +167,15 @@ export class Engine<T extends Parser = Parser> {
}
}
/**
* Create a new parser instance with the current configuration.
*
* @hidden
*/
public instantiateParser(): Parser {
return new this.ParserClass(this.config);
}
private processDirective(
event: DirectiveEvent,
parser: Parser,
......
import { ConfigData } from "../config";
import { Location } from "../context";
import { DOMTree, DynamicValue, HtmlElement } from "../dom";
import { Rule } from "../rule";
/**
* @hidden
......@@ -9,6 +11,14 @@ export interface Event {
location: Location;
}
/**
* Configuration ready event.
*/
export interface ConfigReadyEvent extends Event {
config: ConfigData;
rules: { [ruleId: string]: Rule };
}
/**
* Event emitted when opening tags are encountered.
*/
......
......@@ -5,6 +5,7 @@ import { DOMTree, HtmlElement, NodeClosed } from "../dom";
import {
AttributeEvent,
ConditionalEvent,
ConfigReadyEvent,
DirectiveEvent,
DoctypeEvent,
DOMReadyEvent,
......@@ -522,17 +523,18 @@ export class Parser {
* @param {string} event - Event name
* @param {Event} data - Event data
*/
protected trigger(event: "tag:open", data: TagOpenEvent): void;
protected trigger(event: "tag:close", data: TagCloseEvent): void;
protected trigger(event: "element:ready", data: ElementReadyEvent): void;
protected trigger(event: "dom:load", data: Event): void;
protected trigger(event: "dom:ready", data: DOMReadyEvent): void;
protected trigger(event: "doctype", data: DoctypeEvent): void;
protected trigger(event: "attr", data: AttributeEvent): void;
protected trigger(event: "whitespace", data: WhitespaceEvent): void;
protected trigger(event: "conditional", data: ConditionalEvent): void;
protected trigger(event: "directive", data: DirectiveEvent): void;
protected trigger(event: any, data: any): void {
public trigger(event: "config:ready", data: ConfigReadyEvent): void;
public trigger(event: "tag:open", data: TagOpenEvent): void;
public trigger(event: "tag:close", data: TagCloseEvent): void;
public trigger(event: "element:ready", data: ElementReadyEvent): void;
public trigger(event: "dom:load", data: Event): void;
public trigger(event: "dom:ready", data: DOMReadyEvent): void;
public trigger(event: "doctype", data: DoctypeEvent): void;
public trigger(event: "attr", data: AttributeEvent): void;
public trigger(event: "whitespace", data: WhitespaceEvent): void;
public trigger(event: "conditional", data: ConditionalEvent): void;
public trigger(event: "directive", data: DirectiveEvent): void;
public trigger(event: any, data: any): void {
if (typeof data.location === "undefined") {
throw Error("Triggered event must contain location");
}
......
......@@ -12,6 +12,7 @@ import {
TagCloseEvent,
TagOpenEvent,
WhitespaceEvent,
ConfigReadyEvent,
} from "./event";
import { Parser } from "./parser";
import { Reporter } from "./reporter";
......@@ -117,6 +118,10 @@ export abstract class Rule<T = any> {
*
* @param event - Event name
*/
public on(
event: "config:ready",
callback: (event: ConfigReadyEvent) => void
): void;
public on(event: "tag:open", callback: (event: TagOpenEvent) => void): void;
public on(event: "tag:close", callback: (event: TagCloseEvent) => void): void;
public on(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment