lint-suite 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.cjs +623 -45
- package/eslint.cjs.map +4 -4
- package/eslint.js +636 -42
- package/eslint.js.map +4 -4
- package/lib/angular-template.d.ts +1 -2
- package/lib/angular-template.d.ts.map +1 -1
- package/lib/angular.d.ts +1 -2
- package/lib/angular.d.ts.map +1 -1
- package/lib/base.d.ts +1 -1
- package/lib/base.d.ts.map +1 -1
- package/lib/boundaries.d.ts +1 -1
- package/lib/boundaries.d.ts.map +1 -1
- package/lib/javascript.d.ts +1 -2
- package/lib/javascript.d.ts.map +1 -1
- package/lib/json.d.ts +1 -1
- package/lib/json.d.ts.map +1 -1
- package/lib/playwright.d.ts +1 -1
- package/lib/playwright.d.ts.map +1 -1
- package/lib/prettier.d.ts +1 -1
- package/lib/prettier.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts +10 -0
- package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts +7 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts +2 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.d.ts +6 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts +7 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts.map +1 -0
- package/lib/rxjs.d.ts +1 -1
- package/lib/rxjs.d.ts.map +1 -1
- package/lib/storybook.d.ts +1 -1
- package/lib/storybook.d.ts.map +1 -1
- package/lib/typescript.d.ts +1 -2
- package/lib/typescript.d.ts.map +1 -1
- package/lib/vitest.d.ts +1 -1
- package/lib/vitest.d.ts.map +1 -1
- package/package.json +23 -22
- package/stylelint.cjs +3 -0
- package/stylelint.cjs.map +2 -2
- package/stylelint.d.ts.map +1 -1
- package/stylelint.js +3 -0
- package/stylelint.js.map +2 -2
package/eslint.cjs
CHANGED
|
@@ -11,9 +11,9 @@ var __export = (target, all) => {
|
|
|
11
11
|
};
|
|
12
12
|
var __copyProps = (to, from, except, desc) => {
|
|
13
13
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let
|
|
15
|
-
if (!__hasOwnProp.call(to,
|
|
16
|
-
__defProp(to,
|
|
14
|
+
for (let key2 of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
16
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
17
17
|
}
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
@@ -127,10 +127,588 @@ var angularTemplate = (0, import_config.defineConfig)([
|
|
|
127
127
|
var import_globals = __toESM(require("globals"), 1);
|
|
128
128
|
var import_angular_eslint2 = require("angular-eslint");
|
|
129
129
|
var import_config2 = require("eslint/config");
|
|
130
|
+
|
|
131
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
|
|
132
|
+
var import_utils4 = require("@typescript-eslint/utils");
|
|
133
|
+
|
|
134
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
|
|
135
|
+
var import_utils2 = require("@typescript-eslint/utils");
|
|
136
|
+
|
|
137
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
|
|
138
|
+
var import_node_fs = require("node:fs");
|
|
139
|
+
var import_node_path = require("node:path");
|
|
140
|
+
var import_compiler2 = require("@angular/compiler");
|
|
141
|
+
var import_utils = require("@typescript-eslint/utils");
|
|
142
|
+
|
|
143
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.ts
|
|
144
|
+
var import_compiler = require("@angular/compiler");
|
|
145
|
+
var ReadCollector = class extends import_compiler.CombinedRecursiveAstVisitor {
|
|
146
|
+
constructor(boundTarget, action) {
|
|
147
|
+
super();
|
|
148
|
+
this.boundTarget = boundTarget;
|
|
149
|
+
this.action = action;
|
|
150
|
+
}
|
|
151
|
+
boundTarget;
|
|
152
|
+
action;
|
|
153
|
+
reads = /* @__PURE__ */ new Set();
|
|
154
|
+
record(node) {
|
|
155
|
+
if (node.receiver instanceof import_compiler.ThisReceiver) {
|
|
156
|
+
this.reads.add(node.name);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (node.receiver instanceof import_compiler.ImplicitReceiver && (!this.action || node.name !== "$event") && !this.boundTarget?.getExpressionTarget(node)) {
|
|
160
|
+
this.reads.add(node.name);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
visitBinary(node, context) {
|
|
164
|
+
if (node.operation !== "=") {
|
|
165
|
+
return super.visitBinary(node, context);
|
|
166
|
+
}
|
|
167
|
+
if (node.left instanceof import_compiler.PropertyRead || node.left instanceof import_compiler.SafePropertyRead || node.left instanceof import_compiler.KeyedRead || node.left instanceof import_compiler.SafeKeyedRead) {
|
|
168
|
+
this.visit(node.left.receiver);
|
|
169
|
+
}
|
|
170
|
+
if (node.left instanceof import_compiler.KeyedRead || node.left instanceof import_compiler.SafeKeyedRead) {
|
|
171
|
+
this.visit(node.left.key);
|
|
172
|
+
}
|
|
173
|
+
this.visit(node.right);
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
visitPropertyRead(node, context) {
|
|
177
|
+
this.record(node);
|
|
178
|
+
return super.visitPropertyRead(node, context);
|
|
179
|
+
}
|
|
180
|
+
visitSafePropertyRead(node, context) {
|
|
181
|
+
this.record(node);
|
|
182
|
+
return super.visitSafePropertyRead(node, context);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
var collectAngularExpressionReads = (nodes, boundTarget, action) => {
|
|
186
|
+
const collector = new ReadCollector(boundTarget, action);
|
|
187
|
+
for (const node of nodes) {
|
|
188
|
+
collector.visit(node);
|
|
189
|
+
}
|
|
190
|
+
return collector.reads;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
|
|
194
|
+
var externalTemplates = /* @__PURE__ */ new Map();
|
|
195
|
+
var parser = new import_compiler2.Parser(new import_compiler2.Lexer());
|
|
196
|
+
var templateBinder = new import_compiler2.R3TargetBinder(null);
|
|
197
|
+
var text = (node) => {
|
|
198
|
+
if (node?.type === import_utils.TSESTree.AST_NODE_TYPES.Literal && typeof node.value === "string") {
|
|
199
|
+
return node.value;
|
|
200
|
+
}
|
|
201
|
+
return node?.type === import_utils.TSESTree.AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0 ? node.quasis[0].value.cooked : null;
|
|
202
|
+
};
|
|
203
|
+
var templateReads = (template, filename) => {
|
|
204
|
+
try {
|
|
205
|
+
const result = (0, import_compiler2.parseTemplate)(template, filename);
|
|
206
|
+
if (result.errors?.length) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return collectAngularExpressionReads(
|
|
210
|
+
result.nodes,
|
|
211
|
+
templateBinder.bind({ template: result.nodes }),
|
|
212
|
+
false
|
|
213
|
+
);
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var externalTemplateReads = (filename) => {
|
|
219
|
+
try {
|
|
220
|
+
const stats = (0, import_node_fs.statSync)(filename, { bigint: true });
|
|
221
|
+
const version = `${stats.mtimeNs}:${stats.size}`;
|
|
222
|
+
const cached = externalTemplates.get(filename);
|
|
223
|
+
if (cached?.version === version) {
|
|
224
|
+
return cached.reads;
|
|
225
|
+
}
|
|
226
|
+
const reads = templateReads((0, import_node_fs.readFileSync)(filename, "utf8"), filename);
|
|
227
|
+
externalTemplates.set(filename, { reads, version });
|
|
228
|
+
return reads;
|
|
229
|
+
} catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var expressionReads = (expression, filename, action) => {
|
|
234
|
+
try {
|
|
235
|
+
const file = new import_compiler2.ParseSourceFile(expression, filename);
|
|
236
|
+
const start = new import_compiler2.ParseLocation(file, 0, 0, 0);
|
|
237
|
+
const span = new import_compiler2.ParseSourceSpan(start, start.moveBy(expression.length));
|
|
238
|
+
const result = action ? parser.parseAction(expression, span, 0) : parser.parseBinding(expression, span, 0);
|
|
239
|
+
if (result.errors.length > 0) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return collectAngularExpressionReads([result], void 0, action);
|
|
243
|
+
} catch {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
var addReads = (target, source) => {
|
|
248
|
+
if (!source) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
for (const name of source) {
|
|
252
|
+
target.add(name);
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
};
|
|
256
|
+
var key = (property) => {
|
|
257
|
+
if (property.type !== import_utils.TSESTree.AST_NODE_TYPES.Property || property.computed) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
return property.key.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier ? property.key.name : text(property.key);
|
|
261
|
+
};
|
|
262
|
+
var metadataValue = (metadata, name) => {
|
|
263
|
+
for (const property of metadata.properties) {
|
|
264
|
+
if (property.type === import_utils.TSESTree.AST_NODE_TYPES.Property && key(property) === name) {
|
|
265
|
+
return property.value;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return void 0;
|
|
269
|
+
};
|
|
270
|
+
var hostPropertyReads = (property, reads, filename) => {
|
|
271
|
+
const name = key(property);
|
|
272
|
+
const expression = text(property.value);
|
|
273
|
+
if (name === null || expression === null) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
if (name.startsWith("[")) {
|
|
277
|
+
return addReads(reads, expressionReads(expression, filename, false));
|
|
278
|
+
}
|
|
279
|
+
if (name.startsWith("(")) {
|
|
280
|
+
return addReads(reads, expressionReads(expression, filename, true));
|
|
281
|
+
}
|
|
282
|
+
return true;
|
|
283
|
+
};
|
|
284
|
+
var hostReads = (host, reads, filename) => {
|
|
285
|
+
if (!host) {
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
if (host.type !== import_utils.TSESTree.AST_NODE_TYPES.ObjectExpression || host.properties.some((property) => key(property) === null)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
for (const property of host.properties) {
|
|
292
|
+
if (property.type !== import_utils.TSESTree.AST_NODE_TYPES.Property || !hostPropertyReads(property, reads, filename)) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
};
|
|
298
|
+
var inlineTemplateReads = (template, reads, filename) => {
|
|
299
|
+
if (!template) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
const source = text(template);
|
|
303
|
+
return source !== null && addReads(reads, templateReads(source, filename));
|
|
304
|
+
};
|
|
305
|
+
var externalTemplatePropertyReads = (templateUrl, reads, filename) => {
|
|
306
|
+
if (!templateUrl) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
const url = text(templateUrl);
|
|
310
|
+
return url !== null && addReads(reads, externalTemplateReads((0, import_node_path.resolve)((0, import_node_path.dirname)(filename), url)));
|
|
311
|
+
};
|
|
312
|
+
var componentTemplateReads = (metadata, reads, filename) => {
|
|
313
|
+
const template = metadataValue(metadata, "template");
|
|
314
|
+
const templateUrl = metadataValue(metadata, "templateUrl");
|
|
315
|
+
return inlineTemplateReads(template, reads, filename) && externalTemplatePropertyReads(templateUrl, reads, filename);
|
|
316
|
+
};
|
|
317
|
+
var metadataReads = (metadata, component, filename, remainingNames) => {
|
|
318
|
+
if (metadata.properties.some((property) => key(property) === null)) {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
const reads = /* @__PURE__ */ new Set();
|
|
322
|
+
if (!hostReads(metadataValue(metadata, "host"), reads, filename)) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
if (component && remainingNames.every((name) => reads.has(name)) || !component || componentTemplateReads(metadata, reads, filename)) {
|
|
326
|
+
return reads;
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
|
|
332
|
+
var managedApis = {
|
|
333
|
+
input: true,
|
|
334
|
+
model: true,
|
|
335
|
+
output: true
|
|
336
|
+
};
|
|
337
|
+
var angularName = (node, imports) => {
|
|
338
|
+
if (node.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
339
|
+
return imports.get(node.name);
|
|
340
|
+
}
|
|
341
|
+
if (node.type !== import_utils2.TSESTree.AST_NODE_TYPES.MemberExpression || node.computed || node.property.type !== import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
if (node.object.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier && imports.get(node.object.name) === null) {
|
|
345
|
+
return node.property.name;
|
|
346
|
+
}
|
|
347
|
+
return angularName(node.object, imports);
|
|
348
|
+
};
|
|
349
|
+
var angularClass = (node, imports) => {
|
|
350
|
+
for (const decorator of node.decorators) {
|
|
351
|
+
if (decorator.expression.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const kind = angularName(decorator.expression.callee, imports);
|
|
355
|
+
const metadata = decorator.expression.arguments[0];
|
|
356
|
+
if ((kind === "Component" || kind === "Directive") && metadata?.type === import_utils2.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
357
|
+
return {
|
|
358
|
+
component: kind === "Component",
|
|
359
|
+
metadata
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
};
|
|
365
|
+
var isInstanceField = (node) => node.type === import_utils2.TSESTree.AST_NODE_TYPES.PropertyDefinition && node.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier;
|
|
366
|
+
var lifecycleHooks = {
|
|
367
|
+
ngOnChanges: true,
|
|
368
|
+
ngOnInit: true,
|
|
369
|
+
ngDoCheck: true,
|
|
370
|
+
ngAfterContentInit: true,
|
|
371
|
+
ngAfterContentChecked: true,
|
|
372
|
+
ngAfterViewInit: true,
|
|
373
|
+
ngAfterViewChecked: true,
|
|
374
|
+
ngOnDestroy: true
|
|
375
|
+
};
|
|
376
|
+
var isInstanceMethod = (node) => node.type === import_utils2.TSESTree.AST_NODE_TYPES.MethodDefinition && node.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier;
|
|
377
|
+
var isExcludedField = (node, component) => node.static || node.declare || node.override || node.decorators.length > 0 || !component && node.accessibility !== "private";
|
|
378
|
+
var isManagedField = (node, imports) => {
|
|
379
|
+
if (node.value?.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
const name = angularName(node.value.callee, imports);
|
|
383
|
+
return typeof name === "string" && managedApis[name] === true;
|
|
384
|
+
};
|
|
385
|
+
var field = (node, imports, component) => {
|
|
386
|
+
if (isInstanceField(node) && !isExcludedField(node, component) && !isManagedField(node, imports)) {
|
|
387
|
+
return { messageId: "unusedField", name: node.key.name, node };
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
};
|
|
391
|
+
var isExcludedMethod = (node, component) => node.static || node.override || node.decorators.length > 0 || node.computed || node.kind !== "method" || node.value.body === null || lifecycleHooks[node.key.name] === true || !component && node.accessibility !== "private";
|
|
392
|
+
var method = (node, component) => {
|
|
393
|
+
if (isInstanceMethod(node) && !isExcludedMethod(node, component)) {
|
|
394
|
+
return { messageId: "unusedMethod", name: node.key.name, node };
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
};
|
|
398
|
+
var addAngularImport = (node, imports) => {
|
|
399
|
+
if (node.source.value !== "@angular/core" || node.importKind === "type") {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
for (const specifier of node.specifiers) {
|
|
403
|
+
if (specifier.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportNamespaceSpecifier) {
|
|
404
|
+
imports.set(specifier.local.name, null);
|
|
405
|
+
} else if (specifier.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type") {
|
|
406
|
+
const importedName = specifier.imported.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier ? specifier.imported.name : specifier.imported.value;
|
|
407
|
+
imports.set(specifier.local.name, importedName);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
var reportUnusedMembers = (context, imports, classes, dynamicClasses) => {
|
|
412
|
+
for (const entry of classes) {
|
|
413
|
+
const ngClass = angularClass(entry.node, imports);
|
|
414
|
+
if (!ngClass || dynamicClasses.has(entry)) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const members = [];
|
|
418
|
+
for (const node of entry.node.body.body) {
|
|
419
|
+
const candidate = field(node, imports, ngClass.component) ?? method(node, ngClass.component);
|
|
420
|
+
if (candidate) {
|
|
421
|
+
members.push(candidate);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (members.length === 0) {
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const unreadMembers = members.filter(
|
|
428
|
+
(candidate) => !entry.reads.has(candidate.name)
|
|
429
|
+
);
|
|
430
|
+
if (unreadMembers.length === 0) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const reads = metadataReads(
|
|
434
|
+
ngClass.metadata,
|
|
435
|
+
ngClass.component,
|
|
436
|
+
context.filename,
|
|
437
|
+
unreadMembers.map((candidate) => candidate.name)
|
|
438
|
+
);
|
|
439
|
+
if (!reads) {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
for (const candidate of unreadMembers) {
|
|
443
|
+
if (!reads.has(candidate.name)) {
|
|
444
|
+
context.report({
|
|
445
|
+
data: { name: candidate.name },
|
|
446
|
+
messageId: candidate.messageId,
|
|
447
|
+
node: candidate.node.key
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.ts
|
|
455
|
+
var import_utils3 = require("@typescript-eslint/utils");
|
|
456
|
+
var isTypeScriptExpressionWrapper = (node) => {
|
|
457
|
+
switch (node.type) {
|
|
458
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.TSAsExpression:
|
|
459
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.TSInstantiationExpression:
|
|
460
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.TSNonNullExpression:
|
|
461
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.TSSatisfiesExpression:
|
|
462
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.TSTypeAssertion:
|
|
463
|
+
return true;
|
|
464
|
+
default:
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
var unwrapTypeScriptExpression = (node) => {
|
|
469
|
+
let current = node;
|
|
470
|
+
while (current && isTypeScriptExpressionWrapper(current)) {
|
|
471
|
+
current = current.expression;
|
|
472
|
+
}
|
|
473
|
+
return current;
|
|
474
|
+
};
|
|
475
|
+
var isThisExpression = (node) => unwrapTypeScriptExpression(node)?.type === import_utils3.TSESTree.AST_NODE_TYPES.ThisExpression;
|
|
476
|
+
var isPatternTarget = (parent, child) => {
|
|
477
|
+
switch (parent?.type) {
|
|
478
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.ArrayPattern:
|
|
479
|
+
return parent.elements.some((element) => element === child);
|
|
480
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.AssignmentPattern:
|
|
481
|
+
return parent.left === child;
|
|
482
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern:
|
|
483
|
+
return parent.properties.some((property) => property === child);
|
|
484
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.Property:
|
|
485
|
+
return parent.value === child && parent.parent.type === import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern;
|
|
486
|
+
case import_utils3.TSESTree.AST_NODE_TYPES.RestElement:
|
|
487
|
+
return parent.argument === child;
|
|
488
|
+
default:
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
var isSimpleAssignmentTarget = (parent, current) => parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.AssignmentExpression && parent.left === current && parent.operator === "=";
|
|
493
|
+
var isLoopTarget = (parent, current) => (parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.ForInStatement || parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.ForOfStatement) && parent.left === current;
|
|
494
|
+
var isDirectWrite = (node) => {
|
|
495
|
+
let current = node;
|
|
496
|
+
let parent = node.parent;
|
|
497
|
+
while (parent && isTypeScriptExpressionWrapper(parent) && parent.expression === current) {
|
|
498
|
+
current = parent;
|
|
499
|
+
parent = parent.parent;
|
|
500
|
+
}
|
|
501
|
+
return isSimpleAssignmentTarget(parent, current) || parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.UnaryExpression && parent.operator === "delete";
|
|
502
|
+
};
|
|
503
|
+
var isDestructuringOrLoopTarget = (node) => {
|
|
504
|
+
let current = node;
|
|
505
|
+
let parent = node.parent;
|
|
506
|
+
let patternTarget = false;
|
|
507
|
+
while (parent) {
|
|
508
|
+
const wrapper = isTypeScriptExpressionWrapper(parent) && parent.expression === current;
|
|
509
|
+
const pattern = isPatternTarget(parent, current);
|
|
510
|
+
if (!wrapper && !pattern) {
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
if (pattern) {
|
|
514
|
+
patternTarget = true;
|
|
515
|
+
}
|
|
516
|
+
current = parent;
|
|
517
|
+
parent = parent.parent;
|
|
518
|
+
}
|
|
519
|
+
return patternTarget && isSimpleAssignmentTarget(parent, current) || isLoopTarget(parent, current);
|
|
520
|
+
};
|
|
521
|
+
var isWriteOnly = (node) => isDirectWrite(node) || isDestructuringOrLoopTarget(node);
|
|
522
|
+
var destructuringParts = (node) => {
|
|
523
|
+
if (node.type === import_utils3.TSESTree.AST_NODE_TYPES.VariableDeclarator) {
|
|
524
|
+
return { pattern: node.id, source: node.init };
|
|
525
|
+
}
|
|
526
|
+
if (node.operator === "=") {
|
|
527
|
+
return { pattern: node.left, source: node.right };
|
|
528
|
+
}
|
|
529
|
+
return null;
|
|
530
|
+
};
|
|
531
|
+
var propertyName = (property) => {
|
|
532
|
+
if (property.type !== import_utils3.TSESTree.AST_NODE_TYPES.Property || property.computed) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
if (property.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
536
|
+
return property.key.name;
|
|
537
|
+
}
|
|
538
|
+
return property.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Literal && typeof property.key.value === "string" ? property.key.value : null;
|
|
539
|
+
};
|
|
540
|
+
var destructuredThisReads = (node) => {
|
|
541
|
+
const parts = destructuringParts(node);
|
|
542
|
+
if (!parts || parts.pattern.type !== import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern || !isThisExpression(parts.source)) {
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
545
|
+
const reads = [];
|
|
546
|
+
for (const property of parts.pattern.properties) {
|
|
547
|
+
const name = propertyName(property);
|
|
548
|
+
if (name === null) {
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
reads.push(name);
|
|
552
|
+
}
|
|
553
|
+
return reads;
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
|
|
557
|
+
var createRule = import_utils4.ESLintUtils.RuleCreator(
|
|
558
|
+
() => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
|
|
559
|
+
);
|
|
560
|
+
var enterClass = (node, classes, stack, thisStack) => {
|
|
561
|
+
const entry = {
|
|
562
|
+
node,
|
|
563
|
+
reads: /* @__PURE__ */ new Set()
|
|
564
|
+
};
|
|
565
|
+
classes.push(entry);
|
|
566
|
+
stack.push(entry);
|
|
567
|
+
thisStack.push(true);
|
|
568
|
+
};
|
|
569
|
+
var componentThis = (node, thisStack) => node.type === import_utils4.TSESTree.AST_NODE_TYPES.ArrowFunctionExpression ? thisStack.at(-1) ?? false : node.parent.type === import_utils4.TSESTree.AST_NODE_TYPES.MethodDefinition && !node.parent.static;
|
|
570
|
+
var trackMemberRead = (node, stack, thisStack, dynamicClasses) => {
|
|
571
|
+
const current = stack.at(-1);
|
|
572
|
+
if (!current || !thisStack.at(-1)) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const receiverIsThis = isThisExpression(node.object);
|
|
576
|
+
if (node.computed && receiverIsThis) {
|
|
577
|
+
dynamicClasses.add(current);
|
|
578
|
+
}
|
|
579
|
+
if (receiverIsThis && !node.computed && node.property.type === import_utils4.TSESTree.AST_NODE_TYPES.Identifier && !isWriteOnly(node)) {
|
|
580
|
+
current.reads.add(node.property.name);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
var trackDestructuringRead = (node, stack, thisStack, dynamicClasses) => {
|
|
584
|
+
const current = stack.at(-1);
|
|
585
|
+
if (!current || !thisStack.at(-1)) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const reads = destructuredThisReads(node);
|
|
589
|
+
if (reads === void 0) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (reads === null) {
|
|
593
|
+
dynamicClasses.add(current);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
for (const name of reads) {
|
|
597
|
+
current.reads.add(name);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
var lexicalThisVisitor = (thisStack) => ({
|
|
601
|
+
FunctionDeclaration(node) {
|
|
602
|
+
thisStack.push(componentThis(node, thisStack));
|
|
603
|
+
},
|
|
604
|
+
FunctionExpression(node) {
|
|
605
|
+
thisStack.push(componentThis(node, thisStack));
|
|
606
|
+
},
|
|
607
|
+
ArrowFunctionExpression(node) {
|
|
608
|
+
thisStack.push(componentThis(node, thisStack));
|
|
609
|
+
},
|
|
610
|
+
"FunctionDeclaration:exit"() {
|
|
611
|
+
thisStack.pop();
|
|
612
|
+
},
|
|
613
|
+
"FunctionExpression:exit"() {
|
|
614
|
+
thisStack.pop();
|
|
615
|
+
},
|
|
616
|
+
"ArrowFunctionExpression:exit"() {
|
|
617
|
+
thisStack.pop();
|
|
618
|
+
},
|
|
619
|
+
StaticBlock() {
|
|
620
|
+
thisStack.push(false);
|
|
621
|
+
},
|
|
622
|
+
"StaticBlock:exit"() {
|
|
623
|
+
thisStack.pop();
|
|
624
|
+
},
|
|
625
|
+
PropertyDefinition(node) {
|
|
626
|
+
if (node.static) {
|
|
627
|
+
thisStack.push(false);
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
"PropertyDefinition:exit"(node) {
|
|
631
|
+
if (node.static) {
|
|
632
|
+
thisStack.pop();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
var visitor = (context, imports, classes, stack, dynamicClasses) => {
|
|
637
|
+
const thisStack = [];
|
|
638
|
+
return {
|
|
639
|
+
ClassDeclaration(node) {
|
|
640
|
+
enterClass(node, classes, stack, thisStack);
|
|
641
|
+
},
|
|
642
|
+
ClassExpression(node) {
|
|
643
|
+
enterClass(node, classes, stack, thisStack);
|
|
644
|
+
},
|
|
645
|
+
"ClassDeclaration:exit"() {
|
|
646
|
+
stack.pop();
|
|
647
|
+
thisStack.pop();
|
|
648
|
+
},
|
|
649
|
+
"ClassExpression:exit"() {
|
|
650
|
+
stack.pop();
|
|
651
|
+
thisStack.pop();
|
|
652
|
+
},
|
|
653
|
+
...lexicalThisVisitor(thisStack),
|
|
654
|
+
AssignmentExpression(node) {
|
|
655
|
+
trackDestructuringRead(node, stack, thisStack, dynamicClasses);
|
|
656
|
+
},
|
|
657
|
+
MemberExpression(node) {
|
|
658
|
+
trackMemberRead(node, stack, thisStack, dynamicClasses);
|
|
659
|
+
},
|
|
660
|
+
VariableDeclarator(node) {
|
|
661
|
+
trackDestructuringRead(node, stack, thisStack, dynamicClasses);
|
|
662
|
+
},
|
|
663
|
+
"Program:exit"() {
|
|
664
|
+
reportUnusedMembers(context, imports, classes, dynamicClasses);
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
};
|
|
668
|
+
var no_unused_angular_instance_fields_default = createRule({
|
|
669
|
+
name: "no-unused-instance-fields",
|
|
670
|
+
meta: {
|
|
671
|
+
type: "problem",
|
|
672
|
+
docs: {
|
|
673
|
+
description: "Disallow unread instance fields and methods in Angular components and directives"
|
|
674
|
+
},
|
|
675
|
+
messages: {
|
|
676
|
+
unusedField: "Angular instance field '{{name}}' is never read.",
|
|
677
|
+
unusedMethod: "Angular instance method '{{name}}' is never read."
|
|
678
|
+
},
|
|
679
|
+
schema: []
|
|
680
|
+
},
|
|
681
|
+
defaultOptions: [],
|
|
682
|
+
create(context) {
|
|
683
|
+
const imports = /* @__PURE__ */ new Map();
|
|
684
|
+
for (const node of context.sourceCode.ast.body) {
|
|
685
|
+
if (node.type === import_utils4.TSESTree.AST_NODE_TYPES.ImportDeclaration) {
|
|
686
|
+
addAngularImport(node, imports);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
if (imports.size === 0) {
|
|
690
|
+
return {};
|
|
691
|
+
}
|
|
692
|
+
const classes = [];
|
|
693
|
+
const stack = [];
|
|
694
|
+
const dynamicClasses = /* @__PURE__ */ new Set();
|
|
695
|
+
return visitor(context, imports, classes, stack, dynamicClasses);
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
// packages/lint-suite/src/lib/angular.ts
|
|
700
|
+
var lintSuiteAngularPlugin = {
|
|
701
|
+
rules: {
|
|
702
|
+
"no-unused-instance-fields": no_unused_angular_instance_fields_default
|
|
703
|
+
}
|
|
704
|
+
};
|
|
130
705
|
var angular = (0, import_config2.defineConfig)([
|
|
131
706
|
{
|
|
132
707
|
files: ["**/*.ts"],
|
|
133
708
|
extends: [...import_angular_eslint2.configs.tsRecommended],
|
|
709
|
+
plugins: {
|
|
710
|
+
"lint-suite-angular": lintSuiteAngularPlugin
|
|
711
|
+
},
|
|
134
712
|
languageOptions: {
|
|
135
713
|
globals: {
|
|
136
714
|
...import_globals.default.browser,
|
|
@@ -140,7 +718,9 @@ var angular = (0, import_config2.defineConfig)([
|
|
|
140
718
|
},
|
|
141
719
|
processor: import_angular_eslint2.processInlineTemplates,
|
|
142
720
|
rules: {
|
|
721
|
+
"lint-suite-angular/no-unused-instance-fields": "error",
|
|
143
722
|
"@angular-eslint/prefer-on-push-component-change-detection": "error",
|
|
723
|
+
// v22: flags only explicit opt-out of OnPush (omission now means OnPush)
|
|
144
724
|
"@angular-eslint/prefer-signals": "error",
|
|
145
725
|
"@angular-eslint/use-injectable-provided-in": "error",
|
|
146
726
|
"@angular-eslint/prefer-signal-model": "error",
|
|
@@ -158,8 +738,6 @@ var angular = (0, import_config2.defineConfig)([
|
|
|
158
738
|
// Consistent lifecycle method ordering
|
|
159
739
|
"@angular-eslint/computed-must-return": "error",
|
|
160
740
|
// Catch silent computed() bugs missing a return
|
|
161
|
-
"@angular-eslint/no-conflicting-lifecycle": "error",
|
|
162
|
-
// Block incompatible hook combinations (OnChanges + DoCheck)
|
|
163
741
|
"@angular-eslint/no-duplicates-in-metadata-arrays": "error",
|
|
164
742
|
// Catch duplicate imports/providers in @Component/@NgModule
|
|
165
743
|
"@angular-eslint/no-lifecycle-call": "error",
|
|
@@ -525,8 +1103,8 @@ var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"),
|
|
|
525
1103
|
var import_config9 = require("eslint/config");
|
|
526
1104
|
|
|
527
1105
|
// packages/lint-suite/src/lib/rules/explicit-accessibility.ts
|
|
528
|
-
var
|
|
529
|
-
var
|
|
1106
|
+
var import_utils5 = require("@typescript-eslint/utils");
|
|
1107
|
+
var createRule2 = import_utils5.ESLintUtils.RuleCreator(
|
|
530
1108
|
() => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
|
|
531
1109
|
);
|
|
532
1110
|
var defaultOptions = {
|
|
@@ -537,10 +1115,10 @@ var getNodeName = (node) => {
|
|
|
537
1115
|
return "<unknown>";
|
|
538
1116
|
}
|
|
539
1117
|
if ("key" in node && node.key) {
|
|
540
|
-
if (node.key.type ===
|
|
1118
|
+
if (node.key.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
541
1119
|
return node.key.name;
|
|
542
1120
|
}
|
|
543
|
-
if (node.key.type ===
|
|
1121
|
+
if (node.key.type === import_utils5.TSESTree.AST_NODE_TYPES.PrivateIdentifier) {
|
|
544
1122
|
return `#${node.key.name}`;
|
|
545
1123
|
}
|
|
546
1124
|
return "<computed/complex key>";
|
|
@@ -548,13 +1126,13 @@ var getNodeName = (node) => {
|
|
|
548
1126
|
if ("kind" in node && node.kind === "constructor") {
|
|
549
1127
|
return "constructor";
|
|
550
1128
|
}
|
|
551
|
-
if (node.type ===
|
|
1129
|
+
if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty) {
|
|
552
1130
|
const param = node.parameter;
|
|
553
|
-
if (param.type ===
|
|
1131
|
+
if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
554
1132
|
return param.name;
|
|
555
1133
|
}
|
|
556
|
-
if (param.type ===
|
|
557
|
-
if (param.left.type ===
|
|
1134
|
+
if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.AssignmentPattern) {
|
|
1135
|
+
if (param.left.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
558
1136
|
return param.left.name;
|
|
559
1137
|
}
|
|
560
1138
|
return "<destructured parameter>";
|
|
@@ -563,7 +1141,7 @@ var getNodeName = (node) => {
|
|
|
563
1141
|
}
|
|
564
1142
|
return "<unknown>";
|
|
565
1143
|
};
|
|
566
|
-
var explicit_accessibility_default =
|
|
1144
|
+
var explicit_accessibility_default = createRule2({
|
|
567
1145
|
name: "explicit-accessibility",
|
|
568
1146
|
meta: {
|
|
569
1147
|
type: "suggestion",
|
|
@@ -598,13 +1176,13 @@ var explicit_accessibility_default = createRule({
|
|
|
598
1176
|
}
|
|
599
1177
|
let reportNode = node;
|
|
600
1178
|
const name = getNodeName(node);
|
|
601
|
-
if (node.type ===
|
|
1179
|
+
if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.MethodDefinition || node.type === import_utils5.TSESTree.AST_NODE_TYPES.PropertyDefinition) {
|
|
602
1180
|
reportNode = node.key;
|
|
603
1181
|
} else {
|
|
604
1182
|
const param = node.parameter;
|
|
605
|
-
if (param.type ===
|
|
1183
|
+
if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
606
1184
|
reportNode = param;
|
|
607
|
-
} else if (param.type ===
|
|
1185
|
+
} else if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.AssignmentPattern && param.left.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
608
1186
|
reportNode = param.left;
|
|
609
1187
|
}
|
|
610
1188
|
}
|
|
@@ -621,7 +1199,7 @@ var explicit_accessibility_default = createRule({
|
|
|
621
1199
|
} else {
|
|
622
1200
|
tokenToInsertBefore = sourceCode.getFirstToken(node);
|
|
623
1201
|
}
|
|
624
|
-
if (node.type ===
|
|
1202
|
+
if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty && node.readonly) {
|
|
625
1203
|
const firstToken = sourceCode.getFirstToken(node);
|
|
626
1204
|
if (firstToken?.value === "readonly") {
|
|
627
1205
|
tokenToInsertBefore = firstToken;
|
|
@@ -926,7 +1504,7 @@ var typescript = (0, import_config9.defineConfig)([
|
|
|
926
1504
|
],
|
|
927
1505
|
rules: {
|
|
928
1506
|
"@typescript-eslint/no-empty-function": "off",
|
|
929
|
-
"@typescript-eslint/
|
|
1507
|
+
"@typescript-eslint/unbound-method": "off",
|
|
930
1508
|
"@typescript-eslint/consistent-type-assertions": "off"
|
|
931
1509
|
}
|
|
932
1510
|
},
|
|
@@ -1048,53 +1626,53 @@ var boundaries = (0, import_config12.defineConfig)([
|
|
|
1048
1626
|
"error",
|
|
1049
1627
|
{
|
|
1050
1628
|
default: "disallow",
|
|
1051
|
-
message: "
|
|
1052
|
-
|
|
1629
|
+
message: "{{to.element.types}} is not allowed to be imported in {{from.element.types}}",
|
|
1630
|
+
policies: [
|
|
1053
1631
|
{
|
|
1054
|
-
from: { type: "feature" },
|
|
1632
|
+
from: { element: { type: "feature" } },
|
|
1055
1633
|
allow: [
|
|
1056
|
-
{ to: { type: "feature" } },
|
|
1057
|
-
{ to: { type: "ui" } },
|
|
1058
|
-
{ to: { type: "domain-logic" } },
|
|
1059
|
-
{ to: { type: "utils" } },
|
|
1060
|
-
{ to: { type: "common" } }
|
|
1634
|
+
{ to: { element: { type: "feature" } } },
|
|
1635
|
+
{ to: { element: { type: "ui" } } },
|
|
1636
|
+
{ to: { element: { type: "domain-logic" } } },
|
|
1637
|
+
{ to: { element: { type: "utils" } } },
|
|
1638
|
+
{ to: { element: { type: "common" } } }
|
|
1061
1639
|
]
|
|
1062
1640
|
},
|
|
1063
1641
|
{
|
|
1064
|
-
from: { type: "domain-logic" },
|
|
1642
|
+
from: { element: { type: "domain-logic" } },
|
|
1065
1643
|
allow: [
|
|
1066
|
-
{ to: { type: "domain-logic" } },
|
|
1067
|
-
{ to: { type: "data-access" } },
|
|
1068
|
-
{ to: { type: "utils" } },
|
|
1069
|
-
{ to: { type: "common" } }
|
|
1644
|
+
{ to: { element: { type: "domain-logic" } } },
|
|
1645
|
+
{ to: { element: { type: "data-access" } } },
|
|
1646
|
+
{ to: { element: { type: "utils" } } },
|
|
1647
|
+
{ to: { element: { type: "common" } } }
|
|
1070
1648
|
]
|
|
1071
1649
|
},
|
|
1072
1650
|
{
|
|
1073
|
-
from: { type: "data-access" },
|
|
1651
|
+
from: { element: { type: "data-access" } },
|
|
1074
1652
|
allow: [
|
|
1075
|
-
{ to: { type: "data-access" } },
|
|
1076
|
-
{ to: { type: "utils" } },
|
|
1077
|
-
{ to: { type: "common" } }
|
|
1653
|
+
{ to: { element: { type: "data-access" } } },
|
|
1654
|
+
{ to: { element: { type: "utils" } } },
|
|
1655
|
+
{ to: { element: { type: "common" } } }
|
|
1078
1656
|
]
|
|
1079
1657
|
},
|
|
1080
1658
|
{
|
|
1081
|
-
from: { type: "ui" },
|
|
1659
|
+
from: { element: { type: "ui" } },
|
|
1082
1660
|
allow: [
|
|
1083
|
-
{ to: { type: "ui" } },
|
|
1084
|
-
{ to: { type: "utils" } },
|
|
1085
|
-
{ to: { type: "common" } }
|
|
1661
|
+
{ to: { element: { type: "ui" } } },
|
|
1662
|
+
{ to: { element: { type: "utils" } } },
|
|
1663
|
+
{ to: { element: { type: "common" } } }
|
|
1086
1664
|
]
|
|
1087
1665
|
},
|
|
1088
1666
|
{
|
|
1089
|
-
from: { type: "utils" },
|
|
1667
|
+
from: { element: { type: "utils" } },
|
|
1090
1668
|
allow: [
|
|
1091
|
-
{ to: { type: "utils" } },
|
|
1092
|
-
{ to: { type: "common" } }
|
|
1669
|
+
{ to: { element: { type: "utils" } } },
|
|
1670
|
+
{ to: { element: { type: "common" } } }
|
|
1093
1671
|
]
|
|
1094
1672
|
},
|
|
1095
1673
|
{
|
|
1096
|
-
from: { type: "common" },
|
|
1097
|
-
allow: [{ to: { type: "common" } }]
|
|
1674
|
+
from: { element: { type: "common" } },
|
|
1675
|
+
allow: [{ to: { element: { type: "common" } } }]
|
|
1098
1676
|
}
|
|
1099
1677
|
]
|
|
1100
1678
|
}
|