@arcgis/eslint-config 5.1.0-next.11 → 5.1.0-next.112

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/README.md CHANGED
@@ -8,5 +8,5 @@ It is not intended to be used directly, but rather used as a dependency by other
8
8
 
9
9
  ## License
10
10
 
11
- This package is licensed under the terms described in the `LICENSE.md` file, located in the root of the package, and at https://js.arcgis.com/5.0/LICENSE.txt.
12
- For third party notices, see https://js.arcgis.com/5.0/third-party-notices.txt.
11
+ This package is licensed under the terms described in the `LICENSE.md` file, located in the root of the package, and at https://js.arcgis.com/5.1/LICENSE.txt.
12
+ For third party notices, see https://js.arcgis.com/5.1/third-party-notices.txt.
@@ -213,6 +213,18 @@ const defaultConfig = [
213
213
  "@typescript-eslint/restrict-plus-operands": ["warn", { allowNumberAndString: true }],
214
214
  // We often actually have control characters in our regexes
215
215
  "no-control-regex": "off",
216
+ "@typescript-eslint/no-restricted-imports": [
217
+ "error",
218
+ {
219
+ paths: [
220
+ {
221
+ name: "commander",
222
+ importNames: ["Command"],
223
+ message: "Import from @commander-js/extra-typings instead."
224
+ }
225
+ ]
226
+ }
227
+ ],
216
228
  // Functions that deal with JSON.stringify/localStorage may have a type
217
229
  // parameter as a more readable alternative to a type assertion.
218
230
  // Also, this rule is quite complicated/expensive.
@@ -446,7 +458,13 @@ const defaultConfig = [
446
458
  "@typescript-eslint/no-duplicate-type-constituents": ["warn"],
447
459
  "@typescript-eslint/no-unnecessary-boolean-literal-compare": ["warn"],
448
460
  "@typescript-eslint/no-extra-non-null-assertion": ["warn"],
449
- "@typescript-eslint/no-unnecessary-type-arguments": ["warn"],
461
+ // False positive for the following:
462
+ // this.listen<CustomEvent>("arcgisChartsJSDataProcessComplete", this.handleDataProcessComplete);
463
+ "@typescript-eslint/no-unnecessary-type-arguments": "off",
464
+ // The autofix creates TS errors in makeT9nController(). This is a new
465
+ // rule - give it more time to catch the bug cases. Also, this rule
466
+ // changes runtime behavior, and may lead to breaking changes.
467
+ "@typescript-eslint/no-useless-default-assignment": "off",
450
468
  "@typescript-eslint/no-unnecessary-type-assertion": ["warn"],
451
469
  "@typescript-eslint/prefer-includes": ["warn"],
452
470
  "@typescript-eslint/prefer-reduce-type-parameter": ["warn"],
@@ -587,6 +605,18 @@ const defaultConfig = [
587
605
  // Allow empty "files" field to explicitly indicate that no files
588
606
  // should be included in the package
589
607
  "package-json/no-empty-fields": ["error", { ignoreProperties: ["files"] }],
608
+ // We use license instead
609
+ "package-json/require-attribution": "off",
610
+ // We are not open source
611
+ "package-json/require-repository": "off",
612
+ // This option is tricky to set right, especially for web component
613
+ // libraries that have many side effect entrypoints. It can also get out
614
+ // of date easily. If we don't explicitly indicate sideEffects, bundlers
615
+ // have good default AST-based heuristics.
616
+ "package-json/require-sideEffects": "off",
617
+ // Can't address these till 6.0 without breaking changes.
618
+ // Most errors are in react wrappers which will be dropped in 6.0.
619
+ "package-json/require-exports": "off",
590
620
  // Enforce a specific property order for better readability and consistency
591
621
  "package-json/order-properties": [
592
622
  "warn",
@@ -29,10 +29,16 @@ const storybookConfig = [
29
29
  "storybook/no-title-property-in-meta": "off",
30
30
  // Not applicable as we have a central Storybook config (@arcgis/storybook-utils)
31
31
  "storybook/no-uninstalled-addons": "off",
32
+ // Not that helpful as we have a central Storybook config (@arcgis/storybook-utils)
33
+ "storybook/no-renderer-packages": "off",
32
34
  // We never used storiesOf, and it's no longer included in Storybook
33
35
  "storybook/no-stories-of": "off",
34
36
  // Redundant with TypeScript
35
- "storybook/context-in-play-function": "off"
37
+ "storybook/context-in-play-function": "off",
38
+ // Enforces writing satisfies Meta after the meta object definition to ensure that stories use the correct properties in the metadata.
39
+ "storybook/meta-satisfies-type": "error",
40
+ // In our Lumina stories, render args should infer from Meta<T>/StoryObj<T>.
41
+ "webgis/no-story-render-args-type-annotation": "error"
36
42
  }
37
43
  }
38
44
  ];
@@ -1,5 +1,5 @@
1
1
  import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
2
- const version = "5.1.0-next.11";
2
+ const version = "5.1.0-next.112";
3
3
  const packageJson = {
4
4
  version
5
5
  };
@@ -81,6 +81,7 @@ function getComponentDeclaration(node) {
81
81
  }
82
82
  return;
83
83
  }
84
+ const sourceCodeDeclaresComponent = (sourceCode) => sourceCode.text.includes("interface DeclareElements");
84
85
  function isCreateEvent(node) {
85
86
  return node.value?.type === AST_NODE_TYPES.CallExpression && node.value.callee.type === AST_NODE_TYPES.Identifier && node.value.callee.name === "createEvent" && !node.static;
86
87
  }
@@ -144,16 +145,17 @@ export {
144
145
  luminaEntrypointName as a,
145
146
  luminaTestEntrypointName as b,
146
147
  getProperty as c,
147
- checkForLuminaJsx as d,
148
+ isCreateEvent as d,
148
149
  extractDeclareElementsInterface as e,
149
- isCreateEvent as f,
150
+ getName as f,
150
151
  getComponentDeclaration as g,
151
152
  hasDecorator as h,
152
153
  isGetterWithoutSetter as i,
153
- getName as j,
154
+ checkForLuminaJsx as j,
154
155
  isBindThisCallee as k,
155
156
  luminaJsxExportName as l,
156
157
  makeEslintPlugin as m,
157
158
  parsePropertyDecorator as p,
159
+ sourceCodeDeclaresComponent as s,
158
160
  unwrapExpression as u
159
161
  };
@@ -1,4 +1,4 @@
1
- import { m as makeEslintPlugin, l as luminaJsxExportName, a as luminaEntrypointName, b as luminaTestEntrypointName, p as parsePropertyDecorator, c as getProperty, i as isGetterWithoutSetter, d as checkForLuminaJsx, e as extractDeclareElementsInterface, f as isCreateEvent, h as hasDecorator, j as getName, k as isBindThisCallee, g as getComponentDeclaration, u as unwrapExpression } from "../../estree-DYv2wwWx.js";
1
+ import { m as makeEslintPlugin, l as luminaJsxExportName, a as luminaEntrypointName, b as luminaTestEntrypointName, s as sourceCodeDeclaresComponent, p as parsePropertyDecorator, c as getProperty, i as isGetterWithoutSetter, e as extractDeclareElementsInterface, d as isCreateEvent, h as hasDecorator, f as getName, j as checkForLuminaJsx, k as isBindThisCallee, g as getComponentDeclaration, u as unwrapExpression } from "../../estree-C51QozkW.js";
2
2
  import { AST_NODE_TYPES, ESLintUtils, AST_TOKEN_TYPES } from "@typescript-eslint/utils";
3
3
  import ts from "typescript";
4
4
  import { camelToKebab } from "@arcgis/toolkit/string";
@@ -7,16 +7,16 @@ const plugin = makeEslintPlugin(
7
7
  (rule) => `https://devtopia.esri.com/WebGIS/arcgis-web-components/tree/main/packages/support-packages/eslint-config/src/plugins/lumina/rules/${rule}.ts`
8
8
  );
9
9
  const importDeclaration = `import { ${luminaJsxExportName} } from "${luminaEntrypointName}";`;
10
- const description$l = `To use Lumina's JSX, you need to ${importDeclaration}`;
10
+ const description$m = `To use Lumina's JSX, you need to ${importDeclaration}`;
11
11
  plugin.createRule({
12
12
  name: "add-missing-jsx-import",
13
13
  meta: {
14
14
  docs: {
15
- description: description$l,
15
+ description: description$m,
16
16
  defaultLevel: "error"
17
17
  },
18
18
  messages: {
19
- addMissingJsxImport: description$l
19
+ addMissingJsxImport: description$m
20
20
  },
21
21
  type: "problem",
22
22
  schema: [],
@@ -73,12 +73,12 @@ plugin.createRule({
73
73
  };
74
74
  }
75
75
  });
76
- const description$k = "Auto add { type: Boolean } or { type: Number } where necessary";
76
+ const description$l = "Auto add { type: Boolean } or { type: Number } where necessary";
77
77
  plugin.createRule({
78
78
  name: "auto-add-type",
79
79
  meta: {
80
80
  docs: {
81
- description: description$k,
81
+ description: description$l,
82
82
  defaultLevel: "warn"
83
83
  },
84
84
  messages: {
@@ -96,6 +96,9 @@ More information: https://devtopia.esri.com/WebGIS/arcgis-web-components/issues/
96
96
  },
97
97
  defaultOptions: [],
98
98
  create(context) {
99
+ if (!sourceCodeDeclaresComponent(context.sourceCode)) {
100
+ return {};
101
+ }
99
102
  const services = ESLintUtils.getParserServices(context);
100
103
  return {
101
104
  Decorator(decorator) {
@@ -112,7 +115,7 @@ More information: https://devtopia.esri.com/WebGIS/arcgis-web-components/issues/
112
115
  const typeProperty = getProperty(properties, "type");
113
116
  const converterProperty = getProperty(properties, "converter");
114
117
  const isTrivialType = trivialType === "Number" || trivialType === "Boolean";
115
- if (isTrivialType && typeProperty !== void 0 && typeProperty.type === AST_NODE_TYPES.Identifier && (typeProperty.name === "Number" || typeProperty.name === "Boolean")) {
118
+ if (isTrivialType && typeProperty?.type === AST_NODE_TYPES.Identifier && (typeProperty.name === "Number" || typeProperty.name === "Boolean")) {
116
119
  context.report({
117
120
  node: typeProperty,
118
121
  messageId: "noUnnecessaryType",
@@ -274,6 +277,9 @@ plugin.createRule({
274
277
  type: "problem"
275
278
  },
276
279
  create(context) {
280
+ if (!sourceCodeDeclaresComponent(context.sourceCode)) {
281
+ return {};
282
+ }
277
283
  const bannedEventToMessageLookup = /* @__PURE__ */ new Map();
278
284
  context.options.forEach((option) => {
279
285
  const event = typeof option === "string" ? option : option.event;
@@ -294,32 +300,24 @@ plugin.createRule({
294
300
  });
295
301
  }
296
302
  }
297
- const luminaJsxCheck = checkForLuminaJsx();
298
303
  return {
299
- "ImportDeclaration": luminaJsxCheck,
300
304
  "CallExpression:matches([callee.property.name=addEventListener], [callee.property.name=removeEventListener]), CallExpression[callee.object.type=ThisExpression][callee.property.name=listen]"(node) {
301
- if (!luminaJsxCheck.isLuminaJsx) {
302
- return;
303
- }
304
305
  const eventName = node.arguments[0].value;
305
306
  checkEvent(node, eventName);
306
307
  },
307
308
  "CallExpression[callee.object.type=ThisExpression][callee.property.name=listenOn]"(node) {
308
- if (!luminaJsxCheck.isLuminaJsx) {
309
- return;
310
- }
311
309
  const eventName = node.arguments[1].value;
312
310
  checkEvent(node, eventName);
313
311
  }
314
312
  };
315
313
  }
316
314
  });
317
- const description$j = `Lumina component must be declared in a TSX file with a matching folder name located inside of src/components folder.`;
315
+ const description$k = `Lumina component must be declared in a TSX file with a matching folder name located inside of src/components folder.`;
318
316
  plugin.createRule({
319
317
  name: "component-placement-rules",
320
318
  meta: {
321
319
  docs: {
322
- description: description$j,
320
+ description: description$k,
323
321
  defaultLevel: "error"
324
322
  },
325
323
  messages: {
@@ -358,7 +356,7 @@ plugin.createRule({
358
356
  };
359
357
  }
360
358
  });
361
- const description$i = `Enforce consistent event naming.`;
359
+ const description$j = `Enforce consistent event naming.`;
362
360
  const defaultOptions$1 = [
363
361
  {
364
362
  eventNamespaces: ["arcgis"],
@@ -369,7 +367,7 @@ plugin.createRule({
369
367
  name: "consistent-event-naming",
370
368
  meta: {
371
369
  docs: {
372
- description: description$i,
370
+ description: description$j,
373
371
  defaultLevel: "warn"
374
372
  },
375
373
  messages: {
@@ -470,12 +468,12 @@ Discussion: https://devtopia.esri.com/WebGIS/arcgis-web-components/discussions/3
470
468
  }
471
469
  });
472
470
  const capitalAfterLower = /(?<=[a-z\d])[A-Z]/u;
473
- const description$h = `Enforce consistent usage of ? for marking property as nullable, rather than |null, |undefined or |Nil.`;
471
+ const description$i = `Enforce consistent usage of ? for marking property as nullable, rather than |null, |undefined or |Nil.`;
474
472
  plugin.createRule({
475
473
  name: "consistent-nullability",
476
474
  meta: {
477
475
  docs: {
478
- description: description$h,
476
+ description: description$i,
479
477
  // TODO: enable this by default
480
478
  defaultLevel: "off"
481
479
  },
@@ -551,18 +549,18 @@ plugin.createRule({
551
549
  };
552
550
  }
553
551
  });
554
- const description$g = `Enforce that @property(), @method() and createEvent() members are used in the correct context.`;
552
+ const description$h = `Enforce that @property(), @method() and createEvent() members are used in the correct context.`;
555
553
  plugin.createRule({
556
554
  name: "decorators-context",
557
555
  meta: {
558
556
  docs: {
559
- description: description$g,
557
+ description: description$h,
560
558
  defaultLevel: "error"
561
559
  },
562
560
  messages: {
563
561
  publicApiMustBePublic: `@property(), @method() and createEvent() members must not have private or protected modifier.
564
562
 
565
- If you wish to hide this member from public documentation, use @private or @protected JSDoc tags instead. Documentation: https://webgis.esri.com/references/lumina/documenting-components#excluding-api-from-public-documentation`,
563
+ If you wish to hide this member from public documentation, use @private or @internal JSDoc tags instead. Documentation: https://webgis.esri.com/references/api-extractor/tags-reference`,
566
564
  noPropertyDecoratorOnMethods: `Methods must not have @property() nor @state() decorator. Did you mean @property() instead?`,
567
565
  noCombinedPropertyEvent: `Property may either be an event (initialized with createEvent()) or a property (has @property() decorator), but not both`,
568
566
  noCombinedPropertyState: `Property may either be a state (initialized with @state()) or a property (has @property() decorator), but not both`,
@@ -574,6 +572,9 @@ If you wish to hide this member from public documentation, use @private or @prot
574
572
  },
575
573
  defaultOptions: [],
576
574
  create(context) {
575
+ if (!sourceCodeDeclaresComponent(context.sourceCode)) {
576
+ return {};
577
+ }
577
578
  return {
578
579
  PropertyDefinition(node) {
579
580
  const hasPropertyDecorator = hasDecorator(node, "property");
@@ -650,7 +651,7 @@ function isLuminaJsxType(type) {
650
651
  }
651
652
  const hasTypeFlag = (type, flag) => type.flags & flag ? true : (type.flags & ts.TypeFlags.Union) !== 0 && type.types.some((t) => hasTypeFlag(t, flag));
652
653
  const literalTypeFlag = ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BooleanLike;
653
- const description$f = `Need to add explicit type annotation: {{ setterType }}
654
+ const description$g = `Need to add explicit type annotation: {{ setterType }}
654
655
 
655
656
  Explanation:
656
657
  Lumina automatically creates an attribute for a property if property type includes a literal type (string|number|boolean).
@@ -661,11 +662,11 @@ plugin.createRule({
661
662
  name: "explicit-setter-type",
662
663
  meta: {
663
664
  docs: {
664
- description: description$f,
665
+ description: description$g,
665
666
  defaultLevel: "error"
666
667
  },
667
668
  messages: {
668
- explicitSetterType: description$f,
669
+ explicitSetterType: description$g,
669
670
  addExplicitSetterType: `Add {{ setterType }} type annotation`
670
671
  },
671
672
  type: "problem",
@@ -1211,16 +1212,16 @@ function isCreateElementComponent(node) {
1211
1212
  }
1212
1213
  return false;
1213
1214
  }
1214
- const description$e = `Use @internal or @private JSDoc tag over @ignore. See https://webgis.esri.com/references/lumina/documenting-components#excluding-api-from-public-documentation`;
1215
+ const description$f = `Use @internal or @private JSDoc tag over @ignore. See https://webgis.esri.com/references/api-extractor/tags-reference`;
1215
1216
  plugin.createRule({
1216
1217
  name: "no-ignore-jsdoc-tag",
1217
1218
  meta: {
1218
1219
  docs: {
1219
- description: description$e,
1220
+ description: description$f,
1220
1221
  defaultLevel: "error"
1221
1222
  },
1222
1223
  messages: {
1223
- noIgnoreJsDocTag: description$e
1224
+ noIgnoreJsDocTag: description$f
1224
1225
  },
1225
1226
  type: "problem",
1226
1227
  schema: []
@@ -1249,12 +1250,12 @@ plugin.createRule({
1249
1250
  }
1250
1251
  });
1251
1252
  const reIgnore = /\* @ignore/gu;
1252
- const description$d = `Detect incorrect usage of dynamic JSX tag name`;
1253
+ const description$e = `Detect incorrect usage of dynamic JSX tag name`;
1253
1254
  plugin.createRule({
1254
1255
  name: "no-incorrect-dynamic-tag-name",
1255
1256
  meta: {
1256
1257
  docs: {
1257
- description: description$d,
1258
+ description: description$e,
1258
1259
  defaultLevel: "error"
1259
1260
  },
1260
1261
  messages: {
@@ -1297,18 +1298,18 @@ plugin.createRule({
1297
1298
  };
1298
1299
  }
1299
1300
  });
1300
- const description$c = `If inline arrow function is passed to ref, it will be called again on each render.
1301
+ const description$d = `If inline arrow function is passed to ref, it will be called again on each render.
1301
1302
 
1302
1303
  If this is not desirable, see alternatives: https://webgis.esri.com/references/lumina/jsx#refs`;
1303
1304
  plugin.createRule({
1304
1305
  name: "no-inline-arrow-in-ref",
1305
1306
  meta: {
1306
1307
  docs: {
1307
- description: description$c,
1308
+ description: description$d,
1308
1309
  defaultLevel: "warn"
1309
1310
  },
1310
1311
  messages: {
1311
- errorInlineArrow: description$c
1312
+ errorInlineArrow: description$d
1312
1313
  },
1313
1314
  type: "problem",
1314
1315
  schema: []
@@ -1334,16 +1335,16 @@ plugin.createRule({
1334
1335
  };
1335
1336
  }
1336
1337
  });
1337
- const description$b = `Put @internal and @private on their own JSDoc line, not inline.`;
1338
+ const description$c = `Put @internal and @private on their own JSDoc line, not inline.`;
1338
1339
  plugin.createRule({
1339
1340
  name: "no-inline-exposure-jsdoc-tag",
1340
1341
  meta: {
1341
1342
  docs: {
1342
- description: description$b,
1343
+ description: description$c,
1343
1344
  defaultLevel: "error"
1344
1345
  },
1345
1346
  messages: {
1346
- inlineExposure: description$b
1347
+ inlineExposure: description$c
1347
1348
  },
1348
1349
  type: "problem",
1349
1350
  schema: []
@@ -1353,25 +1354,75 @@ plugin.createRule({
1353
1354
  return {
1354
1355
  "Program:exit"() {
1355
1356
  const source = context.sourceCode.text;
1356
- for (const match of source.matchAll(/@(?:internal|private)\b/gu)) {
1357
- const idx = match.index;
1358
- const lineStart = source.lastIndexOf("\n", idx - 1) + 1;
1359
- const before = source.slice(lineStart, idx).trim();
1360
- if (before === "*" || before === "/**") {
1357
+ for (const comment of context.sourceCode.getAllComments()) {
1358
+ const commentText = source.slice(comment.range[0], comment.range[1]);
1359
+ if (!commentText.startsWith("/**")) {
1361
1360
  continue;
1362
1361
  }
1363
- context.report({
1364
- messageId: "inlineExposure",
1365
- loc: {
1366
- start: context.sourceCode.getLocFromIndex(idx - 1),
1367
- end: context.sourceCode.getLocFromIndex(idx + match[0].length)
1362
+ for (const match of comment.value.matchAll(/@(?:internal|private)\b/gu)) {
1363
+ const idx = comment.range[0] + 2 + match.index;
1364
+ const lineStart = source.lastIndexOf("\n", idx - 1) + 1;
1365
+ const before = source.slice(lineStart, idx).trim();
1366
+ if (before === "*" || before === "/**") {
1367
+ continue;
1368
1368
  }
1369
- });
1369
+ context.report({
1370
+ messageId: "inlineExposure",
1371
+ loc: {
1372
+ start: context.sourceCode.getLocFromIndex(idx - 1),
1373
+ end: context.sourceCode.getLocFromIndex(idx + match[0].length)
1374
+ }
1375
+ });
1376
+ }
1370
1377
  }
1371
1378
  }
1372
1379
  };
1373
1380
  }
1374
1381
  });
1382
+ const absoluteDocsBaseUrl = "https://next.gha.afd.arcgis.com/";
1383
+ const description$b = `xref:// URLs are not supported in JSDoc. Use absolute links to ${absoluteDocsBaseUrl} instead.`;
1384
+ plugin.createRule({
1385
+ name: "no-jsdoc-xref-links",
1386
+ meta: {
1387
+ docs: {
1388
+ description: description$b,
1389
+ defaultLevel: "error"
1390
+ },
1391
+ messages: {
1392
+ noJsDocXrefLinks: description$b
1393
+ },
1394
+ type: "problem",
1395
+ schema: []
1396
+ },
1397
+ defaultOptions: [],
1398
+ create(context) {
1399
+ return {
1400
+ "Program:exit"() {
1401
+ const source = context.sourceCode.text;
1402
+ if (!source.includes("xref://")) {
1403
+ return;
1404
+ }
1405
+ for (const comment of context.sourceCode.getAllComments()) {
1406
+ const commentText = source.slice(comment.range[0], comment.range[1]);
1407
+ if (!commentText.startsWith("/**") || !commentText.includes("xref://")) {
1408
+ continue;
1409
+ }
1410
+ for (const match of commentText.matchAll(reXrefUrl)) {
1411
+ const idx = comment.range[0] + (match.index ?? 0);
1412
+ context.report({
1413
+ messageId: "noJsDocXrefLinks",
1414
+ loc: {
1415
+ start: context.sourceCode.getLocFromIndex(idx),
1416
+ end: context.sourceCode.getLocFromIndex(idx + match[0].length)
1417
+ }
1418
+ });
1419
+ }
1420
+ }
1421
+ }
1422
+ };
1423
+ }
1424
+ });
1425
+ const reXrefUrl = /xref:\/\/[\w./#-]+/gu;
1375
1426
  const description$a = `directives={} prop value must be an array literal. Documentation: https://webgis.esri.com/references/lumina/jsx#lit-directives`;
1376
1427
  plugin.createRule({
1377
1428
  name: "no-invalid-directives-prop",
@@ -1525,8 +1576,10 @@ plugin.createRule({
1525
1576
  },
1526
1577
  defaultOptions: [],
1527
1578
  create(context) {
1579
+ if (!sourceCodeDeclaresComponent(context.sourceCode)) {
1580
+ return {};
1581
+ }
1528
1582
  let className;
1529
- const hasLuminaDeclarations = context.sourceCode.text.includes("interface DeclareElements");
1530
1583
  return {
1531
1584
  TSModuleDeclaration(node) {
1532
1585
  const luminaDeclarationInterface = extractDeclareElementsInterface(node);
@@ -1536,7 +1589,7 @@ plugin.createRule({
1536
1589
  className = getComponentDeclaration(luminaDeclarationInterface)?.typeAnnotation?.typeAnnotation.typeName.name;
1537
1590
  },
1538
1591
  ExportNamedDeclaration(node) {
1539
- if (!hasLuminaDeclarations && className === void 0) {
1592
+ if (className === void 0) {
1540
1593
  return;
1541
1594
  }
1542
1595
  if (node.exportKind === "type") {
@@ -1571,7 +1624,7 @@ plugin.createRule({
1571
1624
  });
1572
1625
  },
1573
1626
  ExportDefaultDeclaration(node) {
1574
- if (!hasLuminaDeclarations && className === void 0) {
1627
+ if (className === void 0) {
1575
1628
  return;
1576
1629
  }
1577
1630
  context.report({
@@ -1580,7 +1633,7 @@ plugin.createRule({
1580
1633
  });
1581
1634
  },
1582
1635
  ExportAllDeclaration(node) {
1583
- if (!hasLuminaDeclarations && className === void 0) {
1636
+ if (className === void 0) {
1584
1637
  return;
1585
1638
  }
1586
1639
  if (node.exportKind === "type") {
@@ -1731,7 +1784,7 @@ plugin.createRule({
1731
1784
  return;
1732
1785
  }
1733
1786
  const argument = functionParent.params.at(0);
1734
- if (argument === void 0 || argument.type !== AST_NODE_TYPES.Identifier || argument.name !== eventVariableName) {
1787
+ if (argument?.type !== AST_NODE_TYPES.Identifier || argument.name !== eventVariableName) {
1735
1788
  return;
1736
1789
  }
1737
1790
  const reportPossiblyUnnecessaryTypeAssertion = () => context.report({
@@ -0,0 +1,2 @@
1
+ declare const _default: import('@typescript-eslint/utils/ts-eslint').RuleModule<"noJsDocXrefLinks", [], import('../../utils/makePlugin.ts').CommonDocs, import('@typescript-eslint/utils/ts-eslint').RuleListener>;
2
+ export default _default;
@@ -17,6 +17,9 @@ export declare function getComponentDeclaration(node: TSESTree.TSInterfaceDeclar
17
17
  };
18
18
  };
19
19
  } | undefined;
20
+ export declare const sourceCodeDeclaresComponent: (sourceCode: {
21
+ readonly text: string;
22
+ }) => boolean;
20
23
  export declare function isCreateEvent(node: TSESTree.PropertyDefinition): boolean;
21
24
  export declare const getProperty: (properties: TSESTree.ObjectLiteralElement[] | undefined, name: string) => TSESTree.Property["value"] | undefined;
22
25
  export declare function isGetterWithoutSetter(node: TSESTree.MethodDefinition | TSESTree.PropertyDefinition): boolean;
@@ -1,4 +1,4 @@
1
- import { m as makeEslintPlugin, e as extractDeclareElementsInterface, g as getComponentDeclaration } from "../../estree-DYv2wwWx.js";
1
+ import { m as makeEslintPlugin, e as extractDeclareElementsInterface, g as getComponentDeclaration } from "../../estree-C51QozkW.js";
2
2
  import { resolve } from "path/posix";
3
3
  import { AST_NODE_TYPES } from "@typescript-eslint/utils";
4
4
  const plugin = makeEslintPlugin(
@@ -7,16 +7,16 @@ const plugin = makeEslintPlugin(
7
7
  );
8
8
  const isTestFile = (filePath) => filePath.includes("/test") || filePath.includes(".test") || filePath.includes(".spec") || filePath.includes("e2e") || filePath.includes("__") || filePath.includes("/.");
9
9
  const isStorybookFile = (filePath) => filePath.includes(".stories");
10
- const description$5 = `Imports of files outside the src/ folder are not-portable and likely to break for consumers of this package.`;
10
+ const description$6 = `Imports of files outside the src/ folder are not-portable and likely to break for consumers of this package.`;
11
11
  plugin.createRule({
12
12
  name: "no-import-outside-src",
13
13
  meta: {
14
14
  docs: {
15
- description: description$5,
15
+ description: description$6,
16
16
  defaultLevel: "error"
17
17
  },
18
18
  messages: {
19
- noImportOutsideSrc: description$5
19
+ noImportOutsideSrc: description$6
20
20
  },
21
21
  type: "problem",
22
22
  schema: []
@@ -29,7 +29,7 @@ plugin.createRule({
29
29
  return {};
30
30
  }
31
31
  const basePath = fileName.slice(0, srcIndex + "/src/".length);
32
- if (isTestFile(fileName)) {
32
+ if (isTestFile(fileName) || isStorybookFile(fileName)) {
33
33
  return {};
34
34
  }
35
35
  return {
@@ -50,16 +50,16 @@ plugin.createRule({
50
50
  };
51
51
  }
52
52
  });
53
- const description$4 = `Having two JSDoc comments next to each other is most likely a mistake - consider combining them into one, or separating them for clarity.`;
53
+ const description$5 = `Having two JSDoc comments next to each other is most likely a mistake - consider combining them into one, or separating them for clarity.`;
54
54
  plugin.createRule({
55
55
  name: "no-touching-jsdoc",
56
56
  meta: {
57
57
  docs: {
58
- description: description$4,
58
+ description: description$5,
59
59
  defaultLevel: "warn"
60
60
  },
61
61
  messages: {
62
- noTouchingJsDoc: description$4
62
+ noTouchingJsDoc: description$5
63
63
  },
64
64
  type: "problem",
65
65
  schema: []
@@ -95,17 +95,17 @@ plugin.createRule({
95
95
  }
96
96
  });
97
97
  const reTouchingJsDoc = /\*\/\s+\/\*\*/gu;
98
- const description$3 = `@arcgis/core imports need to end with .js for better compatibility with ESM CDN builds for @arcgis/core and other packages.`;
98
+ const description$4 = `@arcgis/core imports need to end with .js for better compatibility with ESM CDN builds for @arcgis/core and other packages.`;
99
99
  const packagesToEnforce = ["@arcgis/core/", "@amcharts/amcharts4/", "@amcharts/amcharts5/"];
100
100
  plugin.createRule({
101
101
  name: "require-js-in-imports",
102
102
  meta: {
103
103
  docs: {
104
- description: description$3,
104
+ description: description$4,
105
105
  defaultLevel: "warn"
106
106
  },
107
107
  messages: {
108
- requireJsInCoreImport: description$3
108
+ requireJsInCoreImport: description$4
109
109
  },
110
110
  type: "problem",
111
111
  fixable: "code",
@@ -117,7 +117,7 @@ plugin.createRule({
117
117
  return {};
118
118
  }
119
119
  function updateSpecifier(node) {
120
- if (node.source.type !== AST_NODE_TYPES.Literal || node.importKind === "type") {
120
+ if (node.source.type !== AST_NODE_TYPES.Literal) {
121
121
  return;
122
122
  }
123
123
  const specifier = node.source.value;
@@ -139,17 +139,17 @@ plugin.createRule({
139
139
  };
140
140
  }
141
141
  });
142
- const description$2 = "Using .d.ts files is discouraged. Prefer .ts files instead, as they are type-checked and not in global scope.";
142
+ const description$3 = "Using .d.ts files is discouraged. Prefer .ts files instead, as they are type-checked and not in global scope.";
143
143
  const allowedNames = /* @__PURE__ */ new Set(["vite-env.d.ts", "components.d.ts"]);
144
144
  plugin.createRule({
145
145
  name: "no-dts-files",
146
146
  meta: {
147
147
  docs: {
148
- description: description$2,
148
+ description: description$3,
149
149
  defaultLevel: "warn"
150
150
  },
151
151
  messages: {
152
- avoidDtsFiles: description$2
152
+ avoidDtsFiles: description$3
153
153
  },
154
154
  type: "suggestion",
155
155
  schema: []
@@ -179,12 +179,12 @@ plugin.createRule({
179
179
  };
180
180
  }
181
181
  });
182
- const description$1 = `Enforce consistent logging so that ArcGIS developers can easily debug errors or warnings logged by our web components, which may lack a meaningful context in compiled code. See [our documentation on @arcgis/toolkit/log](https://webgis.esri.com/references/toolkit/log).`;
182
+ const description$2 = `Enforce consistent logging so that ArcGIS developers can easily debug errors or warnings logged by our web components, which may lack a meaningful context in compiled code. See [our documentation on @arcgis/toolkit/log](https://webgis.esri.com/references/toolkit/log).`;
183
183
  plugin.createRule({
184
184
  name: "consistent-logging",
185
185
  meta: {
186
186
  docs: {
187
- description: description$1,
187
+ description: description$2,
188
188
  defaultLevel: "off"
189
189
  // NOTE: this is turned on conditionally in root eslint config
190
190
  },
@@ -217,16 +217,16 @@ plugin.createRule({
217
217
  };
218
218
  }
219
219
  });
220
- const description = `Do not use links like [](#something) as they are not portable across .d.ts, and are not validated at build time. Use {@link } syntax, or absolute links. See https://webgis.esri.com/webgis/core/core/documenting-api#link`;
220
+ const description$1 = `Do not use links like [](#something) as they are not portable across .d.ts, and are not validated at build time. Use {@link } syntax, or absolute links. See https://webgis.esri.com/references/api-extractor/tags-reference#link)`;
221
221
  plugin.createRule({
222
222
  name: "no-unsafe-hash-links",
223
223
  meta: {
224
224
  docs: {
225
- description,
225
+ description: description$1,
226
226
  defaultLevel: "warn"
227
227
  },
228
228
  messages: {
229
- error: description
229
+ error: description$1
230
230
  },
231
231
  type: "problem",
232
232
  schema: [],
@@ -272,6 +272,47 @@ function computeReplacement(declareElementsInterface, anchor) {
272
272
  const tagName = declaration.key.value;
273
273
  return `components/${tagName}#${anchor}`;
274
274
  }
275
+ const description = "In Storybook render functions, let `args` infer from `Meta<T>` or `StoryObj<T>` instead of annotating the render parameter.";
276
+ plugin.createRule({
277
+ name: "no-story-render-args-type-annotation",
278
+ meta: {
279
+ docs: {
280
+ description,
281
+ defaultLevel: "off"
282
+ },
283
+ messages: {
284
+ noStoryRenderArgsTypeAnnotation: "Do not annotate `render(args)` in stories. Type the story with `Meta<T>` or `StoryObj<T>` and let `args` infer from that."
285
+ },
286
+ schema: [],
287
+ type: "suggestion",
288
+ fixable: "code"
289
+ },
290
+ defaultOptions: [],
291
+ create(context) {
292
+ if (!isStorybookFile(context.filename)) {
293
+ return {};
294
+ }
295
+ return {
296
+ Property(node) {
297
+ if (!isRenderProperty(node)) {
298
+ return;
299
+ }
300
+ const [firstParameter] = node.value.params;
301
+ if (firstParameter?.type !== AST_NODE_TYPES.Identifier || firstParameter.typeAnnotation === void 0) {
302
+ return;
303
+ }
304
+ context.report({
305
+ node: firstParameter.typeAnnotation,
306
+ messageId: "noStoryRenderArgsTypeAnnotation",
307
+ fix: (fixer) => fixer.remove(firstParameter.typeAnnotation)
308
+ });
309
+ }
310
+ };
311
+ }
312
+ });
313
+ function isRenderProperty(node) {
314
+ return node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "render" && (node.value.type === AST_NODE_TYPES.ArrowFunctionExpression || node.value.type === AST_NODE_TYPES.FunctionExpression);
315
+ }
275
316
  const webgisPlugin = plugin.finalize();
276
317
  export {
277
318
  webgisPlugin
@@ -0,0 +1,2 @@
1
+ declare const _default: import('@typescript-eslint/utils/ts-eslint').RuleModule<"noStoryRenderArgsTypeAnnotation", [], import('../../utils/makePlugin.ts').CommonDocs, import('@typescript-eslint/utils/ts-eslint').RuleListener>;
2
+ export default _default;
@@ -0,0 +1,24 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ /**
3
+ * A utility for temporary running ESLint with only specific rules enabled.
4
+ *
5
+ * @param config flat config
6
+ * @param enabledRules exceptions
7
+ * @param disableTypeChecking make ESLint much faster by temporary disabling
8
+ * type-aware linting.
9
+ * @returns a new flat config array where every rule is disabled,
10
+ * except for rules explicitly listed in `enabledRules`.
11
+ *
12
+ * @example
13
+ * const config = [
14
+ * // Your ESLint flat config
15
+ * ];
16
+ * export default disableAllRulesExcept(
17
+ * config,
18
+ * {
19
+ * "rule-name-1": "error",
20
+ * },
21
+ * true,
22
+ * );
23
+ */
24
+ export declare function disableAllRulesExcept(config: TSESLint.FlatConfig.ConfigArray, enabledRules: Record<string, TSESLint.FlatConfig.RuleLevel>, disableTypeChecking: boolean): TSESLint.FlatConfig.ConfigArray;
@@ -0,0 +1,47 @@
1
+ function disableAllRulesExcept(config, enabledRules, disableTypeChecking) {
2
+ return config.map((entry) => applyRulesAndOptions(entry, enabledRules, disableTypeChecking));
3
+ }
4
+ function applyRulesAndOptions(entry, enabledRules, disableTypeChecking) {
5
+ if (!entry || typeof entry !== "object") {
6
+ return entry;
7
+ }
8
+ const nextEntry = entry.rules ? {
9
+ ...entry,
10
+ rules: Object.fromEntries(
11
+ Object.keys(entry.rules).map((ruleName) => {
12
+ const override = enabledRules[ruleName];
13
+ return [ruleName, override ?? "off"];
14
+ })
15
+ )
16
+ } : entry;
17
+ return tweakOptions(nextEntry, disableTypeChecking);
18
+ }
19
+ function tweakOptions(entry, disableTypeChecking) {
20
+ if (entry.linterOptions !== void 0) {
21
+ entry = {
22
+ ...entry,
23
+ linterOptions: {
24
+ ...entry.linterOptions,
25
+ reportUnusedDisableDirectives: "off",
26
+ reportUnusedInlineConfigs: "off"
27
+ }
28
+ };
29
+ }
30
+ if (disableTypeChecking && entry.languageOptions?.parserOptions) {
31
+ entry = {
32
+ ...entry,
33
+ languageOptions: {
34
+ ...entry.languageOptions,
35
+ parserOptions: {
36
+ ...entry.languageOptions.parserOptions,
37
+ project: void 0,
38
+ projectService: void 0
39
+ }
40
+ }
41
+ };
42
+ }
43
+ return entry;
44
+ }
45
+ export {
46
+ disableAllRulesExcept
47
+ };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@arcgis/eslint-config",
3
- "version": "5.1.0-next.11",
4
- "description": "ESLint configuration for arcgis-web-components",
3
+ "version": "5.1.0-next.112",
4
+ "description": "ESLint configuration for WebGIS SDK",
5
5
  "type": "module",
6
- "main": "index.js",
7
- "module": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
6
  "exports": {
10
7
  ".": "./dist/config/index.js",
8
+ "./ts": "./src/config/index.ts",
11
9
  "./application": "./dist/config/applications.js",
12
10
  "./extra": "./dist/config/extra.js",
13
11
  "./lumina": "./dist/config/lumina.js",
12
+ "./lumina/ts": "./src/config/lumina.ts",
14
13
  "./plugins/webgis": "./dist/plugins/webgis/index.js",
15
14
  "./plugins/lumina": "./dist/plugins/lumina/index.js",
15
+ "./utils/disable-rules": "./dist/utils/disable-rules.js",
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "files": [
@@ -20,21 +20,21 @@
20
20
  ],
21
21
  "license": "SEE LICENSE IN LICENSE.md",
22
22
  "dependencies": {
23
- "@eslint/js": "^9.39.1",
24
- "@eslint/markdown": "^7.5.1",
23
+ "@eslint/js": "^10.0.1",
24
+ "@eslint/markdown": "^8.0.1",
25
25
  "@types/confusing-browser-globals": "^1.0.3",
26
- "@typescript-eslint/utils": "^8.46.4",
26
+ "@typescript-eslint/utils": "^8.58.0",
27
27
  "confusing-browser-globals": "^1.0.11",
28
- "eslint-plugin-package-json": "^0.88.1",
29
- "eslint-plugin-storybook": "^0.12.0",
28
+ "eslint-plugin-package-json": "~0.91.1",
29
+ "eslint-plugin-storybook": "^10.3.4",
30
30
  "globals": "^16.5.0",
31
- "jsonc-eslint-parser": "^2.0.0",
31
+ "jsonc-eslint-parser": "^3.1.0",
32
32
  "tslib": "^2.8.1",
33
- "typescript": "~5.9.3",
34
- "typescript-eslint": "^8.46.3",
35
- "@arcgis/toolkit": "5.1.0-next.11"
33
+ "typescript": "~6.0.2",
34
+ "typescript-eslint": "^8.58.0",
35
+ "@arcgis/toolkit": "5.1.0-next.112"
36
36
  },
37
37
  "peerDependencies": {
38
- "eslint": "^9.39.1"
38
+ "eslint": "^10.2.0"
39
39
  }
40
40
  }