Skip to content

Commit 935b6f4

Browse files
authored
Upgrade esquery and use new option (#100)
1 parent 5724851 commit 935b6f4

File tree

8 files changed

+122
-13
lines changed

8 files changed

+122
-13
lines changed

.eslintrc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ overrides:
1515
"@typescript-eslint/no-duplicate-imports": error
1616
- files: "typings/**"
1717
rules:
18-
node/no-missing-import:
18+
'@mysticatea/node/no-missing-import':
1919
- error
2020
- allowModules:
2121
- estree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"eslint-scope": "^5.0.0",
1818
"eslint-visitor-keys": "^1.1.0",
1919
"espree": "^6.2.1",
20-
"esquery": "^1.0.1",
20+
"esquery": "^1.4.0",
2121
"lodash": "^4.17.15"
2222
},
2323
"devDependencies": {

src/ast/traverse.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { Node } from "./nodes"
1111
// Helpers
1212
//------------------------------------------------------------------------------
1313

14-
const KEYS = Evk.unionWith({
14+
export const KEYS = Evk.unionWith({
1515
VAttribute: ["key", "value"],
1616
VDirectiveKey: ["name", "argument", "modifiers"],
1717
VDocumentFragment: ["children"],

src/external/node-event-generator.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* This file is copied from `eslint/lib/util/node-event-generator.js`
33
*/
44
import EventEmitter from "events"
5-
import esquery, {Selector} from "esquery"
5+
import esquery, {ESQueryOptions, Selector} from "esquery"
66
import union from "lodash/union"
77
import intersection from "lodash/intersection"
88
import memoize from "lodash/memoize"
@@ -187,6 +187,7 @@ const parseSelector = memoize<(rawSelector: string) => NodeSelector>(rawSelector
187187
*/
188188
export default class NodeEventGenerator {
189189
emitter: EventEmitter
190+
esqueryOptions: ESQueryOptions
190191

191192
private currentAncestry: Node[]
192193
private enterSelectorsByNodeType: Map<string, NodeSelector[]>
@@ -198,8 +199,9 @@ export default class NodeEventGenerator {
198199
* @param emitter - An event emitter which is the destination of events. This emitter must already
199200
* have registered listeners for all of the events that it needs to listen for.
200201
*/
201-
constructor(emitter: EventEmitter) {
202+
constructor(emitter: EventEmitter, esqueryOptions: ESQueryOptions) {
202203
this.emitter = emitter
204+
this.esqueryOptions = esqueryOptions
203205
this.currentAncestry = []
204206
this.enterSelectorsByNodeType = new Map()
205207
this.exitSelectorsByNodeType = new Map()
@@ -260,7 +262,7 @@ export default class NodeEventGenerator {
260262
* @param selector An AST selector descriptor
261263
*/
262264
private applySelector(node: Node, selector: NodeSelector): void {
263-
if (esquery.matches(node, selector.parsedSelector, this.currentAncestry)) {
265+
if (esquery.matches(node, selector.parsedSelector, this.currentAncestry, this.esqueryOptions)) {
264266
this.emitter.emit(selector.rawSelector, node)
265267
}
266268
}

src/parser-services.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
VDocumentFragment,
1414
VAttribute,
1515
} from "./ast"
16-
import { traverseNodes } from "./ast"
16+
import { getFallbackKeys, KEYS, traverseNodes } from "./ast/traverse"
1717
import type { LocationCalculator } from "./common/location-calculator"
1818
import type {
1919
CustomBlockContext,
@@ -149,6 +149,10 @@ export function define(
149149
// Traverse template body.
150150
const generator = new NodeEventGenerator(
151151
emitter as EventEmitter,
152+
{
153+
visitorKeys: KEYS,
154+
fallback: getFallbackKeys,
155+
},
152156
)
153157
traverseNodes(
154158
rootAST.templateBody as VElement,
@@ -273,7 +277,10 @@ export function define(
273277
}
274278

275279
// Traverse custom block.
276-
const generator = new NodeEventGenerator(emitter)
280+
const generator = new NodeEventGenerator(emitter, {
281+
visitorKeys: parsedResult.visitorKeys,
282+
fallback: getFallbackKeys,
283+
})
277284
traverseNodes(parsedResult.ast, {
278285
visitorKeys: parsedResult.visitorKeys,
279286
enterNode(n) {

test/define-custom-blocks-visitor.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ const noProgramExitRule = {
9696
}
9797
},
9898
}
99+
const siblingSelectorRule = {
100+
create(context) {
101+
return {
102+
"* ~ *"(node) {
103+
context.report({
104+
node,
105+
message: "* ~ *",
106+
})
107+
},
108+
}
109+
},
110+
}
99111

100112
function createLinter(target = "json") {
101113
const linter = new Linter()
@@ -417,6 +429,36 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => {
417429
)
418430
})
419431

432+
it("should work even if used sibling selector.", () => {
433+
const code = `
434+
<i18n lang="json">
435+
[42, 42]
436+
</i18n>
437+
`
438+
const linter = createLinter()
439+
linter.defineRule("test-for-sibling-selector", (context) =>
440+
context.parserServices.defineCustomBlocksVisitor(
441+
context,
442+
jsonParser,
443+
{
444+
target: "json",
445+
create: siblingSelectorRule.create,
446+
}
447+
)
448+
)
449+
const messages = linter.verify(code, {
450+
...LINTER_CONFIG,
451+
rules: {
452+
"test-for-sibling-selector": "error",
453+
},
454+
})
455+
456+
assert.strictEqual(messages.length, 1)
457+
assert.strictEqual(messages[0].message, "* ~ *")
458+
assert.strictEqual(messages[0].line, 3)
459+
assert.strictEqual(messages[0].column, 6)
460+
})
461+
420462
describe("API tests", () => {
421463
it("should work getAncestors().", () => {
422464
const code = `

test/index.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,5 +614,33 @@ describe("Basic tests", () => {
614614
assert.strictEqual(messages2.length, 1)
615615
assert.strictEqual(messages2[0].message, "OK")
616616
})
617+
618+
it("should work even if used sibling selector.", () => {
619+
const code = "<template><div/><div/></template>"
620+
const config = {
621+
parser: PARSER_PATH,
622+
rules: {
623+
"test-rule": "error",
624+
},
625+
}
626+
const linter = new Linter()
627+
628+
linter.defineParser(PARSER_PATH, require(PARSER_PATH))
629+
linter.defineRule("test-rule", (context) =>
630+
context.parserServices.defineTemplateBodyVisitor({
631+
"* ~ *"(node) {
632+
context.report({ node, message: "OK" })
633+
},
634+
})
635+
)
636+
637+
const messages1 = linter.verify(code, config)
638+
const messages2 = linter.verify(linter.getSourceCode(), config)
639+
640+
assert.strictEqual(messages1.length, 1)
641+
assert.strictEqual(messages1[0].message, "OK")
642+
assert.strictEqual(messages2.length, 1)
643+
assert.strictEqual(messages2[0].message, "OK")
644+
})
617645
})
618646
})

typings/esquery/index.d.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,32 @@
44
* See LICENSE file in root directory for full license.
55
*/
66

7-
export type Selector = AdjacentSelector | AttributeSelector | ChildSelector | ClassSelector | CompoundSelector | DescendantSelector | FieldSelector | HasSelector | IdentifierSelector | MatchesSelector | NotSelector | NthChildSelector | NthLastChildSelector | SiblingSelector | WildcardSelector
7+
import type { Node } from "../../src/ast"
8+
// eslint-disable-next-line @mysticatea/node/no-missing-import
9+
import type { VisitorKeys } from "../eslint-visitor-keys"
10+
11+
export type Selector =
12+
| AdjacentSelector
13+
| AttributeSelector
14+
| ChildSelector
15+
| ClassSelector
16+
| CompoundSelector
17+
| DescendantSelector
18+
| FieldSelector
19+
| HasSelector
20+
| IdentifierSelector
21+
| MatchesSelector
22+
| NotSelector
23+
| NthChildSelector
24+
| NthLastChildSelector
25+
| SiblingSelector
26+
| WildcardSelector
27+
28+
export type TraverseOptionFallback = (node: Node) => readonly string[]
29+
export interface ESQueryOptions {
30+
visitorKeys?: VisitorKeys
31+
fallback?: TraverseOptionFallback
32+
}
833

934
export interface AdjacentSelector {
1035
type: "adjacent"
@@ -16,7 +41,7 @@ export interface AttributeSelector {
1641
type: "attribute"
1742
name: string
1843
operator: string | null | undefined
19-
value: { type: string, value: any }
44+
value: { type: string; value: any }
2045
}
2146

2247
export interface ChildSelector {
@@ -68,13 +93,13 @@ export interface NotSelector {
6893
export interface NthChildSelector {
6994
type: "nth-child"
7095
right: Selector
71-
index: { type: string, value: any }
96+
index: { type: string; value: any }
7297
}
7398

7499
export interface NthLastChildSelector {
75100
type: "nth-last-child"
76101
right: Selector
77-
index: { type: string, value: any }
102+
index: { type: string; value: any }
78103
}
79104

80105
export interface SiblingSelector {
@@ -89,6 +114,11 @@ export interface WildcardSelector {
89114

90115
declare const esquery: {
91116
parse(query: string): Selector
92-
matches(node: object, selector: Selector, ancestry: object[]): boolean
117+
matches(
118+
node: object,
119+
selector: Selector,
120+
ancestry: object[],
121+
options?: ESQueryOptions,
122+
): boolean
93123
}
94124
export default esquery

0 commit comments

Comments
 (0)