Skip to content

Commit

Permalink
New: Include element reference if source was inline in HTML
Browse files Browse the repository at this point in the history
Allows hints for CSS and JavaScript source to correctly offset the
location of reported issues nested inside an HTML document.
  • Loading branch information
antross committed Feb 21, 2019
1 parent 1de5a33 commit 7c3e36f
Show file tree
Hide file tree
Showing 9 changed files with 25 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/parser-css/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ This `parser` emits the following events:
See the [PostCSS `walk*` APIs][postcss-walk] for help navigating
the AST.
* `code`: a string containing the raw stylesheet source code.
* `element`: an `IAsyncHTMLElement` reference if the source was inline in HTML; `null` otherwise.
* `resource`: the parsed resource. If the CSS is in a `style tag`
and not a file, the value will be `Inline CSS`.

Expand Down
7 changes: 4 additions & 3 deletions packages/parser-css/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default class CSSParser extends Parser<StyleEvents> {
engine.on('element::style', this.parseStyleTag.bind(this));
}

private async emitCSS(code: string, resource: string) {
private async emitCSS(code: string, resource: string, element: IAsyncHTMLElement | null) {

try {
await this.engine.emitAsync(`parse::start::css`, { resource });
Expand All @@ -31,6 +31,7 @@ export default class CSSParser extends Parser<StyleEvents> {
await this.engine.emitAsync(`parse::end::css`, {
ast,
code,
element,
resource
});

Expand All @@ -43,7 +44,7 @@ export default class CSSParser extends Parser<StyleEvents> {
const code = fetchEnd.response.body.content;
const resource = fetchEnd.resource;

await this.emitCSS(code, resource);
await this.emitCSS(code, resource, null);
}

private isCSSType(element: IAsyncHTMLElement) {
Expand Down Expand Up @@ -76,6 +77,6 @@ export default class CSSParser extends Parser<StyleEvents> {
const code = this.getStyleContent(await element.outerHTML());
const resource: string = 'Inline CSS';

await this.emitCSS(code, resource);
await this.emitCSS(code, resource, element);
}
}
3 changes: 3 additions & 0 deletions packages/parser-css/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IAsyncHTMLElement } from 'hint/dist/src/lib/types';
import { Event, Events } from 'hint/dist/src/lib/types/events';
import { Root } from 'postcss';

Expand All @@ -11,6 +12,8 @@ export type StyleParse = Event & {
ast: Root;
/** The raw stylesheet source code */
code: string;
/** The originating <style> element if the CSS was inline */
element: IAsyncHTMLElement | null;
};

export type StyleEvents = Events & {
Expand Down
2 changes: 1 addition & 1 deletion packages/parser-css/tests/helpers/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ export const mockStyleElement = (type: string, code: string) => {
outerHTML() {
return Promise.resolve(`<style> ${code} </style>`);
}
} as Partial<IAsyncHTMLElement>;
} as Partial<IAsyncHTMLElement> as IAsyncHTMLElement;
};
2 changes: 2 additions & 0 deletions packages/parser-css/tests/interface-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ test('If a style tag is inline CSS, then we should parse the stylesheet and emit

t.is(args[0], 'parse::end::css');
t.is(data.code, code);
t.is(data.element, element);
t.is(data.resource, 'Inline CSS');
});

Expand Down Expand Up @@ -105,5 +106,6 @@ test('If fetch::end::css is received, then we should parse the stylesheet and em

t.is(args[0], 'parse::end::css');
t.is(data.code, code);
t.is(data.element, null);
t.is(data.resource, 'styles.css');
});
9 changes: 5 additions & 4 deletions packages/parser-javascript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ This `parser` emits the following events:
* `parse::end::javascript`, of type `ScriptParse` which contains the following
information:

* `resource`: the parsed resource. If the JavaScript is in
a `script tag` and not a file, the value will be `Internal
javascript`.
* `sourceCode`: a `eslint` `SourceCode` object.
* `element`: an `IAsyncHTMLElement` reference if the source was inline in HTML; `null` otherwise.
* `resource`: the parsed resource. If the JavaScript is in
a `script tag` and not a file, the value will be `Internal
javascript`.
* `sourceCode`: a `eslint` `SourceCode` object.

<!-- Link labels: -->

Expand Down
7 changes: 4 additions & 3 deletions packages/parser-javascript/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ export default class JavascriptParser extends Parser<ScriptEvents> {
engine.on('element::script', this.parseJavascriptTag.bind(this));
}

private async emitScript(code: string, resource: string) {
private async emitScript(code: string, resource: string, element: IAsyncHTMLElement | null) {
try {
await this.engine.emitAsync(`parse::start::javascript`, { resource });

const ast: AST.Program = espree.parse(code, defaultParserOptions);

await this.engine.emitAsync(`parse::end::javascript`, {
ast,
element,
resource,
sourceCode: new SourceCode(code, ast)
});
Expand All @@ -48,7 +49,7 @@ export default class JavascriptParser extends Parser<ScriptEvents> {
const code = fetchEnd.response.body.content;
const resource = fetchEnd.resource;

await this.emitScript(code, resource);
await this.emitScript(code, resource, null);
}

private hasSrcAttribute(element: IAsyncHTMLElement) {
Expand Down Expand Up @@ -91,6 +92,6 @@ export default class JavascriptParser extends Parser<ScriptEvents> {
const code = this.getScriptContent(await element.outerHTML());
const resource: string = 'Internal javascript';

await this.emitScript(code, resource);
await this.emitScript(code, resource, element);
}
}
3 changes: 3 additions & 0 deletions packages/parser-javascript/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { AST, SourceCode } from 'eslint';

import { IAsyncHTMLElement } from 'hint/dist/src/lib/types';
import { Event, Events } from 'hint/dist/src/lib/types/events';

/** The object emitted by the `javascript` parser */
export type ScriptParse = Event & {
/** The ast generated from the script */
ast: AST.Program;
/** The originating <script> element if the script was inline */
element: IAsyncHTMLElement | null;
/** The source code parsed */
sourceCode: SourceCode;
};
Expand Down
2 changes: 2 additions & 0 deletions packages/parser-javascript/tests/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ test('If an script tag is an internal javascript, then we should parse the code
const data = args[1] as ScriptParse;

t.is(args[0], 'parse::end::javascript');
t.is(data.element, t.context.element);
t.is(data.resource, 'Internal javascript');
t.is(data.sourceCode, sourceCodeObject);
});
Expand Down Expand Up @@ -189,6 +190,7 @@ test('If fetch::end::script is received, then we should parse the code and emit
const data = args[1] as ScriptParse;

t.is(args[0], 'parse::end::javascript');
t.is(data.element, null);
t.is(data.sourceCode, sourceCodeObject);
t.is(data.resource, 'script.js');
});

0 comments on commit 7c3e36f

Please sign in to comment.