@@ -79,6 +79,41 @@ function getCoreRule(name) {
79
79
return map . get ( name ) || null
80
80
}
81
81
82
+ /**
83
+ * @template {object} T
84
+ * @param {T } target
85
+ * @param {Partial<T>[] } propsArray
86
+ * @returns {T }
87
+ */
88
+ function newProxy ( target , ...propsArray ) {
89
+ const result = new Proxy (
90
+ { } ,
91
+ {
92
+ get ( _object , key ) {
93
+ for ( const props of propsArray ) {
94
+ if ( key in props ) {
95
+ // @ts -expect-error
96
+ return props [ key ]
97
+ }
98
+ }
99
+ // @ts -expect-error
100
+ return target [ key ]
101
+ } ,
102
+
103
+ has ( _object , key ) {
104
+ return key in target
105
+ } ,
106
+ ownKeys ( _object ) {
107
+ return Reflect . ownKeys ( target )
108
+ } ,
109
+ getPrototypeOf ( _object ) {
110
+ return Reflect . getPrototypeOf ( target )
111
+ }
112
+ }
113
+ )
114
+ return /** @type {T } */ ( result )
115
+ }
116
+
82
117
/**
83
118
* Wrap the rule context object to override methods which access to tokens (such as getTokenAfter).
84
119
* @param {RuleContext } context The rule context object.
@@ -147,18 +182,16 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
147
182
} )
148
183
return result
149
184
}
150
- const sourceCode = new Proxy ( Object . assign ( { } , eslintSourceCode ) , {
151
- get ( _object , key ) {
152
- if ( key === 'tokensAndComments' ) {
185
+ const sourceCode = newProxy (
186
+ eslintSourceCode ,
187
+ {
188
+ get tokensAndComments ( ) {
153
189
return getTokensAndComments ( )
154
- }
155
- if ( key === 'getNodeByRangeIndex' ) {
156
- return getNodeByRangeIndex
157
- }
158
- // @ts -expect-error
159
- return key in tokenStore ? tokenStore [ key ] : eslintSourceCode [ key ]
160
- }
161
- } )
190
+ } ,
191
+ getNodeByRangeIndex
192
+ } ,
193
+ tokenStore
194
+ )
162
195
163
196
const containerScopes = new WeakMap ( )
164
197
@@ -183,23 +216,13 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
183
216
const eslintScope = createRequire ( require . resolve ( 'eslint' ) ) (
184
217
'eslint-scope'
185
218
)
186
- const expStmt = new Proxy ( exprContainer , {
187
- get ( _object , key ) {
188
- if ( key === 'type' ) {
189
- return 'ExpressionStatement'
190
- }
191
- // @ts -expect-error
192
- return exprContainer [ key ]
193
- }
219
+ const expStmt = newProxy ( exprContainer , {
220
+ // @ts -expect-error
221
+ type : 'ExpressionStatement'
194
222
} )
195
- const scopeProgram = new Proxy ( programNode , {
196
- get ( _object , key ) {
197
- if ( key === 'body' ) {
198
- return [ expStmt ]
199
- }
200
- // @ts -expect-error
201
- return programNode [ key ]
202
- }
223
+ const scopeProgram = newProxy ( programNode , {
224
+ // @ts -expect-error
225
+ body : [ expStmt ]
203
226
} )
204
227
const scope = eslintScope . analyze ( scopeProgram , {
205
228
ignoreEval : true ,
@@ -218,9 +241,7 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
218
241
219
242
return null
220
243
}
221
- return {
222
- // @ts -expect-error
223
- __proto__ : context ,
244
+ return newProxy ( context , {
224
245
getSourceCode ( ) {
225
246
return sourceCode
226
247
} ,
@@ -232,7 +253,7 @@ function wrapContextToOverrideTokenMethods(context, tokenStore, options) {
232
253
233
254
return context . getDeclaredVariables ( node )
234
255
}
235
- }
256
+ } )
236
257
}
237
258
238
259
/**
@@ -262,9 +283,7 @@ function wrapContextToOverrideReportMethodToSkipDynamicArgument(context) {
262
283
leaveNode ( ) { }
263
284
} )
264
285
265
- return {
266
- // @ts -expect-error
267
- __proto__ : context ,
286
+ return newProxy ( context , {
268
287
report ( descriptor , ...args ) {
269
288
let range = null
270
289
if ( descriptor . loc ) {
@@ -289,7 +308,7 @@ function wrapContextToOverrideReportMethodToSkipDynamicArgument(context) {
289
308
}
290
309
context . report ( descriptor , ...args )
291
310
}
292
- }
311
+ } )
293
312
}
294
313
295
314
// ------------------------------------------------------------------------------
@@ -322,6 +341,25 @@ module.exports = {
322
341
*/
323
342
defineDocumentVisitor,
324
343
344
+ /**
345
+ * @callback WrapCoreRuleCreate
346
+ * @param {RuleContext } ruleContext
347
+ * @param {WrapCoreRuleCreateContext } wrapContext
348
+ * @returns {TemplateListener }
349
+ *
350
+ * @typedef {object } WrapCoreRuleCreateContext
351
+ * @property {RuleListener } coreHandlers
352
+ */
353
+ /**
354
+ * @callback WrapCoreRulePreprocess
355
+ * @param {RuleContext } ruleContext
356
+ * @param {WrapCoreRulePreprocessContext } wrapContext
357
+ * @returns {void }
358
+ *
359
+ * @typedef {object } WrapCoreRulePreprocessContext
360
+ * @property { (override: Partial<RuleContext>) => RuleContext } wrapContextToOverrideProperties Wrap the rule context object to override
361
+ * @property { (visitor: TemplateListener) => void } defineVisitor Define template body visitor
362
+ */
325
363
/**
326
364
* Wrap a given core rule to apply it to Vue.js template.
327
365
* @param {string } coreRuleName The name of the core rule implementation to wrap.
@@ -330,7 +368,8 @@ module.exports = {
330
368
* @param {boolean } [options.skipDynamicArguments] If `true`, skip validation within dynamic arguments.
331
369
* @param {boolean } [options.skipDynamicArgumentsReport] If `true`, skip report within dynamic arguments.
332
370
* @param {boolean } [options.applyDocument] If `true`, apply check to document fragment.
333
- * @param { (context: RuleContext, options: { coreHandlers: RuleListener }) => TemplateListener } [options.create] If define, extend core rule.
371
+ * @param {WrapCoreRulePreprocess } [options.preprocess] Preprocess to calling create of core rule.
372
+ * @param {WrapCoreRuleCreate } [options.create] If define, extend core rule.
334
373
* @returns {RuleModule } The wrapped rule implementation.
335
374
*/
336
375
wrapCoreRule ( coreRuleName , options ) {
@@ -366,6 +405,7 @@ module.exports = {
366
405
skipDynamicArguments,
367
406
skipDynamicArgumentsReport,
368
407
applyDocument,
408
+ preprocess,
369
409
create
370
410
} = options || { }
371
411
return {
@@ -387,12 +427,25 @@ module.exports = {
387
427
wrapContextToOverrideReportMethodToSkipDynamicArgument ( context )
388
428
}
389
429
390
- // Move `Program` handlers to `VElement[parent.type!='VElement']`
430
+ /** @type {TemplateListener } */
431
+ const handlers = { }
432
+
433
+ if ( preprocess ) {
434
+ preprocess ( context , {
435
+ wrapContextToOverrideProperties ( override ) {
436
+ context = newProxy ( context , override )
437
+ return context
438
+ } ,
439
+ defineVisitor ( visitor ) {
440
+ compositingVisitors ( handlers , visitor )
441
+ }
442
+ } )
443
+ }
444
+
391
445
const coreHandlers = coreRule . create ( context )
446
+ compositingVisitors ( handlers , coreHandlers )
392
447
393
- const handlers = /** @type {TemplateListener } */ (
394
- Object . assign ( { } , coreHandlers )
395
- )
448
+ // Move `Program` handlers to `VElement[parent.type!='VElement']`
396
449
if ( handlers . Program ) {
397
450
handlers [
398
451
applyDocument
@@ -462,6 +515,13 @@ module.exports = {
462
515
* @returns {v is T }
463
516
*/
464
517
isDef,
518
+ /**
519
+ * Flattens arrays, objects and iterable objects.
520
+ * @template T
521
+ * @param {T | Iterable<T> | null | undefined } v
522
+ * @returns {T[] }
523
+ */
524
+ flatten,
465
525
/**
466
526
* Get the previous sibling element of the given element.
467
527
* @param {VElement } node The element node to get the previous sibling element.
@@ -1837,6 +1897,33 @@ function isDef(v) {
1837
1897
return v != null
1838
1898
}
1839
1899
1900
+ /**
1901
+ * Flattens arrays, objects and iterable objects.
1902
+ * @template T
1903
+ * @param {T | Iterable<T> | null | undefined } v
1904
+ * @returns {T[] }
1905
+ */
1906
+ function flatten ( v ) {
1907
+ /** @type {T[] } */
1908
+ const result = [ ]
1909
+ if ( v ) {
1910
+ if ( isIterable ( v ) ) {
1911
+ result . push ( ...v )
1912
+ } else {
1913
+ result . push ( v )
1914
+ }
1915
+ }
1916
+ return result
1917
+ }
1918
+
1919
+ /**
1920
+ * @param {* } v
1921
+ * @returns {v is Iterable<any> }
1922
+ */
1923
+ function isIterable ( v ) {
1924
+ return v && Symbol . iterator in v
1925
+ }
1926
+
1840
1927
// ------------------------------------------------------------------------------
1841
1928
// Nodejs Helpers
1842
1929
// ------------------------------------------------------------------------------
0 commit comments