@arcgis/eslint-config 5.2.0-next.51 → 5.2.0-next.52
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 +2 -2
- package/dist/config/core.js +621 -0
- package/dist/config/index.js +10 -1
- package/dist/{makePlugin-DwtvWDJv.js → makePlugin-CErhRqFB.js} +1 -1
- package/dist/plugins/core/index.js +10 -3
- package/dist/plugins/lumina/index.js +1 -1
- package/dist/plugins/webgis/index.js +1 -1
- package/dist/utils/disableRules.d.ts +3 -2
- package/dist/utils/disableRules.js +1 -1
- package/package.json +8 -2
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.
|
|
12
|
-
For third party notices, see https://js.arcgis.com/5.
|
|
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.2/LICENSE.txt.
|
|
12
|
+
For third party notices, see https://js.arcgis.com/5.2/third-party-notices.txt.
|
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
import markdown from "@eslint/markdown";
|
|
2
|
+
import jsdocPlugin from "eslint-plugin-jsdoc";
|
|
3
|
+
import perfectionistPlugin from "eslint-plugin-perfectionist";
|
|
4
|
+
import reactJsxPlugin from "eslint-plugin-react-jsx";
|
|
5
|
+
import regexpPlugin from "eslint-plugin-regexp";
|
|
6
|
+
import unicornPlugin from "eslint-plugin-unicorn";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { corePlugin } from "../plugins/core/index.js";
|
|
9
|
+
const noRestrictedSyntax = [
|
|
10
|
+
"error",
|
|
11
|
+
"AccessorProperty",
|
|
12
|
+
"PrivateIdentifier",
|
|
13
|
+
{
|
|
14
|
+
selector: "CallExpression[callee.property.name='concat'][arguments.length=0]",
|
|
15
|
+
message: "Use slice() instead of concat()."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
selector: "CallExpression[callee.property.name='slice'][arguments.length=1] > .arguments[value=0]",
|
|
19
|
+
message: "Use slice() instead of slice(0)."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
selector: "TSAbstractPropertyDefinition[decorators.length>0]",
|
|
23
|
+
message: "Decorators are not supported on abstract properties."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
selector: "TSEnumDeclaration:not([const=true])",
|
|
27
|
+
message: "Don't declare non-const enums. Use `const enum` instead, or an object with `as const`. See https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
selector: "VariableDeclarator > CallExpression > MemberExpression[property.name='getLogger']",
|
|
31
|
+
message: "Get a logger as needed instead of assigning it for future use."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
selector: "TSModuleDeclaration[id.type='Identifier']",
|
|
35
|
+
message: "Use const objects or static classes instead. See https://devtopia.esri.com/WebGIS/arcgis-js-api/discussions/72194"
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
const disabledMarkdownRules = Object.fromEntries(
|
|
39
|
+
Object.keys(markdown.rules).map((ruleName) => [`markdown/${ruleName}`, "off"])
|
|
40
|
+
);
|
|
41
|
+
const eslintConfigCore = [
|
|
42
|
+
{
|
|
43
|
+
files: ["packages/core-packages/**/*.{ts,tsx}"],
|
|
44
|
+
linterOptions: {
|
|
45
|
+
reportUnusedDisableDirectives: "off"
|
|
46
|
+
},
|
|
47
|
+
plugins: {
|
|
48
|
+
core: corePlugin,
|
|
49
|
+
jsdoc: jsdocPlugin,
|
|
50
|
+
regexp: regexpPlugin,
|
|
51
|
+
unicorn: unicornPlugin
|
|
52
|
+
},
|
|
53
|
+
settings: {
|
|
54
|
+
jsdoc: {
|
|
55
|
+
tagNamePreference: {
|
|
56
|
+
// Our tags
|
|
57
|
+
"public": "public",
|
|
58
|
+
"copyDoc": "copyDoc",
|
|
59
|
+
// Flags
|
|
60
|
+
"beta": "beta",
|
|
61
|
+
"experimental": "experimental",
|
|
62
|
+
"readonly": "readonly",
|
|
63
|
+
// Metadata
|
|
64
|
+
"deprecated": "deprecated",
|
|
65
|
+
"default": "default",
|
|
66
|
+
"since": "since",
|
|
67
|
+
"param": "param",
|
|
68
|
+
"returns": "returns",
|
|
69
|
+
"see": "see",
|
|
70
|
+
"esriCompatibilityName": "esriCompatibilityName",
|
|
71
|
+
// Long descriptions
|
|
72
|
+
"example": "example",
|
|
73
|
+
"privateRemarks": "privateRemarks",
|
|
74
|
+
// Legacy replacements
|
|
75
|
+
"const": "readonly",
|
|
76
|
+
"constant": "readonly",
|
|
77
|
+
"defaultvalue": "default",
|
|
78
|
+
"return": "returns",
|
|
79
|
+
// Obsolete tags. Do not use in new code. These are retained for
|
|
80
|
+
// compatibility with existing non-public Core JSDoc.
|
|
81
|
+
"amdalias": "amdalias",
|
|
82
|
+
"autocast": "autocast",
|
|
83
|
+
"noautocast": "noautocast",
|
|
84
|
+
"constructonly": "constructonly",
|
|
85
|
+
"tag constructor": "constructor",
|
|
86
|
+
"deprecatedParameters": "deprecatedParameters",
|
|
87
|
+
"deprecatedProperties": "deprecatedProperties",
|
|
88
|
+
"esmimport": "esmimport",
|
|
89
|
+
"extends": "extends",
|
|
90
|
+
"method": "method",
|
|
91
|
+
"moduletype": "moduletype",
|
|
92
|
+
"ignoreNilOnly": "ignoreNilOnly"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
rules: {
|
|
97
|
+
//#region Temporary Disable monorepo-exclusive rules
|
|
98
|
+
"@typescript-eslint/adjacent-overload-signatures": "off",
|
|
99
|
+
"@typescript-eslint/array-type": "off",
|
|
100
|
+
"@typescript-eslint/await-thenable": "off",
|
|
101
|
+
"@typescript-eslint/consistent-generic-constructors": "off",
|
|
102
|
+
"@typescript-eslint/consistent-indexed-object-style": "off",
|
|
103
|
+
"@typescript-eslint/consistent-type-assertions": "off",
|
|
104
|
+
"@typescript-eslint/consistent-type-exports": "off",
|
|
105
|
+
"@typescript-eslint/dot-notation": "off",
|
|
106
|
+
"@typescript-eslint/max-params": "off",
|
|
107
|
+
"@typescript-eslint/method-signature-style": "off",
|
|
108
|
+
"@typescript-eslint/no-confusing-non-null-assertion": "off",
|
|
109
|
+
"@typescript-eslint/no-deprecated": "off",
|
|
110
|
+
"@typescript-eslint/no-duplicate-type-constituents": "off",
|
|
111
|
+
"@typescript-eslint/no-dynamic-delete": "off",
|
|
112
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
113
|
+
"@typescript-eslint/no-empty-object-type": "off",
|
|
114
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
115
|
+
"@typescript-eslint/no-extra-non-null-assertion": "off",
|
|
116
|
+
"@typescript-eslint/no-extraneous-class": "off",
|
|
117
|
+
"@typescript-eslint/no-implied-eval": "off",
|
|
118
|
+
"@typescript-eslint/no-inferrable-types": "off",
|
|
119
|
+
"@typescript-eslint/no-misused-new": "off",
|
|
120
|
+
"@typescript-eslint/no-misused-spread": "off",
|
|
121
|
+
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "off",
|
|
122
|
+
"@typescript-eslint/no-non-null-asserted-optional-chain": "off",
|
|
123
|
+
"@typescript-eslint/no-redundant-type-constituents": "off",
|
|
124
|
+
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "off",
|
|
125
|
+
"@typescript-eslint/no-unnecessary-condition": "off",
|
|
126
|
+
"@typescript-eslint/no-unnecessary-template-expression": "off",
|
|
127
|
+
"@typescript-eslint/no-unnecessary-type-assertion": "off",
|
|
128
|
+
"@typescript-eslint/no-unnecessary-type-constraint": "off",
|
|
129
|
+
"@typescript-eslint/no-unnecessary-type-conversion": "off",
|
|
130
|
+
"@typescript-eslint/no-unsafe-argument": "off",
|
|
131
|
+
"@typescript-eslint/no-unsafe-assignment": "off",
|
|
132
|
+
"@typescript-eslint/no-unsafe-call": "off",
|
|
133
|
+
"@typescript-eslint/no-unsafe-enum-comparison": "off",
|
|
134
|
+
"@typescript-eslint/no-unsafe-function-type": "off",
|
|
135
|
+
"@typescript-eslint/no-unsafe-member-access": "off",
|
|
136
|
+
"@typescript-eslint/no-useless-empty-export": "off",
|
|
137
|
+
"@typescript-eslint/no-wrapper-object-types": "off",
|
|
138
|
+
"@typescript-eslint/non-nullable-type-assertion-style": "off",
|
|
139
|
+
"@typescript-eslint/only-throw-error": "off",
|
|
140
|
+
"@typescript-eslint/prefer-as-const": "off",
|
|
141
|
+
"@typescript-eslint/prefer-function-type": "off",
|
|
142
|
+
"@typescript-eslint/prefer-promise-reject-errors": "off",
|
|
143
|
+
"@typescript-eslint/prefer-reduce-type-parameter": "off",
|
|
144
|
+
"@typescript-eslint/prefer-return-this-type": "off",
|
|
145
|
+
"@typescript-eslint/promise-function-async": "off",
|
|
146
|
+
"@typescript-eslint/related-getter-setter-pairs": "off",
|
|
147
|
+
"@typescript-eslint/require-array-sort-compare": "off",
|
|
148
|
+
"@typescript-eslint/require-await": "off",
|
|
149
|
+
"@typescript-eslint/restrict-plus-operands": "off",
|
|
150
|
+
"@typescript-eslint/restrict-template-expressions": "off",
|
|
151
|
+
"@typescript-eslint/sort-type-constituents": "off",
|
|
152
|
+
"@typescript-eslint/switch-exhaustiveness-check": "off",
|
|
153
|
+
"@typescript-eslint/triple-slash-reference": "off",
|
|
154
|
+
"@typescript-eslint/unified-signatures": "off",
|
|
155
|
+
"array-callback-return": "off",
|
|
156
|
+
"default-case-last": "off",
|
|
157
|
+
"func-names": "off",
|
|
158
|
+
"func-style": "off",
|
|
159
|
+
"grouped-accessor-pairs": "off",
|
|
160
|
+
"id-denylist": "off",
|
|
161
|
+
"lumina/add-missing-jsx-import": "off",
|
|
162
|
+
"lumina/auto-add-type": "off",
|
|
163
|
+
"lumina/component-placement-rules": "off",
|
|
164
|
+
"lumina/consistent-event-naming": "off",
|
|
165
|
+
"lumina/consistent-nullability": "off",
|
|
166
|
+
"lumina/decorators-context": "off",
|
|
167
|
+
"lumina/explicit-setter-type": "off",
|
|
168
|
+
"lumina/member-ordering": "off",
|
|
169
|
+
"lumina/no-create-element-component": "off",
|
|
170
|
+
"lumina/no-ignore-jsdoc-tag": "off",
|
|
171
|
+
"lumina/no-incorrect-dynamic-tag-name": "off",
|
|
172
|
+
"lumina/no-inline-arrow-in-ref": "off",
|
|
173
|
+
"lumina/no-inline-exposure-jsdoc-tag": "off",
|
|
174
|
+
"lumina/no-invalid-directives-prop": "off",
|
|
175
|
+
"lumina/no-jsdoc-xref-links": "off",
|
|
176
|
+
"lumina/no-jsx-spread": "off",
|
|
177
|
+
"lumina/no-listen-in-connected-callback": "off",
|
|
178
|
+
"lumina/no-non-component-exports": "off",
|
|
179
|
+
"lumina/no-property-name-start-with-on": "off",
|
|
180
|
+
"lumina/no-render-false": "off",
|
|
181
|
+
"lumina/no-unnecessary-assertion-on-event": "off",
|
|
182
|
+
"lumina/no-unnecessary-attribute-name": "off",
|
|
183
|
+
"lumina/no-unnecessary-bind-this": "off",
|
|
184
|
+
"lumina/no-unnecessary-key": "off",
|
|
185
|
+
"lumina/tag-name-rules": "off",
|
|
186
|
+
"no-alert": "off",
|
|
187
|
+
"no-await-in-loop": "off",
|
|
188
|
+
"no-constructor-return": "off",
|
|
189
|
+
"no-extend-native": "off",
|
|
190
|
+
"no-extra-bind": "off",
|
|
191
|
+
"no-loss-of-precision": "off",
|
|
192
|
+
"no-multi-assign": "off",
|
|
193
|
+
"no-object-constructor": "off",
|
|
194
|
+
"no-restricted-syntax": "off",
|
|
195
|
+
"no-return-assign": "off",
|
|
196
|
+
"no-script-url": "off",
|
|
197
|
+
"no-self-compare": "off",
|
|
198
|
+
"no-sequences": "off",
|
|
199
|
+
"no-unneeded-ternary": "off",
|
|
200
|
+
"no-unreachable-loop": "off",
|
|
201
|
+
"no-unsafe-negation": "off",
|
|
202
|
+
"no-useless-call": "off",
|
|
203
|
+
"no-useless-computed-key": "off",
|
|
204
|
+
"no-useless-concat": "off",
|
|
205
|
+
"no-warning-comments": "off",
|
|
206
|
+
"prefer-arrow-callback": "off",
|
|
207
|
+
"prefer-numeric-literals": "off",
|
|
208
|
+
"prefer-object-has-own": "off",
|
|
209
|
+
"prefer-object-spread": "off",
|
|
210
|
+
"prefer-regex-literals": "off",
|
|
211
|
+
"prefer-rest-params": "off",
|
|
212
|
+
"prefer-spread": "off",
|
|
213
|
+
"prefer-template": "off",
|
|
214
|
+
"require-atomic-updates": "off",
|
|
215
|
+
"require-unicode-regexp": "off",
|
|
216
|
+
"strict": "off",
|
|
217
|
+
"symbol-description": "off",
|
|
218
|
+
"unicode-bom": "off",
|
|
219
|
+
"unicorn/number-literal-case": "off",
|
|
220
|
+
"webgis/consistent-logging": "off",
|
|
221
|
+
"webgis/no-dts-files": "off",
|
|
222
|
+
"webgis/no-import-outside-src": "off",
|
|
223
|
+
"webgis/no-touching-jsdoc": "off",
|
|
224
|
+
"webgis/no-unsafe-hash-links": "off",
|
|
225
|
+
"webgis/require-await-for-async-screenshot-assert": "off",
|
|
226
|
+
"webgis/require-js-in-imports": "off",
|
|
227
|
+
"yoda": "off",
|
|
228
|
+
//#endregion
|
|
229
|
+
//#region Temporary enable core-exclusive rules
|
|
230
|
+
"@typescript-eslint/ban-ts-comment": ["error", { "ts-expect-error": false, "ts-nocheck": false }],
|
|
231
|
+
"@typescript-eslint/consistent-type-definitions": ["error", "interface"],
|
|
232
|
+
"@typescript-eslint/explicit-function-return-type": ["error", { allowExpressions: true }],
|
|
233
|
+
"@typescript-eslint/explicit-member-accessibility": ["error", { accessibility: "no-public" }],
|
|
234
|
+
"@typescript-eslint/naming-convention": [
|
|
235
|
+
"error",
|
|
236
|
+
{ selector: ["typeLike"], format: ["PascalCase"] },
|
|
237
|
+
{
|
|
238
|
+
selector: ["function", "classMethod", "classProperty", "typeMethod"],
|
|
239
|
+
format: ["camelCase"],
|
|
240
|
+
leadingUnderscore: "allow"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
selector: ["memberLike", "classProperty"],
|
|
244
|
+
modifiers: ["private"],
|
|
245
|
+
format: ["camelCase"],
|
|
246
|
+
leadingUnderscore: "require"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
selector: ["classProperty"],
|
|
250
|
+
modifiers: ["static"],
|
|
251
|
+
format: ["UPPER_CASE", "PascalCase", "camelCase"],
|
|
252
|
+
leadingUnderscore: "allow"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
selector: ["classProperty"],
|
|
256
|
+
modifiers: ["private", "static"],
|
|
257
|
+
format: ["UPPER_CASE", "PascalCase", "camelCase"],
|
|
258
|
+
leadingUnderscore: "allow"
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
"@typescript-eslint/no-array-constructor": "error",
|
|
262
|
+
"@typescript-eslint/no-import-type-side-effects": "error",
|
|
263
|
+
"@typescript-eslint/no-redeclare": "off",
|
|
264
|
+
// turn on when this doesn't error on mixins
|
|
265
|
+
"@typescript-eslint/no-require-imports": "error",
|
|
266
|
+
"@typescript-eslint/no-restricted-imports": [
|
|
267
|
+
"error",
|
|
268
|
+
{
|
|
269
|
+
paths: [
|
|
270
|
+
{ name: "esri/identity/IdentityManager", message: "Use `esri/kernel.id` or the `authMode` option." },
|
|
271
|
+
{
|
|
272
|
+
name: "esri/layers/support/rasterFunctionUtils",
|
|
273
|
+
message: "Import raster function creators directly instead."
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "esri/TimeExtent",
|
|
277
|
+
message: "Use `esri/time/TimeExtent` instead. See https://devtopia.esri.com/WebGIS/arcgis-js-api/issues/49223."
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
name: "esri/TimeInterval",
|
|
281
|
+
message: "Use `esri/time/TimeInterval` instead. See https://devtopia.esri.com/WebGIS/arcgis-js-api/issues/49223."
|
|
282
|
+
},
|
|
283
|
+
{ name: "esri/rest/geometryService", message: "Import geometry services directly instead" },
|
|
284
|
+
{ name: "esri/rest/geoprocessor", message: "Import geoprocessor exports directly instead" },
|
|
285
|
+
{ name: "esri/rest/locator", message: "Import locator exports directly instead" },
|
|
286
|
+
{ name: "esri/rest/query", message: "use individual files instead" }
|
|
287
|
+
],
|
|
288
|
+
patterns: [
|
|
289
|
+
{
|
|
290
|
+
group: ["@esri/calcite-components/dist/components/*"],
|
|
291
|
+
message: "Pass a dynamic import to `loadCalciteComponents` inside `loadDependencies` instead.",
|
|
292
|
+
allowTypeImports: true
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
],
|
|
297
|
+
"@typescript-eslint/no-unnecessary-parameter-property-assignment": "error",
|
|
298
|
+
"@typescript-eslint/no-unused-expressions": ["error", { allowShortCircuit: true, allowTernary: true }],
|
|
299
|
+
"@typescript-eslint/no-unused-vars": [
|
|
300
|
+
"error",
|
|
301
|
+
{
|
|
302
|
+
args: "all",
|
|
303
|
+
argsIgnorePattern: "^_",
|
|
304
|
+
caughtErrors: "none",
|
|
305
|
+
destructuredArrayIgnorePattern: "^_",
|
|
306
|
+
varsIgnorePattern: "^_|^tsx",
|
|
307
|
+
ignoreRestSiblings: true,
|
|
308
|
+
enableAutofixRemoval: { imports: true }
|
|
309
|
+
}
|
|
310
|
+
],
|
|
311
|
+
"@typescript-eslint/prefer-namespace-keyword": "error",
|
|
312
|
+
"arrow-body-style": "error",
|
|
313
|
+
"core/glsl-whitespace": "error",
|
|
314
|
+
"core/imports-format": "error",
|
|
315
|
+
"core/no-duplicate-import-comments": "error",
|
|
316
|
+
"core/no-empty-jsdoc-todo": "error",
|
|
317
|
+
"core/no-redundant-checked-in-files": "error",
|
|
318
|
+
"core/prefer-relative-imports": "error",
|
|
319
|
+
"core/require-calcite-import": "error",
|
|
320
|
+
"curly": "error",
|
|
321
|
+
"eqeqeq": ["error", "smart"],
|
|
322
|
+
"import-x/no-duplicates": "error",
|
|
323
|
+
"import-x/no-dynamic-require": ["error", { esmodule: true }],
|
|
324
|
+
"import-x/no-restricted-paths": [
|
|
325
|
+
"error",
|
|
326
|
+
{
|
|
327
|
+
// This is temporary. Once most of this config is merged with the
|
|
328
|
+
// root @arcgis/eslint-config, the core-specific rules can be moved
|
|
329
|
+
// into @webgis/monorepo-config
|
|
330
|
+
basePath: join(import.meta.dirname, "../../../../core-packages/core"),
|
|
331
|
+
zones: [
|
|
332
|
+
{
|
|
333
|
+
target: "src",
|
|
334
|
+
from: "src/identity/IdentityManager.ts",
|
|
335
|
+
message: "Use `kernel.id` or the `authMode` request option."
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
target: "src",
|
|
339
|
+
from: "src/layers/support/rasterFunctionUtils.ts",
|
|
340
|
+
message: "Import raster function creators directly instead."
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
target: "src",
|
|
344
|
+
from: "src/rest/geometryService.ts",
|
|
345
|
+
message: "Import the `geometryService` exports directly instead."
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
target: "src",
|
|
349
|
+
from: "src/rest/geoprocessor.ts",
|
|
350
|
+
message: "Import the geoprocessor exports directly instead."
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
target: "src",
|
|
354
|
+
from: "src/rest/locator.ts",
|
|
355
|
+
message: "Import the locator exports directly instead."
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
target: "src",
|
|
359
|
+
from: "src/rest/query.ts",
|
|
360
|
+
message: "Import the query exports directly instead"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
target: "src",
|
|
364
|
+
from: "tests",
|
|
365
|
+
message: "Modules in /src should not import modules in /tests."
|
|
366
|
+
}
|
|
367
|
+
]
|
|
368
|
+
}
|
|
369
|
+
],
|
|
370
|
+
"import-x/no-useless-path-segments": "error",
|
|
371
|
+
"jsdoc/check-tag-names": [
|
|
372
|
+
"error",
|
|
373
|
+
{ definedTags: ["tstype", "ignoreNilOnly", "noautocast", "collectionItemType"] }
|
|
374
|
+
],
|
|
375
|
+
"jsdoc/check-types": "error",
|
|
376
|
+
// Ensure @readonly and @public is used without any content
|
|
377
|
+
"jsdoc/empty-tags": "error",
|
|
378
|
+
// Avoid /**\n ** something */
|
|
379
|
+
"jsdoc/no-multi-asterisks": ["error", { allowWhitespace: true }],
|
|
380
|
+
// Enforce each JSDoc line starts with *
|
|
381
|
+
"jsdoc/require-asterisk-prefix": "error",
|
|
382
|
+
// Enforce @param has param name
|
|
383
|
+
"jsdoc/require-param-name": "error",
|
|
384
|
+
"no-array-constructor": "off",
|
|
385
|
+
"no-async-promise-executor": "error",
|
|
386
|
+
"no-caller": "error",
|
|
387
|
+
"no-case-declarations": "error",
|
|
388
|
+
"no-cond-assign": "error",
|
|
389
|
+
"no-constant-binary-expression": "error",
|
|
390
|
+
"no-control-regex": "error",
|
|
391
|
+
"no-debugger": "error",
|
|
392
|
+
"no-duplicate-case": "error",
|
|
393
|
+
"no-else-return": "error",
|
|
394
|
+
"no-eval": "error",
|
|
395
|
+
"no-fallthrough": ["error", { reportUnusedFallthroughComment: false }],
|
|
396
|
+
"no-implied-eval": "error",
|
|
397
|
+
"no-inner-declarations": "error",
|
|
398
|
+
"no-labels": ["error", { allowLoop: true, allowSwitch: true }],
|
|
399
|
+
"no-new-func": "error",
|
|
400
|
+
"no-new-wrappers": "error",
|
|
401
|
+
"no-redeclare": "off",
|
|
402
|
+
"no-regex-spaces": "error",
|
|
403
|
+
"no-restricted-globals": ["error", "event", "name", "origin"],
|
|
404
|
+
"no-shadow-restricted-names": "error",
|
|
405
|
+
"no-throw-literal": "error",
|
|
406
|
+
"no-unsafe-finally": "error",
|
|
407
|
+
"no-unsafe-optional-chaining": "error",
|
|
408
|
+
"no-unused-expressions": "off",
|
|
409
|
+
"no-unused-vars": "off",
|
|
410
|
+
"no-useless-escape": "error",
|
|
411
|
+
"no-useless-rename": "error",
|
|
412
|
+
"no-var": "error",
|
|
413
|
+
"object-shorthand": "error",
|
|
414
|
+
"one-var": ["error", { initialized: "never" }],
|
|
415
|
+
"prefer-const": ["error", { destructuring: "all" }],
|
|
416
|
+
"prefer-exponentiation-operator": "error",
|
|
417
|
+
"radix": "error",
|
|
418
|
+
"regexp/control-character-escape": "error",
|
|
419
|
+
"regexp/no-dupe-characters-character-class": "error",
|
|
420
|
+
"regexp/no-dupe-disjunctions": "error",
|
|
421
|
+
"regexp/no-empty-alternative": "error",
|
|
422
|
+
"regexp/no-empty-capturing-group": "error",
|
|
423
|
+
"regexp/no-empty-character-class": "error",
|
|
424
|
+
"regexp/no-empty-group": "error",
|
|
425
|
+
"regexp/no-empty-lookarounds-assertion": "error",
|
|
426
|
+
"regexp/no-escape-backspace": "error",
|
|
427
|
+
"regexp/no-extra-lookaround-assertions": "error",
|
|
428
|
+
"regexp/no-invalid-regexp": "error",
|
|
429
|
+
"regexp/no-invisible-character": "error",
|
|
430
|
+
"regexp/no-lazy-ends": "error",
|
|
431
|
+
"regexp/no-misleading-unicode-character": "error",
|
|
432
|
+
"regexp/no-missing-g-flag": "error",
|
|
433
|
+
"regexp/no-obscure-range": "error",
|
|
434
|
+
"regexp/no-optional-assertion": "error",
|
|
435
|
+
"regexp/no-trivially-nested-assertion": "error",
|
|
436
|
+
"regexp/no-trivially-nested-quantifier": "error",
|
|
437
|
+
"regexp/no-useless-assertions": "error",
|
|
438
|
+
"regexp/no-useless-backreference": "error",
|
|
439
|
+
"regexp/no-useless-character-class": "error",
|
|
440
|
+
"regexp/no-useless-dollar-replacements": "error",
|
|
441
|
+
"regexp/no-useless-escape": "error",
|
|
442
|
+
// adds auto-fix and additional checks compared to `no-useless-escape`
|
|
443
|
+
"regexp/no-useless-lazy": "error",
|
|
444
|
+
"regexp/no-useless-quantifier": "error",
|
|
445
|
+
"regexp/no-useless-range": "error",
|
|
446
|
+
"regexp/no-useless-set-operand": "error",
|
|
447
|
+
"regexp/no-useless-string-literal": "error",
|
|
448
|
+
"regexp/no-useless-two-nums-quantifier": "error",
|
|
449
|
+
"regexp/optimal-quantifier-concatenation": "error",
|
|
450
|
+
"regexp/prefer-predefined-assertion": "error",
|
|
451
|
+
"regexp/prefer-range": "error",
|
|
452
|
+
"regexp/prefer-set-operation": "error",
|
|
453
|
+
"unicorn/consistent-date-clone": "error",
|
|
454
|
+
"unicorn/consistent-empty-array-spread": "error",
|
|
455
|
+
"unicorn/no-abusive-eslint-disable": "error",
|
|
456
|
+
"unicorn/no-accessor-recursion": "error",
|
|
457
|
+
"unicorn/no-await-in-promise-methods": "error",
|
|
458
|
+
"unicorn/no-instanceof-builtins": "error",
|
|
459
|
+
"unicorn/no-invalid-remove-event-listener": "error",
|
|
460
|
+
"unicorn/no-negation-in-equality-check": "error",
|
|
461
|
+
"unicorn/no-single-promise-in-promise-methods": "error",
|
|
462
|
+
"unicorn/no-typeof-undefined": "error",
|
|
463
|
+
"unicorn/no-unnecessary-array-flat-depth": "error",
|
|
464
|
+
"unicorn/no-unnecessary-array-splice-count": "error",
|
|
465
|
+
"unicorn/no-unnecessary-slice-end": "error",
|
|
466
|
+
"unicorn/no-useless-fallback-in-spread": "error",
|
|
467
|
+
"unicorn/no-useless-length-check": "error",
|
|
468
|
+
"unicorn/no-useless-promise-resolve-reject": "error",
|
|
469
|
+
"unicorn/no-useless-spread": "error",
|
|
470
|
+
"unicorn/no-useless-undefined": ["error", { checkArguments: false, checkArrowFunctionBody: false }],
|
|
471
|
+
"unicorn/prefer-array-find": "error",
|
|
472
|
+
"unicorn/prefer-array-flat": "error",
|
|
473
|
+
"unicorn/prefer-array-flat-map": "error",
|
|
474
|
+
"unicorn/prefer-array-index-of": "error",
|
|
475
|
+
"unicorn/prefer-array-some": "error",
|
|
476
|
+
"unicorn/prefer-blob-reading-methods": "error",
|
|
477
|
+
"unicorn/prefer-date-now": "error",
|
|
478
|
+
"unicorn/prefer-default-parameters": "error",
|
|
479
|
+
"unicorn/prefer-includes": "error",
|
|
480
|
+
"unicorn/prefer-logical-operator-over-ternary": "error",
|
|
481
|
+
"unicorn/prefer-negative-index": "error",
|
|
482
|
+
"unicorn/prefer-node-protocol": "error",
|
|
483
|
+
"unicorn/prefer-regexp-test": "error",
|
|
484
|
+
"unicorn/prefer-set-has": "error",
|
|
485
|
+
"unicorn/prefer-set-size": "error",
|
|
486
|
+
"unicorn/prefer-string-replace-all": "error",
|
|
487
|
+
"unicorn/prefer-string-slice": "error",
|
|
488
|
+
"unicorn/prefer-string-starts-ends-with": "error",
|
|
489
|
+
"unicorn/throw-new-error": "error",
|
|
490
|
+
"webgis/consistent-constructor-arguments": "error",
|
|
491
|
+
"webgis/consistent-mixin-syntax": "error",
|
|
492
|
+
"webgis/no-empty-catch": "error",
|
|
493
|
+
"webgis/no-kebab-case-props": "error",
|
|
494
|
+
"webgis/require-button-type": "error"
|
|
495
|
+
//#endregion
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
files: ["packages/core-packages/**/*.md"],
|
|
500
|
+
rules: disabledMarkdownRules
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
files: ["packages/core-packages/core/package.json"],
|
|
504
|
+
rules: {
|
|
505
|
+
// @typescript/native-preview temporarily uses the `beta` tag rather than a semver range.
|
|
506
|
+
"package-json/valid-devDependencies": "off"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
files: ["packages/core-packages/**/*.d.ts"],
|
|
511
|
+
rules: {
|
|
512
|
+
"@typescript-eslint/naming-convention": "off"
|
|
513
|
+
// we can't enforce names in libraries
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
// Type-aware rules
|
|
518
|
+
files: ["packages/core-packages/**/*.{ts,tsx}"],
|
|
519
|
+
// This folder runs in node, so uses a separate tsconfig.json
|
|
520
|
+
ignores: ["packages/core-packages/core/tests/support/vitest/node/**/*.ts"],
|
|
521
|
+
rules: {
|
|
522
|
+
// Disabled until https://github.com/typescript-eslint/typescript-eslint/pull/11267 is available.
|
|
523
|
+
"@typescript-eslint/await-thenable": "off",
|
|
524
|
+
"@typescript-eslint/no-array-delete": "error",
|
|
525
|
+
"@typescript-eslint/no-floating-promises": "error",
|
|
526
|
+
"@typescript-eslint/no-for-in-array": "error",
|
|
527
|
+
"@typescript-eslint/no-meaningless-void-operator": "error",
|
|
528
|
+
"@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
|
|
529
|
+
"@typescript-eslint/no-unsafe-unary-minus": "error",
|
|
530
|
+
"@typescript-eslint/prefer-find": "error",
|
|
531
|
+
"@typescript-eslint/prefer-includes": "error",
|
|
532
|
+
"@typescript-eslint/prefer-optional-chain": ["error", { requireNullish: true }],
|
|
533
|
+
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
|
534
|
+
"@typescript-eslint/return-await": ["error", "error-handling-correctness-only"]
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
files: ["packages/core-packages/**/*.tsx"],
|
|
539
|
+
plugins: {
|
|
540
|
+
"perfectionist": perfectionistPlugin,
|
|
541
|
+
"react-jsx": reactJsxPlugin
|
|
542
|
+
},
|
|
543
|
+
rules: {
|
|
544
|
+
"perfectionist/sort-jsx-props": [
|
|
545
|
+
"error",
|
|
546
|
+
{
|
|
547
|
+
groups: ["unknown", "callback"],
|
|
548
|
+
customGroups: [{ groupName: "callback", elementNamePattern: "^on.+" }]
|
|
549
|
+
}
|
|
550
|
+
],
|
|
551
|
+
"react-jsx/no-children-prop": "error",
|
|
552
|
+
"react-jsx/no-comment-textnodes": "error",
|
|
553
|
+
"react-jsx/no-useless-fragment": "error"
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
files: ["packages/core-packages/core/src/**/*.{ts,tsx}"],
|
|
558
|
+
rules: {
|
|
559
|
+
"core/no-invalid-declared-class": "error"
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
files: ["packages/core-packages/core/src/**/*.{ts,tsx}"],
|
|
564
|
+
ignores: ["packages/core-packages/core/src/**/*.d.ts"],
|
|
565
|
+
rules: {
|
|
566
|
+
"no-restricted-syntax": noRestrictedSyntax
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
files: ["packages/core-packages/core/src/**/*.{ts,tsx}"],
|
|
571
|
+
ignores: ["packages/core-packages/core/src/arcade/**", "packages/core-packages/core/src/widgets/**"],
|
|
572
|
+
rules: {
|
|
573
|
+
"webgis/no-instanceof": "error"
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
files: ["packages/core-packages/core/tests/**/*.{ts,tsx}"],
|
|
578
|
+
rules: {
|
|
579
|
+
"webgis/no-instanceof": "off",
|
|
580
|
+
"@typescript-eslint/no-restricted-imports": [
|
|
581
|
+
"error",
|
|
582
|
+
{
|
|
583
|
+
patterns: [
|
|
584
|
+
{
|
|
585
|
+
group: ["*.spec", "*.spec.*", "**/*.spec", "**/*.spec.*"],
|
|
586
|
+
message: "Do not import test suites (.spec) from other tests. Move shared helpers to tests/support (use the test-support/* alias)."
|
|
587
|
+
}
|
|
588
|
+
]
|
|
589
|
+
}
|
|
590
|
+
],
|
|
591
|
+
"core/spec-suite-filename": "error",
|
|
592
|
+
"no-restricted-syntax": [
|
|
593
|
+
...noRestrictedSyntax,
|
|
594
|
+
{
|
|
595
|
+
message: "The { only: true } test option may be used during local testing, but can not be committed.",
|
|
596
|
+
selector: "CallExpression ObjectExpression Property[key.name='only'][value.value='true']"
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
message: "test.only may be used during local testing, but can not be committed.",
|
|
600
|
+
selector: "CallExpression[callee.type='MemberExpression'][callee.object.name='test'] > MemberExpression.callee > Identifier.property[name='only']"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
message: "The { repeatUntilFailure: true } test option may be used during local testing, but can not be committed.",
|
|
604
|
+
selector: "CallExpression ObjectExpression Property[key.name='repeatUntilFailure'][value.value='true']"
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
message: "test.repeatUntilFailure may be used during local testing, but can not be committed.",
|
|
608
|
+
selector: "CallExpression[callee.type='MemberExpression'][callee.object.name='test'] > MemberExpression.callee > Identifier.property[name='repeatUntilFailure']"
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
selector: "CallExpression MemberExpression[object.name='has'][property.name='add']",
|
|
612
|
+
message: "Avoid adding has flags manually. Instead use the suite/test-level options to set has flags."
|
|
613
|
+
}
|
|
614
|
+
],
|
|
615
|
+
"webgis/require-await-for-async-screenshot-assert": "error"
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
];
|
|
619
|
+
export {
|
|
620
|
+
eslintConfigCore as default
|
|
621
|
+
};
|
package/dist/config/index.js
CHANGED
|
@@ -7,9 +7,12 @@ import { globalIgnores } from "eslint/config";
|
|
|
7
7
|
import markdown from "@eslint/markdown";
|
|
8
8
|
import packageJson from "eslint-plugin-package-json";
|
|
9
9
|
import { importX } from "eslint-plugin-import-x";
|
|
10
|
+
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
|
|
10
11
|
const packageJsonSortableCollections = packageJson.rules["sort-collections"].meta.defaultOptions[0].filter(
|
|
11
12
|
(collection) => !["scripts", "exports"].includes(collection)
|
|
12
13
|
) ?? [];
|
|
14
|
+
const importXTypeScriptSettings = { ...importX.flatConfigs.typescript.settings };
|
|
15
|
+
delete importXTypeScriptSettings["import-x/resolver"];
|
|
13
16
|
const config = [
|
|
14
17
|
globalIgnores(["**/www", "**/dist", "**/assets", "**/coverage", "**/.docs"]),
|
|
15
18
|
{
|
|
@@ -24,7 +27,13 @@ const config = [
|
|
|
24
27
|
...webgisPlugin.configs.recommended,
|
|
25
28
|
files: ["**/*.ts", "**/*.tsx"]
|
|
26
29
|
},
|
|
27
|
-
|
|
30
|
+
{
|
|
31
|
+
...importX.flatConfigs.typescript,
|
|
32
|
+
settings: {
|
|
33
|
+
...importXTypeScriptSettings,
|
|
34
|
+
"import-x/resolver-next": [createTypeScriptImportResolver()]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
28
37
|
{
|
|
29
38
|
files: ["**/*.ts", "**/*.tsx"],
|
|
30
39
|
linterOptions: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as makeEslintPlugin } from "../../makePlugin-
|
|
1
|
+
import { m as makeEslintPlugin } from "../../makePlugin-CErhRqFB.js";
|
|
2
2
|
import { AST_NODE_TYPES, AST_TOKEN_TYPES } from "@typescript-eslint/utils";
|
|
3
3
|
import { generateDifferences, showInvisibles } from "prettier-linter-helpers";
|
|
4
4
|
import path, { relative, win32, posix, normalize } from "path";
|
|
@@ -589,8 +589,15 @@ plugin.createRule({
|
|
|
589
589
|
}
|
|
590
590
|
});
|
|
591
591
|
function pathRoot(p) {
|
|
592
|
-
const
|
|
593
|
-
|
|
592
|
+
const pathImplementation = win32.isAbsolute(p) && !posix.isAbsolute(p) ? win32 : path;
|
|
593
|
+
let root = p;
|
|
594
|
+
while (true) {
|
|
595
|
+
const parent = pathImplementation.dirname(root);
|
|
596
|
+
if (parent === "." || parent === root) {
|
|
597
|
+
return root;
|
|
598
|
+
}
|
|
599
|
+
root = parent;
|
|
600
|
+
}
|
|
594
601
|
}
|
|
595
602
|
function verifyRelativeImport(context, node, absImportPath, basePath, importRoot) {
|
|
596
603
|
const modulePath = node.value;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as makeEslintPlugin } from "../../makePlugin-
|
|
1
|
+
import { m as makeEslintPlugin } from "../../makePlugin-CErhRqFB.js";
|
|
2
2
|
import { AST_NODE_TYPES, ESLintUtils, AST_TOKEN_TYPES } from "@typescript-eslint/utils";
|
|
3
3
|
import { 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-CDc-die8.js";
|
|
4
4
|
import ts from "typescript";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { m as makeEslintPlugin } from "../../makePlugin-
|
|
1
|
+
import { m as makeEslintPlugin } from "../../makePlugin-CErhRqFB.js";
|
|
2
2
|
import { TSESTree, AST_TOKEN_TYPES, AST_NODE_TYPES, TSESLint } from "@typescript-eslint/utils";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { resolve } from "path/posix";
|
|
@@ -4,7 +4,8 @@ import type { TSESLint } from "@typescript-eslint/utils";
|
|
|
4
4
|
* A utility for temporary running ESLint with only specific rules enabled.
|
|
5
5
|
*
|
|
6
6
|
* @param config - flat config
|
|
7
|
-
* @param enabledRules - exceptions
|
|
7
|
+
* @param enabledRules - exceptions. Set a rule to `true` to preserve existing
|
|
8
|
+
* configuration
|
|
8
9
|
* @param disableTypeChecking - make ESLint much faster by temporary disabling
|
|
9
10
|
* type-aware linting.
|
|
10
11
|
* @returns a new flat config array where every rule is disabled,
|
|
@@ -21,4 +22,4 @@ import type { TSESLint } from "@typescript-eslint/utils";
|
|
|
21
22
|
* true,
|
|
22
23
|
* );
|
|
23
24
|
*/
|
|
24
|
-
export function disableAllRulesExcept(config: TSESLint.FlatConfig.ConfigArray, enabledRules: Record<string, TSESLint.FlatConfig.
|
|
25
|
+
export function disableAllRulesExcept(config: TSESLint.FlatConfig.ConfigArray, enabledRules: Partial<Record<string, TSESLint.FlatConfig.RuleEntry | true>>, disableTypeChecking: boolean): TSESLint.FlatConfig.ConfigArray;
|
|
@@ -10,7 +10,7 @@ function applyRulesAndOptions(entry, enabledRules, disableTypeChecking) {
|
|
|
10
10
|
rules: Object.fromEntries(
|
|
11
11
|
Object.keys(entry.rules).map((ruleName) => {
|
|
12
12
|
const override = enabledRules[ruleName];
|
|
13
|
-
return [ruleName, override ?? "off"];
|
|
13
|
+
return [ruleName, override === true ? entry.rules[ruleName] : override ?? "off"];
|
|
14
14
|
})
|
|
15
15
|
)
|
|
16
16
|
} : entry;
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcgis/eslint-config",
|
|
3
|
-
"version": "5.2.0-next.
|
|
3
|
+
"version": "5.2.0-next.52",
|
|
4
4
|
"description": "ESLint configuration for WebGIS SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./dist/config/index.js",
|
|
8
8
|
"./application": "./dist/config/applications.js",
|
|
9
|
+
"./core": "./dist/config/core.js",
|
|
9
10
|
"./extra": "./dist/config/extra.js",
|
|
10
11
|
"./lumina": "./dist/config/lumina.js",
|
|
11
12
|
"./plugins/core": "./dist/plugins/core/index.js",
|
|
@@ -27,15 +28,20 @@
|
|
|
27
28
|
"confusing-browser-globals": "^1.0.11",
|
|
28
29
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
29
30
|
"eslint-plugin-import-x": "^4.17.1",
|
|
31
|
+
"eslint-plugin-jsdoc": "~63.0.13",
|
|
30
32
|
"eslint-plugin-package-json": "~0.91.1",
|
|
33
|
+
"eslint-plugin-perfectionist": "~5.10.0",
|
|
34
|
+
"eslint-plugin-react-jsx": "~5.11.2",
|
|
35
|
+
"eslint-plugin-regexp": "~3.1.1",
|
|
31
36
|
"eslint-plugin-storybook": "^10.3.4",
|
|
37
|
+
"eslint-plugin-unicorn": "~64.0.0",
|
|
32
38
|
"globals": "^16.5.0",
|
|
33
39
|
"jsonc-eslint-parser": "^3.1.0",
|
|
34
40
|
"prettier-linter-helpers": "^1.0.1",
|
|
35
41
|
"tslib": "^2.8.1",
|
|
36
42
|
"typescript": "~6.0.3",
|
|
37
43
|
"typescript-eslint": "^8.63.0",
|
|
38
|
-
"@arcgis/toolkit": "5.2.0-next.
|
|
44
|
+
"@arcgis/toolkit": "5.2.0-next.52"
|
|
39
45
|
},
|
|
40
46
|
"peerDependencies": {
|
|
41
47
|
"eslint": "^10.6.0"
|