@arcgis/eslint-config 5.1.0-next.7 → 5.1.0-next.71
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/dist/config/index.js +31 -1
- package/dist/config/lumina.js +2 -0
- package/dist/estree-IANpebc8.js +161 -0
- package/dist/plugins/lumina/index.js +87 -138
- package/dist/plugins/lumina/rules/no-inline-exposure-jsdoc-tag.d.ts +2 -0
- package/dist/plugins/lumina/utils/estree.d.ts +11 -0
- package/dist/plugins/webgis/index.js +71 -16
- package/dist/plugins/webgis/rules/no-unsafe-hash-links.d.ts +2 -0
- package/dist/utils/disable-rules.d.ts +24 -0
- package/dist/utils/disable-rules.js +47 -0
- package/package.json +15 -12
- package/dist/makePlugin-bIDN023m.js +0 -41
package/dist/config/index.js
CHANGED
|
@@ -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
|
-
|
|
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",
|
package/dist/config/lumina.js
CHANGED
|
@@ -29,6 +29,8 @@ 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
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
+
const version = "5.1.0-next.71";
|
|
3
|
+
const packageJson = {
|
|
4
|
+
version
|
|
5
|
+
};
|
|
6
|
+
function makeEslintPlugin(pluginName, urlCreator) {
|
|
7
|
+
const rules = [];
|
|
8
|
+
const creator = ESLintUtils.RuleCreator(urlCreator);
|
|
9
|
+
return {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
11
|
+
createRule(rule) {
|
|
12
|
+
const { meta, name, ...rest } = rule;
|
|
13
|
+
const docs = { ...meta.docs, name };
|
|
14
|
+
const ruleModule = creator({ ...rest, meta: { ...meta, docs }, name });
|
|
15
|
+
rules.push(ruleModule);
|
|
16
|
+
return ruleModule;
|
|
17
|
+
},
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
19
|
+
finalize() {
|
|
20
|
+
const config = {
|
|
21
|
+
rules: Object.fromEntries(
|
|
22
|
+
rules.map((rule) => [`${pluginName}/${rule.meta.docs.name}`, rule.meta.docs.defaultLevel])
|
|
23
|
+
)
|
|
24
|
+
};
|
|
25
|
+
const plugin = {
|
|
26
|
+
meta: { name: `@arcgis/eslint-plugin-${pluginName}`, version: packageJson.version },
|
|
27
|
+
configs: {
|
|
28
|
+
recommended: config
|
|
29
|
+
},
|
|
30
|
+
rules: Object.fromEntries(rules.map((rule) => [rule.meta.docs.name, rule]))
|
|
31
|
+
};
|
|
32
|
+
config.plugins = {
|
|
33
|
+
[pluginName]: plugin
|
|
34
|
+
};
|
|
35
|
+
return plugin;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const unwrapExpression = (expression) => expression.type === AST_NODE_TYPES.TSAsExpression || expression.type === AST_NODE_TYPES.TSNonNullExpression || expression.type === AST_NODE_TYPES.TSSatisfiesExpression ? unwrapExpression(expression.expression) : expression;
|
|
40
|
+
const luminaEntrypointName = "@arcgis/lumina";
|
|
41
|
+
const luminaTestEntrypointName = "@arcgis/lumina-compiler/testing";
|
|
42
|
+
const luminaJsxExportName = "h";
|
|
43
|
+
function checkForLuminaJsx() {
|
|
44
|
+
const ImportDeclaration = (node) => {
|
|
45
|
+
if (node.source.value !== luminaEntrypointName) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
for (const specifier of node.specifiers) {
|
|
49
|
+
if (specifier.type === AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES.Identifier && specifier.imported.name === luminaJsxExportName || specifier.imported.type === AST_NODE_TYPES.Literal && specifier.imported.value === luminaJsxExportName)) {
|
|
50
|
+
withProperty.isLuminaJsx = true;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const withProperty = ImportDeclaration;
|
|
56
|
+
return withProperty;
|
|
57
|
+
}
|
|
58
|
+
function hasDecorator(node, decoratorName) {
|
|
59
|
+
return node.decorators.some(
|
|
60
|
+
(decorator) => decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === decoratorName
|
|
61
|
+
) ?? false;
|
|
62
|
+
}
|
|
63
|
+
function extractDeclareElementsInterface(node) {
|
|
64
|
+
return node.kind === "global" ? node.body.body.find(
|
|
65
|
+
(node2) => node2.type === AST_NODE_TYPES.TSInterfaceDeclaration && node2.id.name === "DeclareElements"
|
|
66
|
+
) : void 0;
|
|
67
|
+
}
|
|
68
|
+
function getComponentDeclaration(node) {
|
|
69
|
+
for (const member of node.body.body) {
|
|
70
|
+
if (member.type !== AST_NODE_TYPES.TSPropertySignature) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const type = member.typeAnnotation?.typeAnnotation;
|
|
74
|
+
if (type?.type !== AST_NODE_TYPES.TSTypeReference || type.typeName.type !== AST_NODE_TYPES.Identifier) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (member.key.type !== AST_NODE_TYPES.Literal) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
return member;
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const sourceCodeDeclaresComponent = (sourceCode) => sourceCode.text.includes("interface DeclareElements");
|
|
85
|
+
function isCreateEvent(node) {
|
|
86
|
+
return node.value?.type === AST_NODE_TYPES.CallExpression && node.value.callee.type === AST_NODE_TYPES.Identifier && node.value.callee.name === "createEvent" && !node.static;
|
|
87
|
+
}
|
|
88
|
+
const getProperty = (properties, name) => properties?.find(
|
|
89
|
+
(option) => option.type === AST_NODE_TYPES.Property && option.key.type === AST_NODE_TYPES.Identifier && option.key.name === name
|
|
90
|
+
)?.value;
|
|
91
|
+
function isGetterWithoutSetter(node) {
|
|
92
|
+
const isGetter = node.type === AST_NODE_TYPES.MethodDefinition && node.kind === "get";
|
|
93
|
+
if (!isGetter) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
const index = node.parent.body.indexOf(node);
|
|
97
|
+
const previousNode = node.parent.body.at(index - 1);
|
|
98
|
+
const nextNode = node.parent.body.at(index + 1);
|
|
99
|
+
const name = getName(node);
|
|
100
|
+
if (name === void 0) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const previousIsSetter = previousNode?.type === AST_NODE_TYPES.MethodDefinition && previousNode.kind === "set" && getName(previousNode) === name;
|
|
104
|
+
if (previousIsSetter) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const nextIsSetter = nextNode?.type === AST_NODE_TYPES.MethodDefinition && nextNode.kind === "set" && getName(nextNode) === name;
|
|
108
|
+
return !nextIsSetter;
|
|
109
|
+
}
|
|
110
|
+
function getName(node) {
|
|
111
|
+
if (node.key.type === AST_NODE_TYPES.Identifier) {
|
|
112
|
+
return node.key.name;
|
|
113
|
+
} else if (node.key.type === AST_NODE_TYPES.Literal && typeof node.key.value === "string") {
|
|
114
|
+
return node.key.value;
|
|
115
|
+
} else {
|
|
116
|
+
return void 0;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function parsePropertyDecorator(decorator) {
|
|
120
|
+
const isPropertyDecorator = decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === "property";
|
|
121
|
+
if (!isPropertyDecorator) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const callExpression = decorator?.expression.type === AST_NODE_TYPES.CallExpression ? decorator.expression : void 0;
|
|
125
|
+
if (callExpression === void 0) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const options = callExpression.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression ? callExpression.arguments[0] : void 0;
|
|
129
|
+
const properties = options?.properties;
|
|
130
|
+
return {
|
|
131
|
+
callExpression,
|
|
132
|
+
options,
|
|
133
|
+
properties
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function isBindThisCallee(callee) {
|
|
137
|
+
return callee.type === AST_NODE_TYPES.MemberExpression && // expression.identifier(this)
|
|
138
|
+
callee.property.type === AST_NODE_TYPES.Identifier && // expression.bind(this)
|
|
139
|
+
callee.property.name === "bind" && // expression.expression.bind(this)
|
|
140
|
+
callee.object.type === AST_NODE_TYPES.MemberExpression && // expression.identifier.bind(this)
|
|
141
|
+
callee.object.property.type === AST_NODE_TYPES.Identifier && // this.identifier.bind(this)
|
|
142
|
+
callee.object.object.type === AST_NODE_TYPES.ThisExpression;
|
|
143
|
+
}
|
|
144
|
+
export {
|
|
145
|
+
luminaEntrypointName as a,
|
|
146
|
+
luminaTestEntrypointName as b,
|
|
147
|
+
getProperty as c,
|
|
148
|
+
isCreateEvent as d,
|
|
149
|
+
extractDeclareElementsInterface as e,
|
|
150
|
+
getName as f,
|
|
151
|
+
getComponentDeclaration as g,
|
|
152
|
+
hasDecorator as h,
|
|
153
|
+
isGetterWithoutSetter as i,
|
|
154
|
+
checkForLuminaJsx as j,
|
|
155
|
+
isBindThisCallee as k,
|
|
156
|
+
luminaJsxExportName as l,
|
|
157
|
+
makeEslintPlugin as m,
|
|
158
|
+
parsePropertyDecorator as p,
|
|
159
|
+
sourceCodeDeclaresComponent as s,
|
|
160
|
+
unwrapExpression as u
|
|
161
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as makeEslintPlugin } from "../../
|
|
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-IANpebc8.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";
|
|
@@ -6,105 +6,17 @@ const plugin = makeEslintPlugin(
|
|
|
6
6
|
"lumina",
|
|
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
|
-
const unwrapExpression = (expression) => expression.type === AST_NODE_TYPES.TSAsExpression || expression.type === AST_NODE_TYPES.TSNonNullExpression || expression.type === AST_NODE_TYPES.TSSatisfiesExpression ? unwrapExpression(expression.expression) : expression;
|
|
10
|
-
const luminaEntrypointName = "@arcgis/lumina";
|
|
11
|
-
const luminaTestEntrypointName = "@arcgis/lumina-compiler/testing";
|
|
12
|
-
const luminaJsxExportName = "h";
|
|
13
|
-
function checkForLuminaJsx() {
|
|
14
|
-
const ImportDeclaration = (node) => {
|
|
15
|
-
if (node.source.value !== luminaEntrypointName) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
for (const specifier of node.specifiers) {
|
|
19
|
-
if (specifier.type === AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES.Identifier && specifier.imported.name === luminaJsxExportName || specifier.imported.type === AST_NODE_TYPES.Literal && specifier.imported.value === luminaJsxExportName)) {
|
|
20
|
-
withProperty.isLuminaJsx = true;
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
const withProperty = ImportDeclaration;
|
|
26
|
-
return withProperty;
|
|
27
|
-
}
|
|
28
|
-
function hasDecorator(node, decoratorName) {
|
|
29
|
-
return node.decorators.some(
|
|
30
|
-
(decorator) => decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === decoratorName
|
|
31
|
-
) ?? false;
|
|
32
|
-
}
|
|
33
|
-
function extractDeclareElementsInterface(node) {
|
|
34
|
-
return node.kind === "global" ? node.body.body.find(
|
|
35
|
-
(node2) => node2.type === AST_NODE_TYPES.TSInterfaceDeclaration && node2.id.name === "DeclareElements"
|
|
36
|
-
) : void 0;
|
|
37
|
-
}
|
|
38
|
-
function isCreateEvent(node) {
|
|
39
|
-
return node.value?.type === AST_NODE_TYPES.CallExpression && node.value.callee.type === AST_NODE_TYPES.Identifier && node.value.callee.name === "createEvent" && !node.static;
|
|
40
|
-
}
|
|
41
|
-
const getProperty = (properties, name) => properties?.find(
|
|
42
|
-
(option) => option.type === AST_NODE_TYPES.Property && option.key.type === AST_NODE_TYPES.Identifier && option.key.name === name
|
|
43
|
-
)?.value;
|
|
44
|
-
function isGetterWithoutSetter(node) {
|
|
45
|
-
const isGetter = node.type === AST_NODE_TYPES.MethodDefinition && node.kind === "get";
|
|
46
|
-
if (!isGetter) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
const index = node.parent.body.indexOf(node);
|
|
50
|
-
const previousNode = node.parent.body.at(index - 1);
|
|
51
|
-
const nextNode = node.parent.body.at(index + 1);
|
|
52
|
-
const name = getName(node);
|
|
53
|
-
if (name === void 0) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
const previousIsSetter = previousNode?.type === AST_NODE_TYPES.MethodDefinition && previousNode.kind === "set" && getName(previousNode) === name;
|
|
57
|
-
if (previousIsSetter) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
const nextIsSetter = nextNode?.type === AST_NODE_TYPES.MethodDefinition && nextNode.kind === "set" && getName(nextNode) === name;
|
|
61
|
-
return !nextIsSetter;
|
|
62
|
-
}
|
|
63
|
-
function getName(node) {
|
|
64
|
-
if (node.key.type === AST_NODE_TYPES.Identifier) {
|
|
65
|
-
return node.key.name;
|
|
66
|
-
} else if (node.key.type === AST_NODE_TYPES.Literal && typeof node.key.value === "string") {
|
|
67
|
-
return node.key.value;
|
|
68
|
-
} else {
|
|
69
|
-
return void 0;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function parsePropertyDecorator(decorator) {
|
|
73
|
-
const isPropertyDecorator = decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === "property";
|
|
74
|
-
if (!isPropertyDecorator) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
const callExpression = decorator?.expression.type === AST_NODE_TYPES.CallExpression ? decorator.expression : void 0;
|
|
78
|
-
if (callExpression === void 0) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const options = callExpression.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression ? callExpression.arguments[0] : void 0;
|
|
82
|
-
const properties = options?.properties;
|
|
83
|
-
return {
|
|
84
|
-
callExpression,
|
|
85
|
-
options,
|
|
86
|
-
properties
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function isBindThisCallee(callee) {
|
|
90
|
-
return callee.type === AST_NODE_TYPES.MemberExpression && // expression.identifier(this)
|
|
91
|
-
callee.property.type === AST_NODE_TYPES.Identifier && // expression.bind(this)
|
|
92
|
-
callee.property.name === "bind" && // expression.expression.bind(this)
|
|
93
|
-
callee.object.type === AST_NODE_TYPES.MemberExpression && // expression.identifier.bind(this)
|
|
94
|
-
callee.object.property.type === AST_NODE_TYPES.Identifier && // this.identifier.bind(this)
|
|
95
|
-
callee.object.object.type === AST_NODE_TYPES.ThisExpression;
|
|
96
|
-
}
|
|
97
9
|
const importDeclaration = `import { ${luminaJsxExportName} } from "${luminaEntrypointName}";`;
|
|
98
|
-
const description$
|
|
10
|
+
const description$l = `To use Lumina's JSX, you need to ${importDeclaration}`;
|
|
99
11
|
plugin.createRule({
|
|
100
12
|
name: "add-missing-jsx-import",
|
|
101
13
|
meta: {
|
|
102
14
|
docs: {
|
|
103
|
-
description: description$
|
|
15
|
+
description: description$l,
|
|
104
16
|
defaultLevel: "error"
|
|
105
17
|
},
|
|
106
18
|
messages: {
|
|
107
|
-
addMissingJsxImport: description$
|
|
19
|
+
addMissingJsxImport: description$l
|
|
108
20
|
},
|
|
109
21
|
type: "problem",
|
|
110
22
|
schema: [],
|
|
@@ -161,12 +73,12 @@ plugin.createRule({
|
|
|
161
73
|
};
|
|
162
74
|
}
|
|
163
75
|
});
|
|
164
|
-
const description$
|
|
76
|
+
const description$k = "Auto add { type: Boolean } or { type: Number } where necessary";
|
|
165
77
|
plugin.createRule({
|
|
166
78
|
name: "auto-add-type",
|
|
167
79
|
meta: {
|
|
168
80
|
docs: {
|
|
169
|
-
description: description$
|
|
81
|
+
description: description$k,
|
|
170
82
|
defaultLevel: "warn"
|
|
171
83
|
},
|
|
172
84
|
messages: {
|
|
@@ -184,6 +96,9 @@ More information: https://devtopia.esri.com/WebGIS/arcgis-web-components/issues/
|
|
|
184
96
|
},
|
|
185
97
|
defaultOptions: [],
|
|
186
98
|
create(context) {
|
|
99
|
+
if (!sourceCodeDeclaresComponent(context.sourceCode)) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
187
102
|
const services = ESLintUtils.getParserServices(context);
|
|
188
103
|
return {
|
|
189
104
|
Decorator(decorator) {
|
|
@@ -362,6 +277,9 @@ plugin.createRule({
|
|
|
362
277
|
type: "problem"
|
|
363
278
|
},
|
|
364
279
|
create(context) {
|
|
280
|
+
if (!sourceCodeDeclaresComponent(context.sourceCode)) {
|
|
281
|
+
return {};
|
|
282
|
+
}
|
|
365
283
|
const bannedEventToMessageLookup = /* @__PURE__ */ new Map();
|
|
366
284
|
context.options.forEach((option) => {
|
|
367
285
|
const event = typeof option === "string" ? option : option.event;
|
|
@@ -382,32 +300,24 @@ plugin.createRule({
|
|
|
382
300
|
});
|
|
383
301
|
}
|
|
384
302
|
}
|
|
385
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
386
303
|
return {
|
|
387
|
-
"ImportDeclaration": luminaJsxCheck,
|
|
388
304
|
"CallExpression:matches([callee.property.name=addEventListener], [callee.property.name=removeEventListener]), CallExpression[callee.object.type=ThisExpression][callee.property.name=listen]"(node) {
|
|
389
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
305
|
const eventName = node.arguments[0].value;
|
|
393
306
|
checkEvent(node, eventName);
|
|
394
307
|
},
|
|
395
308
|
"CallExpression[callee.object.type=ThisExpression][callee.property.name=listenOn]"(node) {
|
|
396
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
309
|
const eventName = node.arguments[1].value;
|
|
400
310
|
checkEvent(node, eventName);
|
|
401
311
|
}
|
|
402
312
|
};
|
|
403
313
|
}
|
|
404
314
|
});
|
|
405
|
-
const description$
|
|
315
|
+
const description$j = `Lumina component must be declared in a TSX file with a matching folder name located inside of src/components folder.`;
|
|
406
316
|
plugin.createRule({
|
|
407
317
|
name: "component-placement-rules",
|
|
408
318
|
meta: {
|
|
409
319
|
docs: {
|
|
410
|
-
description: description$
|
|
320
|
+
description: description$j,
|
|
411
321
|
defaultLevel: "error"
|
|
412
322
|
},
|
|
413
323
|
messages: {
|
|
@@ -446,7 +356,7 @@ plugin.createRule({
|
|
|
446
356
|
};
|
|
447
357
|
}
|
|
448
358
|
});
|
|
449
|
-
const description$
|
|
359
|
+
const description$i = `Enforce consistent event naming.`;
|
|
450
360
|
const defaultOptions$1 = [
|
|
451
361
|
{
|
|
452
362
|
eventNamespaces: ["arcgis"],
|
|
@@ -457,7 +367,7 @@ plugin.createRule({
|
|
|
457
367
|
name: "consistent-event-naming",
|
|
458
368
|
meta: {
|
|
459
369
|
docs: {
|
|
460
|
-
description: description$
|
|
370
|
+
description: description$i,
|
|
461
371
|
defaultLevel: "warn"
|
|
462
372
|
},
|
|
463
373
|
messages: {
|
|
@@ -558,12 +468,12 @@ Discussion: https://devtopia.esri.com/WebGIS/arcgis-web-components/discussions/3
|
|
|
558
468
|
}
|
|
559
469
|
});
|
|
560
470
|
const capitalAfterLower = /(?<=[a-z\d])[A-Z]/u;
|
|
561
|
-
const description$
|
|
471
|
+
const description$h = `Enforce consistent usage of ? for marking property as nullable, rather than |null, |undefined or |Nil.`;
|
|
562
472
|
plugin.createRule({
|
|
563
473
|
name: "consistent-nullability",
|
|
564
474
|
meta: {
|
|
565
475
|
docs: {
|
|
566
|
-
description: description$
|
|
476
|
+
description: description$h,
|
|
567
477
|
// TODO: enable this by default
|
|
568
478
|
defaultLevel: "off"
|
|
569
479
|
},
|
|
@@ -639,12 +549,12 @@ plugin.createRule({
|
|
|
639
549
|
};
|
|
640
550
|
}
|
|
641
551
|
});
|
|
642
|
-
const description$
|
|
552
|
+
const description$g = `Enforce that @property(), @method() and createEvent() members are used in the correct context.`;
|
|
643
553
|
plugin.createRule({
|
|
644
554
|
name: "decorators-context",
|
|
645
555
|
meta: {
|
|
646
556
|
docs: {
|
|
647
|
-
description: description$
|
|
557
|
+
description: description$g,
|
|
648
558
|
defaultLevel: "error"
|
|
649
559
|
},
|
|
650
560
|
messages: {
|
|
@@ -662,6 +572,9 @@ If you wish to hide this member from public documentation, use @private or @prot
|
|
|
662
572
|
},
|
|
663
573
|
defaultOptions: [],
|
|
664
574
|
create(context) {
|
|
575
|
+
if (!sourceCodeDeclaresComponent(context.sourceCode)) {
|
|
576
|
+
return {};
|
|
577
|
+
}
|
|
665
578
|
return {
|
|
666
579
|
PropertyDefinition(node) {
|
|
667
580
|
const hasPropertyDecorator = hasDecorator(node, "property");
|
|
@@ -738,7 +651,7 @@ function isLuminaJsxType(type) {
|
|
|
738
651
|
}
|
|
739
652
|
const hasTypeFlag = (type, flag) => type.flags & flag ? true : (type.flags & ts.TypeFlags.Union) !== 0 && type.types.some((t) => hasTypeFlag(t, flag));
|
|
740
653
|
const literalTypeFlag = ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BooleanLike;
|
|
741
|
-
const description$
|
|
654
|
+
const description$f = `Need to add explicit type annotation: {{ setterType }}
|
|
742
655
|
|
|
743
656
|
Explanation:
|
|
744
657
|
Lumina automatically creates an attribute for a property if property type includes a literal type (string|number|boolean).
|
|
@@ -749,11 +662,11 @@ plugin.createRule({
|
|
|
749
662
|
name: "explicit-setter-type",
|
|
750
663
|
meta: {
|
|
751
664
|
docs: {
|
|
752
|
-
description: description$
|
|
665
|
+
description: description$f,
|
|
753
666
|
defaultLevel: "error"
|
|
754
667
|
},
|
|
755
668
|
messages: {
|
|
756
|
-
explicitSetterType: description$
|
|
669
|
+
explicitSetterType: description$f,
|
|
757
670
|
addExplicitSetterType: `Add {{ setterType }} type annotation`
|
|
758
671
|
},
|
|
759
672
|
type: "problem",
|
|
@@ -1299,16 +1212,16 @@ function isCreateElementComponent(node) {
|
|
|
1299
1212
|
}
|
|
1300
1213
|
return false;
|
|
1301
1214
|
}
|
|
1302
|
-
const description$
|
|
1215
|
+
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`;
|
|
1303
1216
|
plugin.createRule({
|
|
1304
1217
|
name: "no-ignore-jsdoc-tag",
|
|
1305
1218
|
meta: {
|
|
1306
1219
|
docs: {
|
|
1307
|
-
description: description$
|
|
1220
|
+
description: description$e,
|
|
1308
1221
|
defaultLevel: "error"
|
|
1309
1222
|
},
|
|
1310
1223
|
messages: {
|
|
1311
|
-
noIgnoreJsDocTag: description$
|
|
1224
|
+
noIgnoreJsDocTag: description$e
|
|
1312
1225
|
},
|
|
1313
1226
|
type: "problem",
|
|
1314
1227
|
schema: []
|
|
@@ -1337,12 +1250,12 @@ plugin.createRule({
|
|
|
1337
1250
|
}
|
|
1338
1251
|
});
|
|
1339
1252
|
const reIgnore = /\* @ignore/gu;
|
|
1340
|
-
const description$
|
|
1253
|
+
const description$d = `Detect incorrect usage of dynamic JSX tag name`;
|
|
1341
1254
|
plugin.createRule({
|
|
1342
1255
|
name: "no-incorrect-dynamic-tag-name",
|
|
1343
1256
|
meta: {
|
|
1344
1257
|
docs: {
|
|
1345
|
-
description: description$
|
|
1258
|
+
description: description$d,
|
|
1346
1259
|
defaultLevel: "error"
|
|
1347
1260
|
},
|
|
1348
1261
|
messages: {
|
|
@@ -1385,18 +1298,18 @@ plugin.createRule({
|
|
|
1385
1298
|
};
|
|
1386
1299
|
}
|
|
1387
1300
|
});
|
|
1388
|
-
const description$
|
|
1301
|
+
const description$c = `If inline arrow function is passed to ref, it will be called again on each render.
|
|
1389
1302
|
|
|
1390
1303
|
If this is not desirable, see alternatives: https://webgis.esri.com/references/lumina/jsx#refs`;
|
|
1391
1304
|
plugin.createRule({
|
|
1392
1305
|
name: "no-inline-arrow-in-ref",
|
|
1393
1306
|
meta: {
|
|
1394
1307
|
docs: {
|
|
1395
|
-
description: description$
|
|
1308
|
+
description: description$c,
|
|
1396
1309
|
defaultLevel: "warn"
|
|
1397
1310
|
},
|
|
1398
1311
|
messages: {
|
|
1399
|
-
errorInlineArrow: description$
|
|
1312
|
+
errorInlineArrow: description$c
|
|
1400
1313
|
},
|
|
1401
1314
|
type: "problem",
|
|
1402
1315
|
schema: []
|
|
@@ -1422,6 +1335,50 @@ plugin.createRule({
|
|
|
1422
1335
|
};
|
|
1423
1336
|
}
|
|
1424
1337
|
});
|
|
1338
|
+
const description$b = `Put @internal and @private on their own JSDoc line, not inline.`;
|
|
1339
|
+
plugin.createRule({
|
|
1340
|
+
name: "no-inline-exposure-jsdoc-tag",
|
|
1341
|
+
meta: {
|
|
1342
|
+
docs: {
|
|
1343
|
+
description: description$b,
|
|
1344
|
+
defaultLevel: "error"
|
|
1345
|
+
},
|
|
1346
|
+
messages: {
|
|
1347
|
+
inlineExposure: description$b
|
|
1348
|
+
},
|
|
1349
|
+
type: "problem",
|
|
1350
|
+
schema: []
|
|
1351
|
+
},
|
|
1352
|
+
defaultOptions: [],
|
|
1353
|
+
create(context) {
|
|
1354
|
+
return {
|
|
1355
|
+
"Program:exit"() {
|
|
1356
|
+
const source = context.sourceCode.text;
|
|
1357
|
+
for (const comment of context.sourceCode.getAllComments()) {
|
|
1358
|
+
const commentText = source.slice(comment.range[0], comment.range[1]);
|
|
1359
|
+
if (!commentText.startsWith("/**")) {
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
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
|
+
}
|
|
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
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1425
1382
|
const description$a = `directives={} prop value must be an array literal. Documentation: https://webgis.esri.com/references/lumina/jsx#lit-directives`;
|
|
1426
1383
|
plugin.createRule({
|
|
1427
1384
|
name: "no-invalid-directives-prop",
|
|
@@ -1575,28 +1532,20 @@ plugin.createRule({
|
|
|
1575
1532
|
},
|
|
1576
1533
|
defaultOptions: [],
|
|
1577
1534
|
create(context) {
|
|
1578
|
-
|
|
1579
|
-
|
|
1535
|
+
if (!sourceCodeDeclaresComponent(context.sourceCode)) {
|
|
1536
|
+
return {};
|
|
1537
|
+
}
|
|
1538
|
+
let className;
|
|
1580
1539
|
return {
|
|
1581
1540
|
TSModuleDeclaration(node) {
|
|
1582
1541
|
const luminaDeclarationInterface = extractDeclareElementsInterface(node);
|
|
1583
1542
|
if (luminaDeclarationInterface === void 0) {
|
|
1584
1543
|
return;
|
|
1585
1544
|
}
|
|
1586
|
-
luminaDeclarationInterface.
|
|
1587
|
-
if (member.type !== AST_NODE_TYPES.TSPropertySignature || member.computed) {
|
|
1588
|
-
return;
|
|
1589
|
-
}
|
|
1590
|
-
const type = member.typeAnnotation?.typeAnnotation;
|
|
1591
|
-
if (type?.type !== AST_NODE_TYPES.TSTypeReference || type.typeName.type !== AST_NODE_TYPES.Identifier) {
|
|
1592
|
-
return;
|
|
1593
|
-
}
|
|
1594
|
-
const className = type.typeName.name;
|
|
1595
|
-
declaredComponents.add(className);
|
|
1596
|
-
});
|
|
1545
|
+
className = getComponentDeclaration(luminaDeclarationInterface)?.typeAnnotation?.typeAnnotation.typeName.name;
|
|
1597
1546
|
},
|
|
1598
1547
|
ExportNamedDeclaration(node) {
|
|
1599
|
-
if (
|
|
1548
|
+
if (className === void 0) {
|
|
1600
1549
|
return;
|
|
1601
1550
|
}
|
|
1602
1551
|
if (node.exportKind === "type") {
|
|
@@ -1620,7 +1569,7 @@ plugin.createRule({
|
|
|
1620
1569
|
) {
|
|
1621
1570
|
return;
|
|
1622
1571
|
} else if (node.declaration?.type === AST_NODE_TYPES.ClassDeclaration) {
|
|
1623
|
-
const isComponent =
|
|
1572
|
+
const isComponent = node.declaration.id?.name === className;
|
|
1624
1573
|
if (isComponent) {
|
|
1625
1574
|
return;
|
|
1626
1575
|
}
|
|
@@ -1631,7 +1580,7 @@ plugin.createRule({
|
|
|
1631
1580
|
});
|
|
1632
1581
|
},
|
|
1633
1582
|
ExportDefaultDeclaration(node) {
|
|
1634
|
-
if (
|
|
1583
|
+
if (className === void 0) {
|
|
1635
1584
|
return;
|
|
1636
1585
|
}
|
|
1637
1586
|
context.report({
|
|
@@ -1640,7 +1589,7 @@ plugin.createRule({
|
|
|
1640
1589
|
});
|
|
1641
1590
|
},
|
|
1642
1591
|
ExportAllDeclaration(node) {
|
|
1643
|
-
if (
|
|
1592
|
+
if (className === void 0) {
|
|
1644
1593
|
return;
|
|
1645
1594
|
}
|
|
1646
1595
|
if (node.exportKind === "type") {
|
|
@@ -9,6 +9,17 @@ export declare function checkForLuminaJsx(): LuminaJsxCheck & {
|
|
|
9
9
|
};
|
|
10
10
|
export declare function hasDecorator(node: Pick<TSESTree.PropertyDefinitionNonComputedName, "decorators">, decoratorName: string): boolean;
|
|
11
11
|
export declare function extractDeclareElementsInterface(node: TSESTree.TSModuleDeclaration): TSESTree.TSInterfaceDeclaration | undefined;
|
|
12
|
+
export declare function getComponentDeclaration(node: TSESTree.TSInterfaceDeclaration): {
|
|
13
|
+
key: TSESTree.Literal;
|
|
14
|
+
typeAnnotation: {
|
|
15
|
+
typeAnnotation: {
|
|
16
|
+
typeName: TSESTree.Identifier;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
} | undefined;
|
|
20
|
+
export declare const sourceCodeDeclaresComponent: (sourceCode: {
|
|
21
|
+
readonly text: string;
|
|
22
|
+
}) => boolean;
|
|
12
23
|
export declare function isCreateEvent(node: TSESTree.PropertyDefinition): boolean;
|
|
13
24
|
export declare const getProperty: (properties: TSESTree.ObjectLiteralElement[] | undefined, name: string) => TSESTree.Property["value"] | undefined;
|
|
14
25
|
export declare function isGetterWithoutSetter(node: TSESTree.MethodDefinition | TSESTree.PropertyDefinition): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as makeEslintPlugin } from "../../
|
|
1
|
+
import { m as makeEslintPlugin, e as extractDeclareElementsInterface, g as getComponentDeclaration } from "../../estree-IANpebc8.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$
|
|
10
|
+
const description$5 = `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$
|
|
15
|
+
description: description$5,
|
|
16
16
|
defaultLevel: "error"
|
|
17
17
|
},
|
|
18
18
|
messages: {
|
|
19
|
-
noImportOutsideSrc: description$
|
|
19
|
+
noImportOutsideSrc: description$5
|
|
20
20
|
},
|
|
21
21
|
type: "problem",
|
|
22
22
|
schema: []
|
|
@@ -50,16 +50,16 @@ plugin.createRule({
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
|
-
const description$
|
|
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.`;
|
|
54
54
|
plugin.createRule({
|
|
55
55
|
name: "no-touching-jsdoc",
|
|
56
56
|
meta: {
|
|
57
57
|
docs: {
|
|
58
|
-
description: description$
|
|
58
|
+
description: description$4,
|
|
59
59
|
defaultLevel: "warn"
|
|
60
60
|
},
|
|
61
61
|
messages: {
|
|
62
|
-
noTouchingJsDoc: description$
|
|
62
|
+
noTouchingJsDoc: description$4
|
|
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$
|
|
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.`;
|
|
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$
|
|
104
|
+
description: description$3,
|
|
105
105
|
defaultLevel: "warn"
|
|
106
106
|
},
|
|
107
107
|
messages: {
|
|
108
|
-
requireJsInCoreImport: description$
|
|
108
|
+
requireJsInCoreImport: description$3
|
|
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
|
|
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$
|
|
142
|
+
const description$2 = "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$
|
|
148
|
+
description: description$2,
|
|
149
149
|
defaultLevel: "warn"
|
|
150
150
|
},
|
|
151
151
|
messages: {
|
|
152
|
-
avoidDtsFiles: description$
|
|
152
|
+
avoidDtsFiles: description$2
|
|
153
153
|
},
|
|
154
154
|
type: "suggestion",
|
|
155
155
|
schema: []
|
|
@@ -179,12 +179,12 @@ plugin.createRule({
|
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
181
|
});
|
|
182
|
-
const description = `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$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).`;
|
|
183
183
|
plugin.createRule({
|
|
184
184
|
name: "consistent-logging",
|
|
185
185
|
meta: {
|
|
186
186
|
docs: {
|
|
187
|
-
description,
|
|
187
|
+
description: description$1,
|
|
188
188
|
defaultLevel: "off"
|
|
189
189
|
// NOTE: this is turned on conditionally in root eslint config
|
|
190
190
|
},
|
|
@@ -217,6 +217,61 @@ 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`;
|
|
221
|
+
plugin.createRule({
|
|
222
|
+
name: "no-unsafe-hash-links",
|
|
223
|
+
meta: {
|
|
224
|
+
docs: {
|
|
225
|
+
description,
|
|
226
|
+
defaultLevel: "warn"
|
|
227
|
+
},
|
|
228
|
+
messages: {
|
|
229
|
+
error: description
|
|
230
|
+
},
|
|
231
|
+
type: "problem",
|
|
232
|
+
schema: [],
|
|
233
|
+
fixable: "code"
|
|
234
|
+
},
|
|
235
|
+
defaultOptions: [],
|
|
236
|
+
create(context) {
|
|
237
|
+
let declareElementsInterface;
|
|
238
|
+
return {
|
|
239
|
+
"TSModuleDeclaration"(node) {
|
|
240
|
+
declareElementsInterface = extractDeclareElementsInterface(node);
|
|
241
|
+
},
|
|
242
|
+
"Program:exit"() {
|
|
243
|
+
if (declareElementsInterface === void 0 && !context.sourceCode.text.includes("@public") && !context.sourceCode.text.includes("@internal")) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
for (const match of context.sourceCode.text.matchAll(reHashLink)) {
|
|
247
|
+
const fullMatch = match[0];
|
|
248
|
+
const anchor = match[2];
|
|
249
|
+
const replacement = computeReplacement(declareElementsInterface, anchor);
|
|
250
|
+
context.report({
|
|
251
|
+
messageId: "error",
|
|
252
|
+
loc: {
|
|
253
|
+
start: context.sourceCode.getLocFromIndex(match.index),
|
|
254
|
+
end: context.sourceCode.getLocFromIndex(match.index + fullMatch.length)
|
|
255
|
+
},
|
|
256
|
+
fix: replacement === void 0 ? void 0 : (fixer) => fixer.replaceTextRange([match.index, match.index + fullMatch.length], `{@link ${replacement}}`)
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
const reHashLink = /\[([^\]\n]+)\]\(#([^)]+)\)/gu;
|
|
264
|
+
function computeReplacement(declareElementsInterface, anchor) {
|
|
265
|
+
if (declareElementsInterface === void 0) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const declaration = getComponentDeclaration(declareElementsInterface);
|
|
269
|
+
if (declaration === void 0) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const tagName = declaration.key.value;
|
|
273
|
+
return `components/${tagName}#${anchor}`;
|
|
274
|
+
}
|
|
220
275
|
const webgisPlugin = plugin.finalize();
|
|
221
276
|
export {
|
|
222
277
|
webgisPlugin
|
|
@@ -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,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcgis/eslint-config",
|
|
3
|
-
"version": "5.1.0-next.
|
|
4
|
-
"description": "ESLint configuration for
|
|
3
|
+
"version": "5.1.0-next.71",
|
|
4
|
+
"description": "ESLint configuration for WebGIS SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./dist/config/index.js",
|
|
11
|
+
"./ts": "./src/config/index.ts",
|
|
11
12
|
"./application": "./dist/config/applications.js",
|
|
12
13
|
"./extra": "./dist/config/extra.js",
|
|
13
14
|
"./lumina": "./dist/config/lumina.js",
|
|
15
|
+
"./lumina/ts": "./src/config/lumina.ts",
|
|
14
16
|
"./plugins/webgis": "./dist/plugins/webgis/index.js",
|
|
15
17
|
"./plugins/lumina": "./dist/plugins/lumina/index.js",
|
|
18
|
+
"./utils/disable-rules": "./dist/utils/disable-rules.js",
|
|
16
19
|
"./package.json": "./package.json"
|
|
17
20
|
},
|
|
18
21
|
"files": [
|
|
@@ -20,21 +23,21 @@
|
|
|
20
23
|
],
|
|
21
24
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
22
25
|
"dependencies": {
|
|
23
|
-
"@eslint/js": "^
|
|
24
|
-
"@eslint/markdown": "^
|
|
26
|
+
"@eslint/js": "^10.0.1",
|
|
27
|
+
"@eslint/markdown": "^8.0.1",
|
|
25
28
|
"@types/confusing-browser-globals": "^1.0.3",
|
|
26
|
-
"@typescript-eslint/utils": "^8.
|
|
29
|
+
"@typescript-eslint/utils": "^8.58.0",
|
|
27
30
|
"confusing-browser-globals": "^1.0.11",
|
|
28
|
-
"eslint-plugin-package-json": "
|
|
29
|
-
"eslint-plugin-storybook": "^
|
|
31
|
+
"eslint-plugin-package-json": "~0.91.1",
|
|
32
|
+
"eslint-plugin-storybook": "^10.3.4",
|
|
30
33
|
"globals": "^16.5.0",
|
|
31
|
-
"jsonc-eslint-parser": "^
|
|
34
|
+
"jsonc-eslint-parser": "^3.1.0",
|
|
32
35
|
"tslib": "^2.8.1",
|
|
33
|
-
"typescript": "~
|
|
34
|
-
"typescript-eslint": "^8.
|
|
35
|
-
"@arcgis/toolkit": "5.1.0-next.
|
|
36
|
+
"typescript": "~6.0.2",
|
|
37
|
+
"typescript-eslint": "^8.58.0",
|
|
38
|
+
"@arcgis/toolkit": "5.1.0-next.71"
|
|
36
39
|
},
|
|
37
40
|
"peerDependencies": {
|
|
38
|
-
"eslint": "^
|
|
41
|
+
"eslint": "^10.2.0"
|
|
39
42
|
}
|
|
40
43
|
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
-
const version = "5.1.0-next.7";
|
|
3
|
-
const packageJson = {
|
|
4
|
-
version
|
|
5
|
-
};
|
|
6
|
-
function makeEslintPlugin(pluginName, urlCreator) {
|
|
7
|
-
const rules = [];
|
|
8
|
-
const creator = ESLintUtils.RuleCreator(urlCreator);
|
|
9
|
-
return {
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
11
|
-
createRule(rule) {
|
|
12
|
-
const { meta, name, ...rest } = rule;
|
|
13
|
-
const docs = { ...meta.docs, name };
|
|
14
|
-
const ruleModule = creator({ ...rest, meta: { ...meta, docs }, name });
|
|
15
|
-
rules.push(ruleModule);
|
|
16
|
-
return ruleModule;
|
|
17
|
-
},
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
19
|
-
finalize() {
|
|
20
|
-
const config = {
|
|
21
|
-
rules: Object.fromEntries(
|
|
22
|
-
rules.map((rule) => [`${pluginName}/${rule.meta.docs.name}`, rule.meta.docs.defaultLevel])
|
|
23
|
-
)
|
|
24
|
-
};
|
|
25
|
-
const plugin = {
|
|
26
|
-
meta: { name: `@arcgis/eslint-plugin-${pluginName}`, version: packageJson.version },
|
|
27
|
-
configs: {
|
|
28
|
-
recommended: config
|
|
29
|
-
},
|
|
30
|
-
rules: Object.fromEntries(rules.map((rule) => [rule.meta.docs.name, rule]))
|
|
31
|
-
};
|
|
32
|
-
config.plugins = {
|
|
33
|
-
[pluginName]: plugin
|
|
34
|
-
};
|
|
35
|
-
return plugin;
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
export {
|
|
40
|
-
makeEslintPlugin as m
|
|
41
|
-
};
|