Loading docs/dev/events.md +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading src/config/config.ts +7 −3 Original line number Diff line number Diff line Loading @@ -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; } Loading src/engine/engine.spec.ts +16 −6 Original line number Diff line number Diff line Loading @@ -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> { Loading Loading @@ -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", () => { Loading Loading @@ -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", Loading src/engine/engine.ts +24 −2 Original line number Diff line number Diff line 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"; Loading Loading @@ -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); Loading Loading @@ -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, Loading src/event/event.ts +10 −0 Original line number Diff line number Diff line import { ConfigData } from "../config"; import { Location } from "../context"; import { DOMTree, DynamicValue, HtmlElement } from "../dom"; import { Rule } from "../rule"; /** * @hidden Loading @@ -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. */ Loading Loading
docs/dev/events.md +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
src/config/config.ts +7 −3 Original line number Diff line number Diff line Loading @@ -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; } Loading
src/engine/engine.spec.ts +16 −6 Original line number Diff line number Diff line Loading @@ -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> { Loading Loading @@ -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", () => { Loading Loading @@ -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", Loading
src/engine/engine.ts +24 −2 Original line number Diff line number Diff line 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"; Loading Loading @@ -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); Loading Loading @@ -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, Loading
src/event/event.ts +10 −0 Original line number Diff line number Diff line import { ConfigData } from "../config"; import { Location } from "../context"; import { DOMTree, DynamicValue, HtmlElement } from "../dom"; import { Rule } from "../rule"; /** * @hidden Loading @@ -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. */ Loading