Skip to content

Commit 173e35b

Browse files
antrossmolant
authored andcommitted
New: Include element reference if source was inline in HTML
Allow hints for CSS and JavaScript source to correctly offset the location of reported issues nested inside an HTML document. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Close #1953
1 parent a5d2ab0 commit 173e35b

File tree

9 files changed

+26
-11
lines changed

9 files changed

+26
-11
lines changed

packages/parser-css/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ This `parser` emits the following events:
4242
See the [PostCSS `walk*` APIs][postcss-walk] for help navigating
4343
the AST.
4444
* `code`: a string containing the raw stylesheet source code.
45+
* `element`: an `IAsyncHTMLElement` reference if the source was inline in HTML; `null` otherwise.
4546
* `resource`: the parsed resource. If the CSS is in a `style tag`
4647
and not a file, the value will be `Inline CSS`.
4748

packages/parser-css/src/parser.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default class CSSParser extends Parser<StyleEvents> {
2020
engine.on('element::style', this.parseStyleTag.bind(this));
2121
}
2222

23-
private async emitCSS(code: string, resource: string) {
23+
private async emitCSS(code: string, resource: string, element: IAsyncHTMLElement | null) {
2424

2525
try {
2626
await this.engine.emitAsync(`parse::start::css`, { resource });
@@ -31,6 +31,7 @@ export default class CSSParser extends Parser<StyleEvents> {
3131
await this.engine.emitAsync(`parse::end::css`, {
3232
ast,
3333
code,
34+
element,
3435
resource
3536
});
3637

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

46-
await this.emitCSS(code, resource);
47+
await this.emitCSS(code, resource, null);
4748
}
4849

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

79-
await this.emitCSS(code, resource);
80+
await this.emitCSS(code, resource, element);
8081
}
8182
}

packages/parser-css/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { IAsyncHTMLElement } from 'hint/dist/src/lib/types';
12
import { Event, Events } from 'hint/dist/src/lib/types/events';
23
import { Root } from 'postcss';
34

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

1619
export type StyleEvents = Events & {

packages/parser-css/tests/helpers/mocks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ export const mockStyleElement = (type: string, code: string) => {
88
outerHTML() {
99
return Promise.resolve(`<style> ${code} </style>`);
1010
}
11-
} as Partial<IAsyncHTMLElement>;
11+
} as Partial<IAsyncHTMLElement> as IAsyncHTMLElement;
1212
};

packages/parser-css/tests/interface-tests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ test('If a style tag is inline CSS, then we should parse the stylesheet and emit
7777

7878
t.is(args[0], 'parse::end::css');
7979
t.is(data.code, code);
80+
t.is(data.element, element);
8081
t.is(data.resource, 'Inline CSS');
8182
});
8283

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

106107
t.is(args[0], 'parse::end::css');
107108
t.is(data.code, code);
109+
t.is(data.element, null);
108110
t.is(data.resource, 'styles.css');
109111
});

packages/parser-javascript/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ This `parser` emits the following events:
4040
* `parse::end::javascript`, of type `ScriptParse` which contains the following
4141
information:
4242

43-
* `resource`: the parsed resource. If the JavaScript is in
44-
a `script tag` and not a file, the value will be `Internal
45-
javascript`.
46-
* `sourceCode`: a `eslint` `SourceCode` object.
43+
* `ast`: an ESLint `AST.Program` object containing the parsed AST.
44+
* `element`: an `IAsyncHTMLElement` reference if the source was inline in HTML; `null` otherwise.
45+
* `resource`: the parsed resource. If the JavaScript is in
46+
a `script tag` and not a file, the value will be `Internal
47+
javascript`.
48+
* `sourceCode`: a `eslint` `SourceCode` object.
4749

4850
<!-- Link labels: -->
4951

packages/parser-javascript/src/parser.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ export default class JavascriptParser extends Parser<ScriptEvents> {
2828
engine.on('element::script', this.parseJavascriptTag.bind(this));
2929
}
3030

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

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

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

51-
await this.emitScript(code, resource);
52+
await this.emitScript(code, resource, null);
5253
}
5354

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

94-
await this.emitScript(code, resource);
95+
await this.emitScript(code, resource, element);
9596
}
9697
}

packages/parser-javascript/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { AST, SourceCode } from 'eslint';
22

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

56
/** The object emitted by the `javascript` parser */
67
export type ScriptParse = Event & {
78
/** The ast generated from the script */
89
ast: AST.Program;
10+
/** The originating <script> element if the script was inline */
11+
element: IAsyncHTMLElement | null;
912
/** The source code parsed */
1013
sourceCode: SourceCode;
1114
};

packages/parser-javascript/tests/tests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ test('If an script tag is an internal javascript, then we should parse the code
151151
const data = args[1] as ScriptParse;
152152

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

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

0 commit comments

Comments
 (0)