@arcgis/eslint-config 4.33.0-next.15 → 4.33.0-next.151
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/applications.d.ts +5 -0
- package/dist/config/applications.js +40 -0
- package/dist/config/extra.js +2 -3
- package/dist/config/index.d.ts +2 -19
- package/dist/config/index.js +52 -123
- package/dist/config/lumina.d.ts +1 -5
- package/dist/config/lumina.js +17 -20
- package/dist/config/storybook.d.ts +1 -1
- package/dist/makePlugin-DjfiqX_o.js +38 -0
- package/dist/plugins/lumina/index.d.ts +1 -2
- package/dist/plugins/lumina/index.js +2242 -5
- package/dist/plugins/lumina/plugin.d.ts +8 -0
- package/dist/plugins/lumina/rules/add-missing-jsx-import.d.ts +2 -1
- package/dist/plugins/lumina/rules/auto-add-type.d.ts +3 -2
- package/dist/plugins/lumina/rules/ban-events.d.ts +6 -0
- package/dist/plugins/lumina/rules/component-placement-rules.d.ts +2 -1
- package/dist/plugins/lumina/rules/consistent-event-naming.d.ts +2 -2
- package/dist/plugins/lumina/rules/consistent-nullability.d.ts +2 -0
- package/dist/plugins/lumina/rules/decorators-context.d.ts +2 -1
- package/dist/plugins/lumina/rules/explicit-setter-type.d.ts +19 -0
- package/dist/plugins/lumina/rules/member-ordering/build.d.ts +3 -3
- package/dist/plugins/lumina/rules/member-ordering/comments.d.ts +2 -2
- package/dist/plugins/lumina/rules/member-ordering/config.d.ts +1 -1
- package/dist/plugins/lumina/rules/member-ordering/normalize.d.ts +2 -2
- package/dist/plugins/lumina/rules/member-ordering.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-create-element-component.d.ts +2 -0
- package/dist/plugins/lumina/rules/no-ignore-jsdoc-tag.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-incorrect-dynamic-tag-name.d.ts +3 -2
- package/dist/plugins/lumina/rules/no-inline-arrow-in-ref.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-invalid-directives-prop.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-jsx-spread.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-listen-in-connected-callback.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-non-component-exports.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-property-name-start-with-on.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-render-false.d.ts +3 -2
- package/dist/plugins/lumina/rules/no-unnecessary-assertion-on-event.d.ts +3 -0
- package/dist/plugins/lumina/rules/no-unnecessary-attribute-name.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-unnecessary-bind-this.d.ts +2 -1
- package/dist/plugins/lumina/rules/no-unnecessary-key.d.ts +2 -1
- package/dist/plugins/lumina/rules/tag-name-rules.d.ts +2 -2
- package/dist/plugins/lumina/utils/checker.d.ts +3 -1
- package/dist/plugins/lumina/utils/estree.d.ts +2 -1
- package/dist/plugins/lumina/utils/tags.d.ts +14 -0
- package/dist/plugins/utils/makePlugin.d.ts +12 -13
- package/dist/plugins/webgis/index.d.ts +1 -2
- package/dist/plugins/webgis/index.js +180 -5
- package/dist/plugins/webgis/plugin.d.ts +8 -0
- package/dist/plugins/webgis/rules/no-dts-files.d.ts +2 -0
- package/dist/plugins/webgis/rules/no-import-outside-src.d.ts +2 -1
- package/dist/plugins/webgis/rules/no-touching-jsdoc.d.ts +2 -1
- package/dist/plugins/webgis/rules/require-js-in-imports.d.ts +2 -0
- package/package.json +9 -10
- package/dist/chunk-FZOJA343.js +0 -26
- package/dist/chunk-TFRPLMXN.js +0 -160
- package/dist/chunk-UTXDHVIY.js +0 -1975
- package/dist/plugins/lumina/rules/add-missing-jsx-import.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/auto-add-type.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/component-placement-rules.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/consistent-event-naming.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/decorators-context.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/member-ordering.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-ignore-jsdoc-tag.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-incorrect-dynamic-tag-name.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-inline-arrow-in-ref.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-invalid-directives-prop.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-jsx-spread.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-listen-in-connected-callback.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-non-component-exports.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-property-name-start-with-on.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-render-false.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-unnecessary-attribute-name.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-unnecessary-bind-this.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/no-unnecessary-key.test.d.ts +0 -1
- package/dist/plugins/lumina/rules/tag-name-rules.spec.d.ts +0 -1
- package/dist/plugins/lumina/utils/creator.d.ts +0 -3
- package/dist/plugins/utils/tests.d.ts +0 -26
- package/dist/plugins/webgis/rules/no-import-outside-src.test.d.ts +0 -1
- package/dist/plugins/webgis/rules/no-touching-jsdoc.test.d.ts +0 -1
- package/dist/plugins/webgis/rules/require-js-in-core-import.d.ts +0 -1
- package/dist/plugins/webgis/rules/require-js-in-core-import.test.d.ts +0 -1
- package/dist/plugins/webgis/utils/creator.d.ts +0 -3
package/dist/chunk-UTXDHVIY.js
DELETED
|
@@ -1,1975 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
makeEslintPlugin
|
|
3
|
-
} from "./chunk-FZOJA343.js";
|
|
4
|
-
|
|
5
|
-
// src/plugins/lumina/rules/add-missing-jsx-import.ts
|
|
6
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/utils";
|
|
7
|
-
|
|
8
|
-
// src/plugins/lumina/utils/creator.ts
|
|
9
|
-
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
10
|
-
var createRule = ESLintUtils.RuleCreator(
|
|
11
|
-
(rule) => `https://devtopia.esri.com/WebGIS/arcgis-web-components/tree/main/packages/support-packages/eslint-config/src/plugins/lumina/rules/${rule}.ts`
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
// src/plugins/lumina/utils/estree.ts
|
|
15
|
-
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
16
|
-
var unwrapExpression = (expression) => expression.type === AST_NODE_TYPES.TSAsExpression || expression.type === AST_NODE_TYPES.TSNonNullExpression || expression.type === AST_NODE_TYPES.TSSatisfiesExpression ? unwrapExpression(expression.expression) : expression;
|
|
17
|
-
var luminaEntrypointName = "@arcgis/lumina";
|
|
18
|
-
var luminaJsxExportName = "h";
|
|
19
|
-
function checkForLuminaJsx() {
|
|
20
|
-
const ImportDeclaration = (node) => {
|
|
21
|
-
if (node.source.value !== luminaEntrypointName) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
for (const specifier of node.specifiers) {
|
|
25
|
-
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)) {
|
|
26
|
-
withProperty.isLuminaJsx = true;
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
const withProperty = ImportDeclaration;
|
|
32
|
-
return withProperty;
|
|
33
|
-
}
|
|
34
|
-
function hasDecorator(node, decoratorName) {
|
|
35
|
-
return node.decorators.some(
|
|
36
|
-
(decorator) => decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === decoratorName
|
|
37
|
-
) ?? false;
|
|
38
|
-
}
|
|
39
|
-
function extractDeclareElementsInterface(node) {
|
|
40
|
-
return node.kind === "global" ? node.body.body.find(
|
|
41
|
-
(node2) => node2.type === AST_NODE_TYPES.TSInterfaceDeclaration && node2.id.name === "DeclareElements"
|
|
42
|
-
) : void 0;
|
|
43
|
-
}
|
|
44
|
-
function isCreateEvent(node) {
|
|
45
|
-
return node.value?.type === AST_NODE_TYPES.CallExpression && node.value.callee.type === AST_NODE_TYPES.Identifier && node.value.callee.name === "createEvent" && !node.static;
|
|
46
|
-
}
|
|
47
|
-
var getProperty = (properties, name) => properties?.find(
|
|
48
|
-
(option) => option.type === AST_NODE_TYPES.Property && option.key.type === AST_NODE_TYPES.Identifier && option.key.name === name
|
|
49
|
-
)?.value;
|
|
50
|
-
function isGetterWithoutSetter(node) {
|
|
51
|
-
const isGetter = node.type === AST_NODE_TYPES.MethodDefinition && node.kind === "get";
|
|
52
|
-
if (!isGetter) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
const index = node.parent.body.indexOf(node);
|
|
56
|
-
const previousNode = node.parent.body.at(index - 1);
|
|
57
|
-
const nextNode = node.parent.body.at(index + 1);
|
|
58
|
-
const name = getName(node);
|
|
59
|
-
if (name === void 0) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
const previousIsSetter = previousNode?.type === AST_NODE_TYPES.MethodDefinition && previousNode.kind === "set" && getName(previousNode) === name;
|
|
63
|
-
if (previousIsSetter) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
const nextIsSetter = nextNode?.type === AST_NODE_TYPES.MethodDefinition && nextNode.kind === "set" && getName(nextNode) === name;
|
|
67
|
-
return !nextIsSetter;
|
|
68
|
-
}
|
|
69
|
-
function getName(node) {
|
|
70
|
-
if (node.key.type === AST_NODE_TYPES.Identifier) {
|
|
71
|
-
return node.key.name;
|
|
72
|
-
} else if (node.key.type === AST_NODE_TYPES.Literal && typeof node.key.value === "string") {
|
|
73
|
-
return node.key.value;
|
|
74
|
-
} else {
|
|
75
|
-
return void 0;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function parsePropertyDecorator(decorator) {
|
|
79
|
-
const isPropertyDecorator = decorator.expression.type === AST_NODE_TYPES.CallExpression && decorator.expression.callee.type === AST_NODE_TYPES.Identifier && decorator.expression.callee.name === "property";
|
|
80
|
-
if (!isPropertyDecorator) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const callExpression = decorator?.expression.type === AST_NODE_TYPES.CallExpression ? decorator.expression : void 0;
|
|
84
|
-
if (callExpression === void 0) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const options = callExpression.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression ? callExpression.arguments[0] : void 0;
|
|
88
|
-
const properties = options?.properties;
|
|
89
|
-
return {
|
|
90
|
-
callExpression,
|
|
91
|
-
options,
|
|
92
|
-
properties
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function isBindThisCallee(callee) {
|
|
96
|
-
return callee.type === AST_NODE_TYPES.MemberExpression && // expression.identifier(this)
|
|
97
|
-
callee.property.type === AST_NODE_TYPES.Identifier && // expression.bind(this)
|
|
98
|
-
callee.property.name === "bind" && // expression.expression.bind(this)
|
|
99
|
-
callee.object.type === AST_NODE_TYPES.MemberExpression && // expression.identifier.bind(this)
|
|
100
|
-
callee.object.property.type === AST_NODE_TYPES.Identifier && // this.identifier.bind(this)
|
|
101
|
-
callee.object.object.type === AST_NODE_TYPES.ThisExpression;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// src/plugins/lumina/rules/add-missing-jsx-import.ts
|
|
105
|
-
var importDeclaration = `import { ${luminaJsxExportName} } from "${luminaEntrypointName}";`;
|
|
106
|
-
var description = `To use Lumina's JSX, you need to ${importDeclaration}`;
|
|
107
|
-
var addMissingJsxImport = createRule({
|
|
108
|
-
name: "add-missing-jsx-import",
|
|
109
|
-
meta: {
|
|
110
|
-
docs: {
|
|
111
|
-
description,
|
|
112
|
-
defaultLevel: "error"
|
|
113
|
-
},
|
|
114
|
-
messages: {
|
|
115
|
-
addMissingJsxImport: description
|
|
116
|
-
},
|
|
117
|
-
type: "problem",
|
|
118
|
-
schema: [],
|
|
119
|
-
fixable: "code"
|
|
120
|
-
},
|
|
121
|
-
defaultOptions: [],
|
|
122
|
-
create(context) {
|
|
123
|
-
let errorAlreadyReported = false;
|
|
124
|
-
let isUsingLumina = false;
|
|
125
|
-
let lastImportDeclaration;
|
|
126
|
-
let lastLuminaImportClause;
|
|
127
|
-
let hasLuminaJsxImport = false;
|
|
128
|
-
return {
|
|
129
|
-
ImportDeclaration(node) {
|
|
130
|
-
lastImportDeclaration = node;
|
|
131
|
-
if (node.source.value !== luminaEntrypointName) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
isUsingLumina = true;
|
|
135
|
-
const isTypeOnly = node.importKind === "type";
|
|
136
|
-
for (const specifier of node.specifiers) {
|
|
137
|
-
if (!isTypeOnly) {
|
|
138
|
-
lastLuminaImportClause = specifier;
|
|
139
|
-
}
|
|
140
|
-
if (specifier.type === AST_NODE_TYPES2.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES2.Identifier && specifier.imported.name === luminaJsxExportName || specifier.imported.type === AST_NODE_TYPES2.Literal && specifier.imported.value === luminaJsxExportName)) {
|
|
141
|
-
hasLuminaJsxImport = true;
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
JSXIdentifier(node) {
|
|
147
|
-
if (isUsingLumina && !hasLuminaJsxImport && !errorAlreadyReported) {
|
|
148
|
-
errorAlreadyReported = true;
|
|
149
|
-
context.report({
|
|
150
|
-
messageId: "addMissingJsxImport",
|
|
151
|
-
node,
|
|
152
|
-
fix(fixer) {
|
|
153
|
-
if (lastLuminaImportClause !== void 0) {
|
|
154
|
-
return fixer.insertTextAfter(lastLuminaImportClause, `, ${luminaJsxExportName}`);
|
|
155
|
-
}
|
|
156
|
-
if (lastImportDeclaration !== void 0) {
|
|
157
|
-
return fixer.insertTextAfter(lastImportDeclaration, importDeclaration);
|
|
158
|
-
} else {
|
|
159
|
-
return fixer.insertTextBefore(context.sourceCode.ast, importDeclaration);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// src/plugins/lumina/rules/auto-add-type.ts
|
|
170
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
|
|
171
|
-
import ts from "typescript";
|
|
172
|
-
var description2 = "Auto add { type: Boolean } or { type: Number } where necessary";
|
|
173
|
-
var autoAddType = createRule({
|
|
174
|
-
name: "auto-add-type",
|
|
175
|
-
meta: {
|
|
176
|
-
docs: {
|
|
177
|
-
description: description2,
|
|
178
|
-
defaultLevel: "warn"
|
|
179
|
-
},
|
|
180
|
-
messages: {
|
|
181
|
-
addType: `This property is of {{ type }} type, yet the type is not trivially inferrable from the AST without type-checking. Such properties require a { type: {{ type }} } annotation.
|
|
182
|
-
|
|
183
|
-
More information: https://devtopia.esri.com/WebGIS/arcgis-web-components/issues/1991`,
|
|
184
|
-
typeAnnotationMismatchesActualType: "The @property({type: {{type}} }) doesn't match the actual property type ({{actualType}}).",
|
|
185
|
-
noEmptyPropertyObject: "Replace @property({}) with @property()",
|
|
186
|
-
noUnnecessaryType: "Property type is trivially inferrable without type-checking - remove needless { type: {{ type }} } annotation.",
|
|
187
|
-
unhandledType: `The default Lit attribute<-->property converter does not define any behavior for @property({ type: {{type}} }). Consider removing this type annotation, or adding a custom converter @property({ converter: ... }) to handle this type`
|
|
188
|
-
},
|
|
189
|
-
type: "problem",
|
|
190
|
-
schema: [],
|
|
191
|
-
fixable: "code"
|
|
192
|
-
},
|
|
193
|
-
defaultOptions: [],
|
|
194
|
-
create(context) {
|
|
195
|
-
const services = ESLintUtils2.getParserServices(context);
|
|
196
|
-
return {
|
|
197
|
-
Decorator(decorator) {
|
|
198
|
-
const part = parsePropertyDecorator(decorator);
|
|
199
|
-
if (part === void 0) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const { options, properties, callExpression } = part;
|
|
203
|
-
const property = decorator.parent;
|
|
204
|
-
if (property?.type !== AST_NODE_TYPES3.MethodDefinition && property?.type !== AST_NODE_TYPES3.PropertyDefinition) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const trivialType = inferTrivialType(property);
|
|
208
|
-
const typeProperty = getProperty(properties, "type");
|
|
209
|
-
const converterProperty = getProperty(properties, "converter");
|
|
210
|
-
const isTrivialType = trivialType === "Number" || trivialType === "Boolean";
|
|
211
|
-
if (isTrivialType && typeProperty !== void 0 && typeProperty.type === AST_NODE_TYPES3.Identifier && (typeProperty.name === "Number" || typeProperty.name === "Boolean")) {
|
|
212
|
-
context.report({
|
|
213
|
-
node: typeProperty,
|
|
214
|
-
messageId: "noUnnecessaryType",
|
|
215
|
-
data: {
|
|
216
|
-
type: typeProperty.name
|
|
217
|
-
},
|
|
218
|
-
fix(fixer) {
|
|
219
|
-
const nextToken = context.sourceCode.getTokenAfter(typeProperty.parent);
|
|
220
|
-
const isTrailingComma = nextToken && nextToken.value === ",";
|
|
221
|
-
return isTrailingComma ? fixer.removeRange([typeProperty.parent.range[0], nextToken.range[1]]) : fixer.remove(typeProperty.parent);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
if (
|
|
227
|
-
// Do not emit any warnings if has "converter" as we don't know what the converter does
|
|
228
|
-
converterProperty === void 0 && typeProperty?.type === AST_NODE_TYPES3.Identifier && !builtInConverterTypes.has(typeProperty.name)
|
|
229
|
-
) {
|
|
230
|
-
context.report({
|
|
231
|
-
node: typeProperty,
|
|
232
|
-
messageId: "unhandledType",
|
|
233
|
-
data: {
|
|
234
|
-
type: typeProperty.name
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
if (isTrivialType) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (options !== void 0 && properties?.length === 0) {
|
|
243
|
-
context.report({
|
|
244
|
-
node: options,
|
|
245
|
-
messageId: "noEmptyPropertyObject",
|
|
246
|
-
fix(fixer) {
|
|
247
|
-
return fixer.replaceText(
|
|
248
|
-
options,
|
|
249
|
-
context.sourceCode.getCommentsInside(options).map((comment) => context.sourceCode.getText(comment)).join("\n")
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const attributeOption = getProperty(properties, "attribute");
|
|
256
|
-
const isAttributeFalse = attributeOption?.type === AST_NODE_TYPES3.Literal && attributeOption.value === false;
|
|
257
|
-
if (isAttributeFalse) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const type = services.getTypeAtLocation(property);
|
|
261
|
-
const typeFlags = (type.flags & ts.TypeFlags.Union ? type.types : [type]).reduce(
|
|
262
|
-
(flags, type2) => flags | type2.flags,
|
|
263
|
-
0
|
|
264
|
-
);
|
|
265
|
-
const isTypeCastable = (typeFlags & (ts.TypeFlags.String | ts.TypeFlags.Any | ts.TypeFlags.Unknown)) === 0;
|
|
266
|
-
const isNumberType = isTypeCastable && typeFlags & ts.TypeFlags.NumberLike;
|
|
267
|
-
const isBooleanType = isTypeCastable && typeFlags & ts.TypeFlags.BooleanLike;
|
|
268
|
-
if (isNumberType && isBooleanType) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (!isNumberType && !isBooleanType) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
if (typeProperty !== void 0) {
|
|
275
|
-
if (
|
|
276
|
-
// Do not emit any warnings if has "converter" as we don't know what the converter does
|
|
277
|
-
converterProperty === void 0 && typeProperty.type === AST_NODE_TYPES3.Identifier && (typeProperty.name === "Number" && isBooleanType || typeProperty.name === "Boolean" && isNumberType)
|
|
278
|
-
) {
|
|
279
|
-
context.report({
|
|
280
|
-
node: typeProperty,
|
|
281
|
-
messageId: "typeAnnotationMismatchesActualType",
|
|
282
|
-
data: {
|
|
283
|
-
type: typeProperty.name,
|
|
284
|
-
actualType: isNumberType ? "Number" : "Boolean"
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
const comments = context.sourceCode.getCommentsBefore(property);
|
|
291
|
-
const isDocsOnlyReadOnly = comments.some((comment) => comment.value.includes("@readonly"));
|
|
292
|
-
const readOnlyProperty = getProperty(properties, "readOnly");
|
|
293
|
-
const hasReadOnlyFlag = readOnlyProperty?.type === AST_NODE_TYPES3.Literal && readOnlyProperty.value === true;
|
|
294
|
-
const isReadOnly = isDocsOnlyReadOnly || hasReadOnlyFlag || isGetterWithoutSetter(property);
|
|
295
|
-
const reflectsProperty = getProperty(properties, "reflects");
|
|
296
|
-
if (isReadOnly && (!isBooleanType || reflectsProperty?.type !== AST_NODE_TYPES3.Literal || reflectsProperty.value !== true)) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
context.report({
|
|
300
|
-
messageId: "addType",
|
|
301
|
-
data: {
|
|
302
|
-
type: isNumberType ? "Number" : "Boolean"
|
|
303
|
-
},
|
|
304
|
-
node: property,
|
|
305
|
-
fix(fixer) {
|
|
306
|
-
const sourceCode = context.sourceCode;
|
|
307
|
-
if (options === void 0) {
|
|
308
|
-
const token = sourceCode.getTokenAfter(callExpression.callee, {
|
|
309
|
-
filter: (token2) => token2.value === "("
|
|
310
|
-
});
|
|
311
|
-
return fixer.insertTextAfterRange(token.range, `{ type: ${isNumberType ? "Number" : "Boolean"} }`);
|
|
312
|
-
} else {
|
|
313
|
-
return fixer.insertTextBefore(options.properties[0], `type: ${isNumberType ? "Number" : "Boolean"}, `);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
function inferTrivialType(member) {
|
|
322
|
-
const type = member.type === AST_NODE_TYPES3.PropertyDefinition ? member.typeAnnotation?.typeAnnotation : member.type === AST_NODE_TYPES3.MethodDefinition && member.kind === "set" ? member.value.params[0]?.typeAnnotation?.typeAnnotation : member.type === AST_NODE_TYPES3.MethodDefinition && member.kind === "get" ? member.value.returnType?.typeAnnotation : void 0;
|
|
323
|
-
if (type === void 0) {
|
|
324
|
-
if (member.value?.type === AST_NODE_TYPES3.Literal && typeof member.value.value === "number" || member.value?.type === AST_NODE_TYPES3.UnaryExpression && member.value.argument.type === AST_NODE_TYPES3.Literal && typeof member.value.argument.value === "number" && member.value.operator === "-") {
|
|
325
|
-
return "Number";
|
|
326
|
-
}
|
|
327
|
-
if (member.value?.type === AST_NODE_TYPES3.Literal && typeof member.value.value === "boolean") {
|
|
328
|
-
return "Boolean";
|
|
329
|
-
}
|
|
330
|
-
} else if (type.type === AST_NODE_TYPES3.TSNumberKeyword) {
|
|
331
|
-
return "Number";
|
|
332
|
-
} else if (type.type === AST_NODE_TYPES3.TSBooleanKeyword) {
|
|
333
|
-
return "Boolean";
|
|
334
|
-
}
|
|
335
|
-
return "Other";
|
|
336
|
-
}
|
|
337
|
-
var builtInConverterTypes = /* @__PURE__ */ new Set(["Number", "Boolean", "Array", "Object"]);
|
|
338
|
-
|
|
339
|
-
// ../components-build-utils/dist/index.js
|
|
340
|
-
import { sep as sep2 } from "path";
|
|
341
|
-
import posix from "path/posix";
|
|
342
|
-
import win32 from "path/win32";
|
|
343
|
-
var isPosix = sep2 === posix.sep;
|
|
344
|
-
var toPosixPathSeparators = (relativePath) => relativePath.includes(win32.sep) ? relativePath.replaceAll(win32.sep, posix.sep) : relativePath;
|
|
345
|
-
var getCwd = isPosix ? process.cwd : () => toPosixPathSeparators(process.cwd());
|
|
346
|
-
var path = isPosix ? posix : {
|
|
347
|
-
...win32,
|
|
348
|
-
sep: posix.sep,
|
|
349
|
-
join(...paths) {
|
|
350
|
-
const result = win32.join(...paths);
|
|
351
|
-
return toPosixPathSeparators(result);
|
|
352
|
-
},
|
|
353
|
-
normalize(path2) {
|
|
354
|
-
const result = win32.normalize(path2);
|
|
355
|
-
return toPosixPathSeparators(result);
|
|
356
|
-
},
|
|
357
|
-
relative(from, to) {
|
|
358
|
-
const result = win32.relative(from, to);
|
|
359
|
-
return toPosixPathSeparators(result);
|
|
360
|
-
},
|
|
361
|
-
dirname(path2) {
|
|
362
|
-
const result = win32.dirname(path2);
|
|
363
|
-
return toPosixPathSeparators(result);
|
|
364
|
-
},
|
|
365
|
-
resolve(...paths) {
|
|
366
|
-
const result = win32.resolve(...paths);
|
|
367
|
-
return toPosixPathSeparators(result);
|
|
368
|
-
},
|
|
369
|
-
toNamespacedPath(path2) {
|
|
370
|
-
const result = win32.toNamespacedPath(path2);
|
|
371
|
-
return toPosixPathSeparators(result);
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
// src/plugins/lumina/rules/component-placement-rules.ts
|
|
376
|
-
var description3 = `Lumina component must be declared in a TSX file with a matching folder name located inside of src/components folder.`;
|
|
377
|
-
var componentPlacementRules = createRule({
|
|
378
|
-
name: "component-placement-rules",
|
|
379
|
-
meta: {
|
|
380
|
-
docs: {
|
|
381
|
-
description: description3,
|
|
382
|
-
defaultLevel: "error"
|
|
383
|
-
},
|
|
384
|
-
messages: {
|
|
385
|
-
fileFolderNameMismatch: "Lumina component must be declared in a file whose name (without extension) matches the parent folder name.\n\nCreating components in nested folders is supported as long as the file name matches the immediate parent folder name.",
|
|
386
|
-
extensionNotTsx: "Lumina component must be declared in a .tsx file.",
|
|
387
|
-
noComponentOutsideSrcComponents: "All lumina components must be declared within the src/components folder. Inside that folder, you can create sub-folders for structuring component files."
|
|
388
|
-
},
|
|
389
|
-
type: "problem",
|
|
390
|
-
schema: [],
|
|
391
|
-
fixable: "code"
|
|
392
|
-
},
|
|
393
|
-
defaultOptions: [],
|
|
394
|
-
create(context) {
|
|
395
|
-
return {
|
|
396
|
-
TSModuleDeclaration(node) {
|
|
397
|
-
const luminaDeclarationInterface = extractDeclareElementsInterface(node);
|
|
398
|
-
if (luminaDeclarationInterface === void 0) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
const filePath = toPosixPathSeparators(context.filename);
|
|
402
|
-
const containsSrcComponents = filePath.includes("/src/components/");
|
|
403
|
-
if (!containsSrcComponents) {
|
|
404
|
-
context.report({ messageId: "noComponentOutsideSrcComponents", node: luminaDeclarationInterface });
|
|
405
|
-
}
|
|
406
|
-
const isFileExtensionTsx = filePath.endsWith(".tsx");
|
|
407
|
-
if (!isFileExtensionTsx) {
|
|
408
|
-
context.report({ messageId: "extensionNotTsx", node: luminaDeclarationInterface });
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
const [fileName, folderName] = filePath.split("/").reverse();
|
|
412
|
-
const extensionlessFileName = fileName.slice(0, -".tsx".length);
|
|
413
|
-
if (folderName !== extensionlessFileName) {
|
|
414
|
-
context.report({ messageId: "fileFolderNameMismatch", node: luminaDeclarationInterface });
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// src/plugins/lumina/rules/consistent-event-naming.ts
|
|
422
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
|
|
423
|
-
var description4 = `Enforce consistent event naming.`;
|
|
424
|
-
var defaultOptions = [
|
|
425
|
-
{
|
|
426
|
-
eventNamespaces: ["arcgis"],
|
|
427
|
-
includeComponentNameInEventName: false
|
|
428
|
-
}
|
|
429
|
-
];
|
|
430
|
-
var consistentEventNaming = createRule({
|
|
431
|
-
name: "consistent-event-naming",
|
|
432
|
-
meta: {
|
|
433
|
-
docs: {
|
|
434
|
-
description: description4,
|
|
435
|
-
defaultLevel: "warn"
|
|
436
|
-
},
|
|
437
|
-
messages: {
|
|
438
|
-
eventNamespaceError: `Custom event name must start with one of the following prefixes: {{ prefixes }}.
|
|
439
|
-
|
|
440
|
-
Details: https://qawebgis.esri.com/components/lumina/events#best-practices-around-emitting-events`,
|
|
441
|
-
componentNameInEventError: `For consistency, event name should not start with component name.
|
|
442
|
-
|
|
443
|
-
Discussion: https://devtopia.esri.com/WebGIS/arcgis-web-components/discussions/307`,
|
|
444
|
-
noComponentNameInEventError: `For consistency, event name should include component name.`,
|
|
445
|
-
missingPrivateJsDocTag: `Internal and private events must be marked with @internal or @private JSDoc tag.`
|
|
446
|
-
},
|
|
447
|
-
type: "problem",
|
|
448
|
-
schema: [
|
|
449
|
-
{
|
|
450
|
-
type: "object",
|
|
451
|
-
properties: {
|
|
452
|
-
eventNamespaces: {
|
|
453
|
-
type: "array",
|
|
454
|
-
items: {
|
|
455
|
-
type: "string"
|
|
456
|
-
}
|
|
457
|
-
},
|
|
458
|
-
includeComponentNameInEventName: {
|
|
459
|
-
type: "boolean"
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
additionalProperties: false
|
|
463
|
-
}
|
|
464
|
-
]
|
|
465
|
-
},
|
|
466
|
-
defaultOptions,
|
|
467
|
-
create(context, options) {
|
|
468
|
-
const eventNamespaces = options[0].eventNamespaces;
|
|
469
|
-
const includeComponentNameInEventName = options[0].includeComponentNameInEventName;
|
|
470
|
-
return {
|
|
471
|
-
PropertyDefinition(node) {
|
|
472
|
-
const isLuminaEvent = isCreateEvent(node);
|
|
473
|
-
if (!isLuminaEvent) {
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
const comments = context.sourceCode.getCommentsBefore(node);
|
|
477
|
-
const isDeprecated = comments.some((comment) => comment.value.includes("@deprecated"));
|
|
478
|
-
if (isDeprecated) {
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
const componentName = context.sourceCode.getAncestors(node).find((ancestor) => ancestor.type === AST_NODE_TYPES4.ClassDeclaration)?.id?.name;
|
|
482
|
-
if (componentName === void 0) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
const propertyName = node.key.type === AST_NODE_TYPES4.Identifier ? node.key.name : node.key.type === AST_NODE_TYPES4.Literal ? node.key.value : void 0;
|
|
486
|
-
if (typeof propertyName !== "string") {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
let eventName = propertyName;
|
|
490
|
-
if (eventNamespaces.length > 0) {
|
|
491
|
-
const currentNamespace = eventNamespaces.find((namespace) => eventName.startsWith(namespace));
|
|
492
|
-
if (currentNamespace === void 0) {
|
|
493
|
-
context.report({
|
|
494
|
-
messageId: "eventNamespaceError",
|
|
495
|
-
data: {
|
|
496
|
-
prefixes: eventNamespaces.join(", ")
|
|
497
|
-
},
|
|
498
|
-
node: node.key
|
|
499
|
-
});
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
eventName = eventName.slice(currentNamespace.length);
|
|
503
|
-
}
|
|
504
|
-
const startsWithInternal = eventName.toLowerCase().startsWith("internal");
|
|
505
|
-
if (startsWithInternal || eventName.toLowerCase().startsWith("private")) {
|
|
506
|
-
const hasInternalJsDocTag = comments.some((comment) => comment.value.includes("@internal"));
|
|
507
|
-
const hasPrivateJsDocTag = comments.some((comment) => comment.value.includes("@private"));
|
|
508
|
-
if (!hasInternalJsDocTag && !hasPrivateJsDocTag) {
|
|
509
|
-
context.report({
|
|
510
|
-
messageId: "missingPrivateJsDocTag",
|
|
511
|
-
node: node.key
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
eventName = startsWithInternal ? eventName.slice("internal".length) : eventName.slice("private".length);
|
|
515
|
-
}
|
|
516
|
-
const capitalIndex = capitalAfterLower.exec(componentName)?.index;
|
|
517
|
-
const unNamespacedComponentName = capitalIndex === void 0 ? void 0 : componentName.slice(capitalIndex) || void 0;
|
|
518
|
-
const includesComponentName = eventName.startsWith(componentName) || unNamespacedComponentName !== void 0 && eventName.startsWith(unNamespacedComponentName);
|
|
519
|
-
if (includeComponentNameInEventName && !includesComponentName) {
|
|
520
|
-
context.report({
|
|
521
|
-
messageId: "noComponentNameInEventError",
|
|
522
|
-
node: node.key
|
|
523
|
-
});
|
|
524
|
-
} else if (!includeComponentNameInEventName && includesComponentName) {
|
|
525
|
-
context.report({
|
|
526
|
-
messageId: "componentNameInEventError",
|
|
527
|
-
node: node.key
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
});
|
|
534
|
-
var capitalAfterLower = /(?<=[a-z\d])[A-Z]/u;
|
|
535
|
-
|
|
536
|
-
// src/plugins/lumina/rules/decorators-context.ts
|
|
537
|
-
var description5 = `Enforce that @property(), @method() and createEvent() members are used in the correct context.`;
|
|
538
|
-
var decoratorsContext = createRule({
|
|
539
|
-
name: "decorators-context",
|
|
540
|
-
meta: {
|
|
541
|
-
docs: {
|
|
542
|
-
description: description5,
|
|
543
|
-
defaultLevel: "error"
|
|
544
|
-
},
|
|
545
|
-
messages: {
|
|
546
|
-
publicApiMustBePublic: `@property(), @method() and createEvent() members must not have private or protected modifier.
|
|
547
|
-
|
|
548
|
-
If you wish to hide this member from public documentation, use @private or @protected JSDoc tags instead. Documentation: https://qawebgis.esri.com/components/lumina/documenting-components#excluding-api-from-public-documentation`,
|
|
549
|
-
noPropertyDecoratorOnMethods: `Methods must not have @property() nor @state() decorator. Did you mean @property() instead?`,
|
|
550
|
-
noCombinedPropertyEvent: `Property may either be an event (initialized with createEvent()) or a property (has @property() decorator), but not both`,
|
|
551
|
-
noCombinedPropertyState: `Property may either be a state (initialized with @state()) or a property (has @property() decorator), but not both`,
|
|
552
|
-
noComputedName: `Computed property names are not allowed as they are not statically analyzable`
|
|
553
|
-
},
|
|
554
|
-
type: "problem",
|
|
555
|
-
schema: [],
|
|
556
|
-
fixable: "code"
|
|
557
|
-
},
|
|
558
|
-
defaultOptions: [],
|
|
559
|
-
create(context) {
|
|
560
|
-
return {
|
|
561
|
-
PropertyDefinition(node) {
|
|
562
|
-
const hasPropertyDecorator = hasDecorator(node, "property");
|
|
563
|
-
const isPrivateOrProtected = node.accessibility === "private" || node.accessibility === "protected";
|
|
564
|
-
if (hasPropertyDecorator && isPrivateOrProtected) {
|
|
565
|
-
context.report({ messageId: "publicApiMustBePublic", node });
|
|
566
|
-
}
|
|
567
|
-
const isLuminaEvent = isCreateEvent(node);
|
|
568
|
-
if (isLuminaEvent && isPrivateOrProtected) {
|
|
569
|
-
context.report({ messageId: "publicApiMustBePublic", node });
|
|
570
|
-
}
|
|
571
|
-
if (isLuminaEvent && hasPropertyDecorator) {
|
|
572
|
-
context.report({ messageId: "noCombinedPropertyEvent", node });
|
|
573
|
-
}
|
|
574
|
-
const hasStateDecorator = hasDecorator(node, "state");
|
|
575
|
-
if (hasStateDecorator && hasPropertyDecorator) {
|
|
576
|
-
context.report({ messageId: "noCombinedPropertyState", node });
|
|
577
|
-
}
|
|
578
|
-
if (hasPropertyDecorator && node.computed) {
|
|
579
|
-
context.report({ messageId: "noComputedName", node });
|
|
580
|
-
}
|
|
581
|
-
},
|
|
582
|
-
MethodDefinition(node) {
|
|
583
|
-
const hasMethodDecorator = hasDecorator(node, "method");
|
|
584
|
-
const hasPropertyDecorator = hasDecorator(node, "property");
|
|
585
|
-
const hasStateDecorator = hasDecorator(node, "state");
|
|
586
|
-
const isPrivateOrProtected = node.accessibility === "private" || node.accessibility === "protected";
|
|
587
|
-
if (hasMethodDecorator && isPrivateOrProtected) {
|
|
588
|
-
context.report({ messageId: "publicApiMustBePublic", node });
|
|
589
|
-
}
|
|
590
|
-
if (hasMethodDecorator && (hasPropertyDecorator || hasStateDecorator)) {
|
|
591
|
-
context.report({ messageId: "noPropertyDecoratorOnMethods", node });
|
|
592
|
-
}
|
|
593
|
-
if (hasStateDecorator && hasPropertyDecorator) {
|
|
594
|
-
context.report({ messageId: "noCombinedPropertyState", node });
|
|
595
|
-
}
|
|
596
|
-
const isRealMethod = node.kind === "method";
|
|
597
|
-
if (isRealMethod && (hasPropertyDecorator || hasStateDecorator)) {
|
|
598
|
-
context.report({ messageId: "noPropertyDecoratorOnMethods", node });
|
|
599
|
-
}
|
|
600
|
-
if ((hasPropertyDecorator || hasMethodDecorator) && node.computed) {
|
|
601
|
-
context.report({ messageId: "noComputedName", node });
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
// src/plugins/lumina/rules/member-ordering.ts
|
|
609
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES7 } from "@typescript-eslint/utils";
|
|
610
|
-
|
|
611
|
-
// src/plugins/lumina/rules/member-ordering/config.ts
|
|
612
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES5 } from "@typescript-eslint/utils";
|
|
613
|
-
var ordering = [
|
|
614
|
-
/*
|
|
615
|
-
* Putting static before instance members is a common OOP convention.
|
|
616
|
-
* Static members are always evaluated before instance members.
|
|
617
|
-
*/
|
|
618
|
-
"Static Members",
|
|
619
|
-
/**
|
|
620
|
-
* Put private properties before public, because private properties are
|
|
621
|
-
* often used as a default value for public properties.
|
|
622
|
-
*/
|
|
623
|
-
"Private Properties",
|
|
624
|
-
/**
|
|
625
|
-
* Put private properties before public, because private properties are often
|
|
626
|
-
* used as a default value for public properties.
|
|
627
|
-
*/
|
|
628
|
-
"State Properties",
|
|
629
|
-
/*
|
|
630
|
-
* Properties are the key component API. Also, since default values of
|
|
631
|
-
* properties evaluate before the constructor, they should logically be before
|
|
632
|
-
* the constructor.
|
|
633
|
-
*/
|
|
634
|
-
"Public Properties",
|
|
635
|
-
/*
|
|
636
|
-
* Methods should be a supplementary component API, not primary, so are listed
|
|
637
|
-
* after properties. At the same time, it is nice to keep public component API
|
|
638
|
-
* all in one place.
|
|
639
|
-
*/
|
|
640
|
-
"Public Methods",
|
|
641
|
-
/*
|
|
642
|
-
* Put events near properties and methods to keep all public component API in
|
|
643
|
-
* one place.
|
|
644
|
-
*/
|
|
645
|
-
"Events",
|
|
646
|
-
/*
|
|
647
|
-
* Lifecycle methods like constructor and connectedCallback are executed
|
|
648
|
-
* after all properties have default values, but before any render functions.
|
|
649
|
-
*/
|
|
650
|
-
"Lifecycle",
|
|
651
|
-
/*
|
|
652
|
-
* Private methods in between lifecycles and rendering as they are often
|
|
653
|
-
* called by either of them.
|
|
654
|
-
*/
|
|
655
|
-
"Private Methods",
|
|
656
|
-
/*
|
|
657
|
-
* Fred:
|
|
658
|
-
* The reason rendering methods are at the bottom of my modules because I can
|
|
659
|
-
* quickly jump to the bottom find the rendering method and work on it. Less
|
|
660
|
-
* scrolling.
|
|
661
|
-
* Once a module has been implemented, most of the bugs/enhancements occur in
|
|
662
|
-
* the rendering methods.
|
|
663
|
-
*/
|
|
664
|
-
"Rendering"
|
|
665
|
-
];
|
|
666
|
-
var getWireframe = () => new Map(ordering.map((region) => [region, []]));
|
|
667
|
-
var entries = Object.entries;
|
|
668
|
-
var regionMatchers = entries({
|
|
669
|
-
"Static Members": (node) => node.type === AST_NODE_TYPES5.StaticBlock || "static" in node && node.static,
|
|
670
|
-
"Lifecycle": (_node, name) => lifecyclesSet.has(name),
|
|
671
|
-
"Public Methods": (node) => "decorators" in node && hasDecorator(node, "method"),
|
|
672
|
-
"Public Properties": (node) => "decorators" in node && hasDecorator(node, "property"),
|
|
673
|
-
"State Properties": (node) => "decorators" in node && hasDecorator(node, "state"),
|
|
674
|
-
"Events": isEvent,
|
|
675
|
-
"Rendering": (_node, name) => name.startsWith("render") || name.startsWith("_render"),
|
|
676
|
-
"Private Properties": (node) => (
|
|
677
|
-
// We don't yet support public accessor properties
|
|
678
|
-
node.type === AST_NODE_TYPES5.PropertyDefinition || node.type === AST_NODE_TYPES5.AccessorProperty
|
|
679
|
-
),
|
|
680
|
-
"Private Methods": () => true
|
|
681
|
-
});
|
|
682
|
-
var definitelyComponentRegions = /* @__PURE__ */ new Set([
|
|
683
|
-
"Rendering",
|
|
684
|
-
"State Properties",
|
|
685
|
-
"Public Methods",
|
|
686
|
-
"Events"
|
|
687
|
-
]);
|
|
688
|
-
var regionsArray = regionMatchers.map(([key]) => key);
|
|
689
|
-
function isEvent(node, name) {
|
|
690
|
-
if (node.type !== AST_NODE_TYPES5.PropertyDefinition) {
|
|
691
|
-
return false;
|
|
692
|
-
}
|
|
693
|
-
if (name === "arcgisPropertyChange") {
|
|
694
|
-
return true;
|
|
695
|
-
}
|
|
696
|
-
const initializer = node.value;
|
|
697
|
-
if (initializer?.type !== AST_NODE_TYPES5.CallExpression) {
|
|
698
|
-
return false;
|
|
699
|
-
}
|
|
700
|
-
const callExpression = initializer.callee;
|
|
701
|
-
const functionName = callExpression.type === AST_NODE_TYPES5.Identifier ? callExpression.name : callExpression.type === AST_NODE_TYPES5.CallExpression && callExpression.callee.type === AST_NODE_TYPES5.Identifier ? callExpression.callee.name : void 0;
|
|
702
|
-
return functionName === "createEvent" || functionName === "reEmitEvent" || functionName === "usePropertyChange";
|
|
703
|
-
}
|
|
704
|
-
var lifecycles = [
|
|
705
|
-
"constructor",
|
|
706
|
-
"connectedCallback",
|
|
707
|
-
"load",
|
|
708
|
-
"shouldUpdate",
|
|
709
|
-
// Not an actual lifecycle method, but can be temporary inserted by the codemod
|
|
710
|
-
"_shouldUpdate",
|
|
711
|
-
"willUpdate",
|
|
712
|
-
"update",
|
|
713
|
-
"firstUpdated",
|
|
714
|
-
"updated",
|
|
715
|
-
"loaded",
|
|
716
|
-
"disconnectedCallback"
|
|
717
|
-
];
|
|
718
|
-
var lifecyclesSet = new Set(lifecycles);
|
|
719
|
-
var supportedNodeTypes = {
|
|
720
|
-
MethodDefinition: true,
|
|
721
|
-
PropertyDefinition: true,
|
|
722
|
-
AccessorProperty: true,
|
|
723
|
-
StaticBlock: true,
|
|
724
|
-
// These should not be present in non-abstract Lumina component classes
|
|
725
|
-
TSAbstractAccessorProperty: false,
|
|
726
|
-
TSAbstractMethodDefinition: false,
|
|
727
|
-
TSAbstractPropertyDefinition: false,
|
|
728
|
-
TSIndexSignature: false
|
|
729
|
-
};
|
|
730
|
-
|
|
731
|
-
// src/plugins/lumina/rules/member-ordering/comments.ts
|
|
732
|
-
import { AST_TOKEN_TYPES } from "@typescript-eslint/utils";
|
|
733
|
-
function categorizeComments(membersData, sourceCode) {
|
|
734
|
-
const categorized = {
|
|
735
|
-
header: [],
|
|
736
|
-
regionFooter: /* @__PURE__ */ new Map(),
|
|
737
|
-
memberLineEnd: /* @__PURE__ */ new Map(),
|
|
738
|
-
footer: [],
|
|
739
|
-
membersByName: /* @__PURE__ */ new Map()
|
|
740
|
-
};
|
|
741
|
-
let regionName;
|
|
742
|
-
membersData.forEach((memberData, index) => {
|
|
743
|
-
const nameNodes = categorized.membersByName.get(memberData.name);
|
|
744
|
-
if (nameNodes !== void 0) {
|
|
745
|
-
nameNodes.push(memberData);
|
|
746
|
-
} else {
|
|
747
|
-
categorized.membersByName.set(memberData.name, [memberData]);
|
|
748
|
-
}
|
|
749
|
-
memberData.comments = handleLineEndComment(memberData.comments, membersData.at(index - 1), categorized);
|
|
750
|
-
let newRegionName;
|
|
751
|
-
const lastRegionStart = memberData.comments.findLastIndex((comment) => {
|
|
752
|
-
const match = parseRegionComment(comment);
|
|
753
|
-
const isRegionStart = match !== void 0 && match.end === void 0;
|
|
754
|
-
newRegionName = match?.name;
|
|
755
|
-
return isRegionStart;
|
|
756
|
-
});
|
|
757
|
-
if (lastRegionStart !== -1) {
|
|
758
|
-
const commentsBeforeNewRegionStart = memberData.comments.slice(0, lastRegionStart);
|
|
759
|
-
const previousMember = membersData.at(index - 1);
|
|
760
|
-
handleCommentsAroundEndRegion(
|
|
761
|
-
commentsBeforeNewRegionStart,
|
|
762
|
-
false,
|
|
763
|
-
previousMember ?? memberData,
|
|
764
|
-
categorized,
|
|
765
|
-
regionName
|
|
766
|
-
);
|
|
767
|
-
memberData.comments = memberData.comments.slice(lastRegionStart + 1);
|
|
768
|
-
regionName = newRegionName;
|
|
769
|
-
}
|
|
770
|
-
const isLastNode = index === membersData.length - 1;
|
|
771
|
-
if (isLastNode) {
|
|
772
|
-
const trailingComments = sourceCode.getCommentsAfter(memberData.member);
|
|
773
|
-
const remainingTrailingComments = handleLineEndComment(trailingComments, memberData, categorized);
|
|
774
|
-
const previousMember = membersData.at(index - 1);
|
|
775
|
-
handleCommentsAroundEndRegion(
|
|
776
|
-
remainingTrailingComments,
|
|
777
|
-
true,
|
|
778
|
-
previousMember ?? memberData,
|
|
779
|
-
categorized,
|
|
780
|
-
regionName
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
return categorized;
|
|
785
|
-
}
|
|
786
|
-
function handleLineEndComment(comments, previousNode, categorized) {
|
|
787
|
-
if (comments.at(0)?.loc.start.line === previousNode?.member.loc.end.line) {
|
|
788
|
-
categorized.memberLineEnd.set(previousNode, comments.slice(0, 1));
|
|
789
|
-
return comments.slice(1);
|
|
790
|
-
}
|
|
791
|
-
return comments;
|
|
792
|
-
}
|
|
793
|
-
function handleCommentsAroundEndRegion(commentsBeforeNewRegionStart, isFooter, lastMember, categorized, regionName) {
|
|
794
|
-
if (regionName === void 0) {
|
|
795
|
-
const destination = isFooter ? categorized.footer : categorized.header;
|
|
796
|
-
destination.push(...commentsBeforeNewRegionStart);
|
|
797
|
-
} else {
|
|
798
|
-
const firstEndRegion = commentsBeforeNewRegionStart.findIndex(
|
|
799
|
-
(comment) => parseRegionComment(comment)?.end !== void 0
|
|
800
|
-
);
|
|
801
|
-
let previousRegionComments = commentsBeforeNewRegionStart;
|
|
802
|
-
if (firstEndRegion !== -1) {
|
|
803
|
-
categorized.footer.push(...commentsBeforeNewRegionStart.slice(firstEndRegion + 1));
|
|
804
|
-
previousRegionComments = commentsBeforeNewRegionStart.slice(0, firstEndRegion);
|
|
805
|
-
}
|
|
806
|
-
const existingFooter = categorized.regionFooter.get(regionName);
|
|
807
|
-
if (existingFooter === void 0) {
|
|
808
|
-
categorized.regionFooter.set(regionName, { comments: Array.from(previousRegionComments), lastMember });
|
|
809
|
-
} else {
|
|
810
|
-
existingFooter.comments.push(...previousRegionComments);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
var normalizeComments = (comments = [], sourceCode, indent = " ") => comments.filter((comment) => parseRegionComment(comment) === void 0).map((comment) => `${indent}${sourceCode.getText(comment)}`).join("\n").replaceAll(reJsApiSectionComment, "");
|
|
815
|
-
var join = (left, right, joiner = "\n\n") => left === "" || right === "" ? right || left : `${left}${joiner}${right}`;
|
|
816
|
-
var reRegionComment = /^ ?#(?<end>end)?region ?(?<name>[^\n]*)$/u;
|
|
817
|
-
var parseRegionComment = (comment) => comment.type === AST_TOKEN_TYPES.Line ? reRegionComment.exec(comment.value)?.groups : void 0;
|
|
818
|
-
var reJsApiSectionComment = /^ \/\/ ?-{4,}\n(?: \/\/\s*\n)? \/\/\s+[^\s][^\n]+\n(?: \/\/\s*\n)? \/\/ ?-{4,}/gmu;
|
|
819
|
-
|
|
820
|
-
// src/plugins/lumina/rules/member-ordering/normalize.ts
|
|
821
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES6 } from "@typescript-eslint/utils";
|
|
822
|
-
function getNormalizedRegions(membersByName) {
|
|
823
|
-
const regions = getWireframe();
|
|
824
|
-
membersByName.values().forEach((members) => {
|
|
825
|
-
const lowestRegionIndex = members.reduce(
|
|
826
|
-
(min, { region }) => Math.min(min, regionsArray.indexOf(region)),
|
|
827
|
-
Number.POSITIVE_INFINITY
|
|
828
|
-
);
|
|
829
|
-
if (members.length === 2 && members[0].member.type === AST_NODE_TYPES6.MethodDefinition && members[0].member.kind === "set") {
|
|
830
|
-
members.reverse();
|
|
831
|
-
}
|
|
832
|
-
const regionName = regionsArray[lowestRegionIndex];
|
|
833
|
-
regions.get(regionName).push(...members);
|
|
834
|
-
});
|
|
835
|
-
const normalizedRegions = Array.from(regions).filter(([_region, members]) => members.length > 0).map(
|
|
836
|
-
([region, members]) => [region, sortableRegions.has(region) ? members.sort(sortFunction.bind(void 0, region)) : members]
|
|
837
|
-
);
|
|
838
|
-
return normalizedRegions;
|
|
839
|
-
}
|
|
840
|
-
var sortableRegions = /* @__PURE__ */ new Set(["Public Methods", "Events", "Lifecycle"]);
|
|
841
|
-
function sortFunction(region, leftMember, rightMember) {
|
|
842
|
-
let leftName = leftMember.name;
|
|
843
|
-
let rightName = rightMember.name;
|
|
844
|
-
if (region === "Lifecycle") {
|
|
845
|
-
const compare = lifecycles.indexOf(leftName) - lifecycles.indexOf(rightName);
|
|
846
|
-
return compare < 0 ? -1 : 1;
|
|
847
|
-
}
|
|
848
|
-
if (leftName.startsWith("_")) {
|
|
849
|
-
leftName = leftName.slice(1);
|
|
850
|
-
}
|
|
851
|
-
if (rightName.startsWith("_")) {
|
|
852
|
-
rightName = rightName.slice(1);
|
|
853
|
-
}
|
|
854
|
-
if (leftName < rightName) {
|
|
855
|
-
return -1;
|
|
856
|
-
} else if (leftName > rightName) {
|
|
857
|
-
return 1;
|
|
858
|
-
} else {
|
|
859
|
-
return 0;
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
function reParentOrphanFooterComments(normalizedRegions, regionFooter) {
|
|
863
|
-
const finalRegions = new Set(normalizedRegions.map(([region]) => region));
|
|
864
|
-
regionFooter.forEach(({ comments, lastMember }, originalRegionName) => {
|
|
865
|
-
const regionStillExists = finalRegions.has(originalRegionName);
|
|
866
|
-
if (regionStillExists) {
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
const newFooterCommentsParent = lastMember.region;
|
|
870
|
-
const existingParentFooter = regionFooter.get(newFooterCommentsParent);
|
|
871
|
-
if (existingParentFooter === void 0) {
|
|
872
|
-
regionFooter.set(newFooterCommentsParent, { comments, lastMember });
|
|
873
|
-
} else {
|
|
874
|
-
existingParentFooter.comments.push(...comments);
|
|
875
|
-
}
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// src/plugins/lumina/rules/member-ordering/build.ts
|
|
880
|
-
function buildNewBody(normalizedRegions, strayComments, sourceCode) {
|
|
881
|
-
const newRegions = normalizedRegions.map(([region, members]) => {
|
|
882
|
-
const memberLines = members.map((memberData, index) => {
|
|
883
|
-
const { member, comments, name } = memberData;
|
|
884
|
-
const commentsString = normalizeComments(comments, sourceCode);
|
|
885
|
-
const code = sourceCode.getText(member);
|
|
886
|
-
const lineEndComment = normalizeComments(strayComments.memberLineEnd.get(memberData), sourceCode, " ");
|
|
887
|
-
const memberString = ` ${code}${lineEndComment}`;
|
|
888
|
-
const fullMemberString = join(commentsString, memberString, "\n");
|
|
889
|
-
const nextMember = members.at(index + 1);
|
|
890
|
-
const isLast = nextMember === void 0;
|
|
891
|
-
const isNextSameName = name.length > 0 && name === nextMember?.name;
|
|
892
|
-
const separator = isLast ? "" : isNextSameName ? "\n" : "\n\n";
|
|
893
|
-
return `${fullMemberString}${separator}`;
|
|
894
|
-
});
|
|
895
|
-
const footerComments = normalizeComments(strayComments.regionFooter.get(region)?.comments, sourceCode);
|
|
896
|
-
const footer2 = join(footerComments, " //#endregion", "\n\n");
|
|
897
|
-
return [` //#region ${region}`, memberLines.join(""), footer2].join("\n\n");
|
|
898
|
-
});
|
|
899
|
-
const header = normalizeComments(strayComments.header, sourceCode);
|
|
900
|
-
const footer = normalizeComments(strayComments.footer, sourceCode);
|
|
901
|
-
const newBodyContent = join(join(header, newRegions.join("\n\n")), footer);
|
|
902
|
-
const newBody = `{
|
|
903
|
-
${newBodyContent}
|
|
904
|
-
}`;
|
|
905
|
-
return newBody;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// src/plugins/lumina/rules/member-ordering.ts
|
|
909
|
-
var baseDescription = `Consistently sort component members`;
|
|
910
|
-
var memberOrdering = createRule({
|
|
911
|
-
name: "member-ordering",
|
|
912
|
-
meta: {
|
|
913
|
-
docs: {
|
|
914
|
-
description: baseDescription,
|
|
915
|
-
defaultLevel: "warn"
|
|
916
|
-
},
|
|
917
|
-
messages: {
|
|
918
|
-
memberOrdering: "Component member ordering is not consistent. Run ESLint autofix to sort members.",
|
|
919
|
-
unsupportedElementType: "Unsupported class element type: {{ type }}"
|
|
920
|
-
},
|
|
921
|
-
type: "layout",
|
|
922
|
-
schema: [],
|
|
923
|
-
fixable: "whitespace"
|
|
924
|
-
},
|
|
925
|
-
defaultOptions: [],
|
|
926
|
-
create: (context) => ({
|
|
927
|
-
ClassDeclaration(component) {
|
|
928
|
-
const isNamedExport = component.parent?.type === AST_NODE_TYPES7.ExportNamedDeclaration;
|
|
929
|
-
if (!isNamedExport || component.abstract) {
|
|
930
|
-
return;
|
|
931
|
-
}
|
|
932
|
-
const hasExtends = component.superClass !== null;
|
|
933
|
-
if (!hasExtends) {
|
|
934
|
-
return;
|
|
935
|
-
}
|
|
936
|
-
const sourceCode = context.sourceCode;
|
|
937
|
-
const seenNames = /* @__PURE__ */ new Set();
|
|
938
|
-
let currentRegion = "";
|
|
939
|
-
let hasWrongOrdering = false;
|
|
940
|
-
let isDefinitelyComponent = false;
|
|
941
|
-
let hadError = false;
|
|
942
|
-
const membersData = component.body.body.map((member) => {
|
|
943
|
-
const isSupportedType = supportedNodeTypes[member.type];
|
|
944
|
-
if (!isSupportedType) {
|
|
945
|
-
hadError = true;
|
|
946
|
-
context.report({ node: member, messageId: "unsupportedElementType", data: { type: member.type } });
|
|
947
|
-
}
|
|
948
|
-
const name = "key" in member ? getName(member) ?? "" : "";
|
|
949
|
-
const newRegion = regionMatchers.find(([, rules]) => rules(member, name))[0];
|
|
950
|
-
const comments = sourceCode.getCommentsBefore(member);
|
|
951
|
-
if (!hasWrongOrdering) {
|
|
952
|
-
let wrongOrdering = false;
|
|
953
|
-
const previousRegion = currentRegion;
|
|
954
|
-
for (const comment of comments) {
|
|
955
|
-
const region = parseRegionComment(comment);
|
|
956
|
-
if (region === void 0 || region.end !== void 0) {
|
|
957
|
-
continue;
|
|
958
|
-
}
|
|
959
|
-
currentRegion = region.name;
|
|
960
|
-
wrongOrdering ||= currentRegion !== newRegion;
|
|
961
|
-
}
|
|
962
|
-
if (
|
|
963
|
-
/*
|
|
964
|
-
* The @property()/@method() decorator might be missing from this
|
|
965
|
-
* node in case of getter/setter or method overload, while still
|
|
966
|
-
* being in correct ordering.
|
|
967
|
-
* The logic in rule body is lightweight compared to more
|
|
968
|
-
* comprehensive in the autofix to keep common case fast, so we
|
|
969
|
-
* ignore possible errors in getter/setters (but those errors would
|
|
970
|
-
* still be fixed as long as there is any other error in the file).
|
|
971
|
-
*/
|
|
972
|
-
!seenNames.has(name) && (member.type !== AST_NODE_TYPES7.MethodDefinition || member.kind !== "get" && member.kind !== "set")
|
|
973
|
-
) {
|
|
974
|
-
wrongOrdering ||= currentRegion !== newRegion;
|
|
975
|
-
wrongOrdering ||= previousRegion !== currentRegion && ordering.indexOf(previousRegion) > ordering.indexOf(currentRegion);
|
|
976
|
-
hasWrongOrdering = wrongOrdering;
|
|
977
|
-
}
|
|
978
|
-
seenNames.add(name);
|
|
979
|
-
}
|
|
980
|
-
isDefinitelyComponent ||= definitelyComponentRegions.has(newRegion);
|
|
981
|
-
return { member, name, comments, region: newRegion };
|
|
982
|
-
});
|
|
983
|
-
if (!isDefinitelyComponent) {
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
if (hadError) {
|
|
987
|
-
return;
|
|
988
|
-
}
|
|
989
|
-
if (!hasWrongOrdering) {
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
context.report({
|
|
993
|
-
/**
|
|
994
|
-
* Since this rule is autofixable and stylistic, to be less obtrusive,
|
|
995
|
-
* report the error for a single character only, rather than entire
|
|
996
|
-
* component
|
|
997
|
-
*/
|
|
998
|
-
loc: {
|
|
999
|
-
start: component.loc.end,
|
|
1000
|
-
end: component.loc.end
|
|
1001
|
-
},
|
|
1002
|
-
messageId: "memberOrdering",
|
|
1003
|
-
/*
|
|
1004
|
-
* We delay as much work as possible till the autofixer is run because
|
|
1005
|
-
* most of the time the rule will be run without need for autofixing.
|
|
1006
|
-
*/
|
|
1007
|
-
fix(fixer) {
|
|
1008
|
-
const { membersByName, ...strayComments } = categorizeComments(membersData, sourceCode);
|
|
1009
|
-
const normalizedRegions = getNormalizedRegions(membersByName);
|
|
1010
|
-
reParentOrphanFooterComments(normalizedRegions, strayComments.regionFooter);
|
|
1011
|
-
const newBody = buildNewBody(normalizedRegions, strayComments, sourceCode);
|
|
1012
|
-
return fixer.replaceText(component.body, newBody);
|
|
1013
|
-
}
|
|
1014
|
-
});
|
|
1015
|
-
}
|
|
1016
|
-
})
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
// src/plugins/lumina/rules/no-ignore-jsdoc-tag.ts
|
|
1020
|
-
var description6 = `Use @internal or @private JSDoc tag over @ignore. See https://qawebgis.esri.com/components/lumina/documenting-components#excluding-api-from-public-documentation`;
|
|
1021
|
-
var noIgnoreJsDocTag = createRule({
|
|
1022
|
-
name: "no-ignore-jsdoc-tag",
|
|
1023
|
-
meta: {
|
|
1024
|
-
docs: {
|
|
1025
|
-
description: description6,
|
|
1026
|
-
defaultLevel: "error"
|
|
1027
|
-
},
|
|
1028
|
-
messages: {
|
|
1029
|
-
noIgnoreJsDocTag: description6
|
|
1030
|
-
},
|
|
1031
|
-
type: "problem",
|
|
1032
|
-
schema: []
|
|
1033
|
-
},
|
|
1034
|
-
defaultOptions: [],
|
|
1035
|
-
create(context) {
|
|
1036
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1037
|
-
return {
|
|
1038
|
-
"ImportDeclaration": luminaJsxCheck,
|
|
1039
|
-
"Program:exit"() {
|
|
1040
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
1041
|
-
return;
|
|
1042
|
-
}
|
|
1043
|
-
Array.from(
|
|
1044
|
-
context.sourceCode.text.matchAll(reIgnore),
|
|
1045
|
-
(match) => context.report({
|
|
1046
|
-
messageId: "noIgnoreJsDocTag",
|
|
1047
|
-
loc: {
|
|
1048
|
-
start: context.sourceCode.getLocFromIndex(match.index + "* ".length),
|
|
1049
|
-
end: context.sourceCode.getLocFromIndex(match.index + match[0].length)
|
|
1050
|
-
}
|
|
1051
|
-
})
|
|
1052
|
-
);
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
});
|
|
1057
|
-
var reIgnore = /\* @ignore/gu;
|
|
1058
|
-
|
|
1059
|
-
// src/plugins/lumina/rules/no-incorrect-dynamic-tag-name.ts
|
|
1060
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES8, ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
|
|
1061
|
-
import ts2 from "typescript";
|
|
1062
|
-
var description7 = `Detect incorrect usage of dynamic JSX tag name`;
|
|
1063
|
-
var noIncorrectDynamicTagName = createRule({
|
|
1064
|
-
name: "no-incorrect-dynamic-tag-name",
|
|
1065
|
-
meta: {
|
|
1066
|
-
docs: {
|
|
1067
|
-
description: description7,
|
|
1068
|
-
defaultLevel: "error"
|
|
1069
|
-
},
|
|
1070
|
-
messages: {
|
|
1071
|
-
incorrectDynamicTagName: `This is using incorrect dynamic tag name syntax. See documentation on how to use dynamic tag in Lumina's JSX: https://qawebgis.esri.com/components/lumina/jsx#dynamic-tag-name`
|
|
1072
|
-
},
|
|
1073
|
-
type: "problem",
|
|
1074
|
-
schema: []
|
|
1075
|
-
},
|
|
1076
|
-
defaultOptions: [],
|
|
1077
|
-
create(context) {
|
|
1078
|
-
const services = ESLintUtils3.getParserServices(context);
|
|
1079
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1080
|
-
return {
|
|
1081
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1082
|
-
JSXIdentifier(node) {
|
|
1083
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
const isInTagName = node.parent?.type !== AST_NODE_TYPES8.JSXAttribute;
|
|
1087
|
-
if (!isInTagName) {
|
|
1088
|
-
return;
|
|
1089
|
-
}
|
|
1090
|
-
const isCapitalized = !node.name.startsWith(node.name.charAt(0).toLowerCase());
|
|
1091
|
-
if (!isCapitalized) {
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
const isCorrectDynamicTagName = node.name === "DynamicHtmlTag" || node.name === "DynamicSvgTag";
|
|
1095
|
-
if (isCorrectDynamicTagName) {
|
|
1096
|
-
return;
|
|
1097
|
-
}
|
|
1098
|
-
const type = services.getTypeAtLocation(node);
|
|
1099
|
-
const isStringType = type.flags & ts2.TypeFlags.StringLike;
|
|
1100
|
-
if (isStringType) {
|
|
1101
|
-
context.report({
|
|
1102
|
-
messageId: "incorrectDynamicTagName",
|
|
1103
|
-
node
|
|
1104
|
-
});
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
// src/plugins/lumina/rules/no-inline-arrow-in-ref.ts
|
|
1112
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES9 } from "@typescript-eslint/utils";
|
|
1113
|
-
var baseDescription2 = `Do not pass an inline arrow function to a ref prop - such syntax creates a new function on each render, which makes Lit call ref callback again on each render.`;
|
|
1114
|
-
var description8 = `${baseDescription2}
|
|
1115
|
-
|
|
1116
|
-
Alternatives: https://qawebgis.esri.com/components/lumina/jsx#refs`;
|
|
1117
|
-
var noInlineArrowInRef = createRule({
|
|
1118
|
-
name: "no-inline-arrow-in-ref",
|
|
1119
|
-
meta: {
|
|
1120
|
-
docs: {
|
|
1121
|
-
description: baseDescription2,
|
|
1122
|
-
defaultLevel: "error"
|
|
1123
|
-
},
|
|
1124
|
-
messages: {
|
|
1125
|
-
errorInlineArrow: description8
|
|
1126
|
-
},
|
|
1127
|
-
type: "problem",
|
|
1128
|
-
schema: []
|
|
1129
|
-
},
|
|
1130
|
-
defaultOptions: [],
|
|
1131
|
-
create(context) {
|
|
1132
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1133
|
-
return {
|
|
1134
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1135
|
-
JSXAttribute(node) {
|
|
1136
|
-
if (!luminaJsxCheck.isLuminaJsx || node.name.name !== "ref" || node.value?.type !== AST_NODE_TYPES9.JSXExpressionContainer) {
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
const initializer = node.value.expression;
|
|
1140
|
-
if (initializer.type !== AST_NODE_TYPES9.ArrowFunctionExpression && initializer.type !== AST_NODE_TYPES9.FunctionExpression && (initializer.type !== AST_NODE_TYPES9.CallExpression || !isBindThisCallee(initializer.callee))) {
|
|
1141
|
-
return;
|
|
1142
|
-
}
|
|
1143
|
-
context.report({
|
|
1144
|
-
messageId: "errorInlineArrow",
|
|
1145
|
-
node: initializer
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
});
|
|
1151
|
-
|
|
1152
|
-
// src/plugins/lumina/rules/no-invalid-directives-prop.ts
|
|
1153
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES10 } from "@typescript-eslint/utils";
|
|
1154
|
-
var description9 = `directives={} prop value must be an array literal. Documentation: https://qawebgis.esri.com/components/lumina/jsx#lit-directives`;
|
|
1155
|
-
var noInvalidDirectivesProp = createRule({
|
|
1156
|
-
name: "no-invalid-directives-prop",
|
|
1157
|
-
meta: {
|
|
1158
|
-
docs: {
|
|
1159
|
-
description: description9,
|
|
1160
|
-
defaultLevel: "error"
|
|
1161
|
-
},
|
|
1162
|
-
messages: {
|
|
1163
|
-
noInvalidDirectivesProp: description9
|
|
1164
|
-
},
|
|
1165
|
-
type: "problem",
|
|
1166
|
-
schema: []
|
|
1167
|
-
},
|
|
1168
|
-
defaultOptions: [],
|
|
1169
|
-
create(context) {
|
|
1170
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1171
|
-
return {
|
|
1172
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1173
|
-
JSXAttribute(node) {
|
|
1174
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
if (node.name.name !== "directives") {
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
|
-
const array = node.value?.type === AST_NODE_TYPES10.JSXExpressionContainer && node.value.expression.type === AST_NODE_TYPES10.ArrayExpression ? node.value.expression : void 0;
|
|
1181
|
-
if (array === void 0 || array.elements.includes(null)) {
|
|
1182
|
-
context.report({
|
|
1183
|
-
messageId: "noInvalidDirectivesProp",
|
|
1184
|
-
node: node.value ?? node
|
|
1185
|
-
});
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
array.elements.forEach((element) => {
|
|
1189
|
-
if (element?.type === AST_NODE_TYPES10.SpreadElement) {
|
|
1190
|
-
context.report({
|
|
1191
|
-
messageId: "noInvalidDirectivesProp",
|
|
1192
|
-
node: element
|
|
1193
|
-
});
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
});
|
|
1200
|
-
|
|
1201
|
-
// src/plugins/lumina/rules/no-jsx-spread.ts
|
|
1202
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES11 } from "@typescript-eslint/utils";
|
|
1203
|
-
var description10 = `This spread syntax is not supported. Alternatives: https://qawebgis.esri.com/components/lumina/jsx#spread-attributes`;
|
|
1204
|
-
var noJsxSpread = createRule({
|
|
1205
|
-
name: "no-jsx-spread",
|
|
1206
|
-
meta: {
|
|
1207
|
-
docs: {
|
|
1208
|
-
description: description10,
|
|
1209
|
-
defaultLevel: "error"
|
|
1210
|
-
},
|
|
1211
|
-
messages: {
|
|
1212
|
-
noJsxSpread: description10
|
|
1213
|
-
},
|
|
1214
|
-
type: "problem",
|
|
1215
|
-
schema: []
|
|
1216
|
-
},
|
|
1217
|
-
defaultOptions: [],
|
|
1218
|
-
create(context) {
|
|
1219
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1220
|
-
return {
|
|
1221
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1222
|
-
JSXSpreadAttribute(node) {
|
|
1223
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
1224
|
-
return;
|
|
1225
|
-
}
|
|
1226
|
-
const name = node.parent.name;
|
|
1227
|
-
if (
|
|
1228
|
-
// Spread syntax is allowed in function calls like <this.render {...props} />
|
|
1229
|
-
name.type === AST_NODE_TYPES11.JSXIdentifier && // Spread syntax is allowed in functions
|
|
1230
|
-
(name.name.toLowerCase() === name.name || name.name === "DynamicHtmlTag" || name.name === "DynamicSvgTag")
|
|
1231
|
-
) {
|
|
1232
|
-
context.report({
|
|
1233
|
-
messageId: "noJsxSpread",
|
|
1234
|
-
node
|
|
1235
|
-
});
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
});
|
|
1241
|
-
|
|
1242
|
-
// src/plugins/lumina/rules/no-listen-in-connected-callback.ts
|
|
1243
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
|
|
1244
|
-
var baseDescription3 = `Do not call this.listen()/this.listenOn() in connectedCallback.`;
|
|
1245
|
-
var description11 = `${baseDescription3}
|
|
1246
|
-
|
|
1247
|
-
Instead, call this.listen()/this.listenOn() in constructor(), load() or loaded().
|
|
1248
|
-
|
|
1249
|
-
Reason:
|
|
1250
|
-
this.listen() automatically creates and cleanups the listener on connect/disconnect.
|
|
1251
|
-
Since connectedCallback can be called multiple times, duplicate listeners may be created.`;
|
|
1252
|
-
var noListenInConnectedCallback = createRule({
|
|
1253
|
-
name: "no-listen-in-connected-callback",
|
|
1254
|
-
meta: {
|
|
1255
|
-
docs: {
|
|
1256
|
-
description: baseDescription3,
|
|
1257
|
-
defaultLevel: "error"
|
|
1258
|
-
},
|
|
1259
|
-
messages: {
|
|
1260
|
-
errorListenInConnectedCallback: description11
|
|
1261
|
-
},
|
|
1262
|
-
type: "problem",
|
|
1263
|
-
schema: []
|
|
1264
|
-
},
|
|
1265
|
-
defaultOptions: [],
|
|
1266
|
-
create(context) {
|
|
1267
|
-
return {
|
|
1268
|
-
CallExpression(node) {
|
|
1269
|
-
const isListenCall = node.callee.type === AST_NODE_TYPES12.MemberExpression && node.callee.object.type === AST_NODE_TYPES12.ThisExpression && node.callee.property.type === AST_NODE_TYPES12.Identifier && (node.callee.property.name === "listen" || node.callee.property.name === "listenOn");
|
|
1270
|
-
if (!isListenCall) {
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
let hasConnectedCallbackParent = false;
|
|
1274
|
-
let currentParent = node.parent;
|
|
1275
|
-
while (currentParent) {
|
|
1276
|
-
if (currentParent.type === AST_NODE_TYPES12.MethodDefinition) {
|
|
1277
|
-
if (currentParent.key.type === AST_NODE_TYPES12.Identifier && currentParent.key.name === "connectedCallback") {
|
|
1278
|
-
hasConnectedCallbackParent = true;
|
|
1279
|
-
}
|
|
1280
|
-
break;
|
|
1281
|
-
}
|
|
1282
|
-
currentParent = currentParent.parent;
|
|
1283
|
-
}
|
|
1284
|
-
if (!hasConnectedCallbackParent) {
|
|
1285
|
-
return;
|
|
1286
|
-
}
|
|
1287
|
-
context.report({
|
|
1288
|
-
messageId: "errorListenInConnectedCallback",
|
|
1289
|
-
node
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
};
|
|
1293
|
-
}
|
|
1294
|
-
});
|
|
1295
|
-
|
|
1296
|
-
// src/plugins/lumina/rules/no-non-component-exports.ts
|
|
1297
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
|
|
1298
|
-
var description12 = `To ensure Hot Module Replacement (HMR) works correctly, the file that defines the Lumina component must not export anything other than the component. Exceptions: type-only exports, and the \`exportsForTests\` object for exposing additional things for usages in tests only`;
|
|
1299
|
-
var noNonComponentExports = createRule({
|
|
1300
|
-
name: "no-non-component-exports",
|
|
1301
|
-
meta: {
|
|
1302
|
-
docs: {
|
|
1303
|
-
description: description12,
|
|
1304
|
-
defaultLevel: "warn"
|
|
1305
|
-
},
|
|
1306
|
-
messages: {
|
|
1307
|
-
noNonComponentExports: description12,
|
|
1308
|
-
noDefaultExports: `Default exports are not allowed in files that export Lumina component - only named exports are allowed. ${description12}`,
|
|
1309
|
-
noExportAll: `\`export *\` exports are not allowed in files that export Lumina component - only named exports are allowed. ${description12}`
|
|
1310
|
-
},
|
|
1311
|
-
type: "problem",
|
|
1312
|
-
schema: []
|
|
1313
|
-
},
|
|
1314
|
-
defaultOptions: [],
|
|
1315
|
-
create(context) {
|
|
1316
|
-
const declaredComponents = /* @__PURE__ */ new Set();
|
|
1317
|
-
const hasLuminaDeclarations = context.sourceCode.text.includes("interface DeclareElements");
|
|
1318
|
-
return {
|
|
1319
|
-
TSModuleDeclaration(node) {
|
|
1320
|
-
const luminaDeclarationInterface = extractDeclareElementsInterface(node);
|
|
1321
|
-
if (luminaDeclarationInterface === void 0) {
|
|
1322
|
-
return;
|
|
1323
|
-
}
|
|
1324
|
-
luminaDeclarationInterface.body.body.forEach((member) => {
|
|
1325
|
-
if (member.type !== AST_NODE_TYPES13.TSPropertySignature || member.computed) {
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
const type = member.typeAnnotation?.typeAnnotation;
|
|
1329
|
-
if (type?.type !== AST_NODE_TYPES13.TSTypeReference || type.typeName.type !== AST_NODE_TYPES13.Identifier) {
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
const className = type.typeName.name;
|
|
1333
|
-
declaredComponents.add(className);
|
|
1334
|
-
});
|
|
1335
|
-
},
|
|
1336
|
-
ExportNamedDeclaration(node) {
|
|
1337
|
-
if (!hasLuminaDeclarations && declaredComponents.size === 0) {
|
|
1338
|
-
return;
|
|
1339
|
-
}
|
|
1340
|
-
if (node.exportKind === "type") {
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
if (node.declaration?.type === AST_NODE_TYPES13.VariableDeclaration) {
|
|
1344
|
-
const isExportsForTests = node.declaration.declarations.every(
|
|
1345
|
-
(declaration) => declaration.id.type === AST_NODE_TYPES13.Identifier && declaration.id.name === "exportsForTests"
|
|
1346
|
-
);
|
|
1347
|
-
if (isExportsForTests) {
|
|
1348
|
-
return;
|
|
1349
|
-
}
|
|
1350
|
-
} else if (node.declaration?.type === AST_NODE_TYPES13.FunctionDeclaration) {
|
|
1351
|
-
const isExportsForTests = node.declaration.id?.name === "exportsForTests";
|
|
1352
|
-
if (isExportsForTests) {
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
} else if (
|
|
1356
|
-
// Type-only constructs
|
|
1357
|
-
node.declaration?.type === AST_NODE_TYPES13.TSDeclareFunction || node.declaration?.type === AST_NODE_TYPES13.TSInterfaceDeclaration || node.declaration?.type === AST_NODE_TYPES13.TSTypeAliasDeclaration
|
|
1358
|
-
) {
|
|
1359
|
-
return;
|
|
1360
|
-
} else if (node.declaration?.type === AST_NODE_TYPES13.ClassDeclaration) {
|
|
1361
|
-
const isComponent = declaredComponents.has(node.declaration.id?.name ?? "");
|
|
1362
|
-
if (isComponent) {
|
|
1363
|
-
return;
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
context.report({
|
|
1367
|
-
node,
|
|
1368
|
-
messageId: "noNonComponentExports"
|
|
1369
|
-
});
|
|
1370
|
-
},
|
|
1371
|
-
ExportDefaultDeclaration(node) {
|
|
1372
|
-
if (!hasLuminaDeclarations && declaredComponents.size === 0) {
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
context.report({
|
|
1376
|
-
node,
|
|
1377
|
-
messageId: "noDefaultExports"
|
|
1378
|
-
});
|
|
1379
|
-
},
|
|
1380
|
-
ExportAllDeclaration(node) {
|
|
1381
|
-
if (!hasLuminaDeclarations && declaredComponents.size === 0) {
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
if (node.exportKind === "type") {
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
context.report({
|
|
1388
|
-
node,
|
|
1389
|
-
messageId: "noExportAll"
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
|
-
};
|
|
1393
|
-
}
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
// src/plugins/lumina/rules/no-property-name-start-with-on.ts
|
|
1397
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES14 } from "@typescript-eslint/utils";
|
|
1398
|
-
var description13 = `Do not start public property names with "on" as that can confuse frameworks into thinking this property is an event`;
|
|
1399
|
-
var noPropertyNameStartWithOn = createRule({
|
|
1400
|
-
name: "no-property-name-start-with-on",
|
|
1401
|
-
meta: {
|
|
1402
|
-
docs: {
|
|
1403
|
-
description: description13,
|
|
1404
|
-
defaultLevel: "error"
|
|
1405
|
-
},
|
|
1406
|
-
messages: {
|
|
1407
|
-
noPropertyNameStartWithOn: description13
|
|
1408
|
-
},
|
|
1409
|
-
type: "problem",
|
|
1410
|
-
schema: []
|
|
1411
|
-
},
|
|
1412
|
-
defaultOptions: [],
|
|
1413
|
-
create(context) {
|
|
1414
|
-
return {
|
|
1415
|
-
PropertyDefinition(node) {
|
|
1416
|
-
const isPublicProperty = hasDecorator(node, "property");
|
|
1417
|
-
if (!isPublicProperty) {
|
|
1418
|
-
return;
|
|
1419
|
-
}
|
|
1420
|
-
const propertyName = node.key.type === AST_NODE_TYPES14.Identifier ? node.key.name : node.key.type === AST_NODE_TYPES14.Literal ? node.key.value : void 0;
|
|
1421
|
-
if (typeof propertyName !== "string") {
|
|
1422
|
-
return;
|
|
1423
|
-
}
|
|
1424
|
-
if (!propertyName.startsWith("on")) {
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
const comments = context.sourceCode.getCommentsBefore(node);
|
|
1428
|
-
const isDeprecated = comments.some((comment) => comment.value.includes("@deprecated"));
|
|
1429
|
-
if (isDeprecated) {
|
|
1430
|
-
return;
|
|
1431
|
-
}
|
|
1432
|
-
context.report({
|
|
1433
|
-
messageId: "noPropertyNameStartWithOn",
|
|
1434
|
-
node: node.key
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1439
|
-
});
|
|
1440
|
-
|
|
1441
|
-
// src/plugins/lumina/rules/no-render-false.ts
|
|
1442
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES15, ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
|
|
1443
|
-
|
|
1444
|
-
// src/plugins/lumina/utils/checker.ts
|
|
1445
|
-
import ts3 from "typescript";
|
|
1446
|
-
var litTemplateResult = "TemplateResult";
|
|
1447
|
-
var explicitJsxTypeName = "JsxNode";
|
|
1448
|
-
var implicitJsxTypeName = "Element";
|
|
1449
|
-
var implicitJsxParentName = "LuminaJsx";
|
|
1450
|
-
function isLuminaJsxType(type) {
|
|
1451
|
-
for (const declaration of type.aliasSymbol?.declarations ?? []) {
|
|
1452
|
-
if (!ts3.isTypeAliasDeclaration(declaration)) {
|
|
1453
|
-
continue;
|
|
1454
|
-
}
|
|
1455
|
-
const typeName = declaration.name.escapedText;
|
|
1456
|
-
if (typeName === litTemplateResult || typeName === explicitJsxTypeName) {
|
|
1457
|
-
return true;
|
|
1458
|
-
}
|
|
1459
|
-
if (typeName !== implicitJsxTypeName) {
|
|
1460
|
-
continue;
|
|
1461
|
-
}
|
|
1462
|
-
const grandParent = declaration.parent?.parent;
|
|
1463
|
-
if (!ts3.isModuleDeclaration(grandParent)) {
|
|
1464
|
-
continue;
|
|
1465
|
-
}
|
|
1466
|
-
const symbol = grandParent.symbol;
|
|
1467
|
-
if (symbol?.escapedName === implicitJsxParentName) {
|
|
1468
|
-
return true;
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
return false;
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// src/plugins/lumina/rules/no-render-false.ts
|
|
1475
|
-
var baseDescription4 = `Avoid accidentally rendering "false" to the screen (Lit stringifies booleans, rather than drop them like React/Stencil).`;
|
|
1476
|
-
var description14 = `${baseDescription4}
|
|
1477
|
-
|
|
1478
|
-
Lumina automatically handles some cases where "false" may get rendered to the screen, but the pattern this code is using is not handled.`;
|
|
1479
|
-
var noRenderFalse = createRule({
|
|
1480
|
-
name: "no-render-false",
|
|
1481
|
-
meta: {
|
|
1482
|
-
docs: {
|
|
1483
|
-
description: baseDescription4,
|
|
1484
|
-
defaultLevel: "warn"
|
|
1485
|
-
},
|
|
1486
|
-
messages: {
|
|
1487
|
-
errorFalseRendered: description14
|
|
1488
|
-
},
|
|
1489
|
-
type: "problem",
|
|
1490
|
-
schema: [],
|
|
1491
|
-
fixable: "code"
|
|
1492
|
-
},
|
|
1493
|
-
defaultOptions: [],
|
|
1494
|
-
create(context) {
|
|
1495
|
-
const services = ESLintUtils4.getParserServices(context);
|
|
1496
|
-
return {
|
|
1497
|
-
LogicalExpression(node) {
|
|
1498
|
-
if (node.operator !== "&&") {
|
|
1499
|
-
return;
|
|
1500
|
-
}
|
|
1501
|
-
const type = services.getTypeAtLocation(node.right);
|
|
1502
|
-
if (!isLuminaJsxType(type)) {
|
|
1503
|
-
return;
|
|
1504
|
-
}
|
|
1505
|
-
if (node.parent.type === AST_NODE_TYPES15.JSXExpressionContainer) {
|
|
1506
|
-
return;
|
|
1507
|
-
}
|
|
1508
|
-
const right = unwrapExpression(node.right);
|
|
1509
|
-
if (right.type === AST_NODE_TYPES15.JSXElement) {
|
|
1510
|
-
return;
|
|
1511
|
-
}
|
|
1512
|
-
if (node.parent.type === AST_NODE_TYPES15.LogicalExpression) {
|
|
1513
|
-
return;
|
|
1514
|
-
}
|
|
1515
|
-
context.report({
|
|
1516
|
-
messageId: "errorFalseRendered",
|
|
1517
|
-
node,
|
|
1518
|
-
fix(fixer) {
|
|
1519
|
-
const leftText = context.sourceCode.getText(node.left);
|
|
1520
|
-
const rightText = context.sourceCode.getText(node.right);
|
|
1521
|
-
const replacement = `${leftText} ? ${rightText} : ""`;
|
|
1522
|
-
return fixer.replaceText(node, replacement);
|
|
1523
|
-
}
|
|
1524
|
-
});
|
|
1525
|
-
}
|
|
1526
|
-
};
|
|
1527
|
-
}
|
|
1528
|
-
});
|
|
1529
|
-
|
|
1530
|
-
// src/plugins/lumina/rules/no-unnecessary-attribute-name.ts
|
|
1531
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES16 } from "@typescript-eslint/utils";
|
|
1532
|
-
import { camelToKebab } from "@arcgis/components-utils";
|
|
1533
|
-
var description15 = 'There is no need for { attribute: "name" } in @property() when attribute name is trivially inferrable from the property name';
|
|
1534
|
-
var noUnnecessaryAttributeName = createRule({
|
|
1535
|
-
name: "no-unnecessary-attribute-name",
|
|
1536
|
-
meta: {
|
|
1537
|
-
docs: {
|
|
1538
|
-
description: description15,
|
|
1539
|
-
defaultLevel: "warn"
|
|
1540
|
-
},
|
|
1541
|
-
messages: {
|
|
1542
|
-
noUnnecessaryAttributeName: description15
|
|
1543
|
-
},
|
|
1544
|
-
type: "suggestion",
|
|
1545
|
-
schema: [],
|
|
1546
|
-
fixable: "code"
|
|
1547
|
-
},
|
|
1548
|
-
defaultOptions: [],
|
|
1549
|
-
create(context) {
|
|
1550
|
-
return {
|
|
1551
|
-
Decorator(decorator) {
|
|
1552
|
-
const part = parsePropertyDecorator(decorator);
|
|
1553
|
-
if (part === void 0) {
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
const { properties } = part;
|
|
1557
|
-
const property = decorator.parent;
|
|
1558
|
-
if (property?.type !== AST_NODE_TYPES16.MethodDefinition && property?.type !== AST_NODE_TYPES16.PropertyDefinition) {
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
const attributeOption = getProperty(properties, "attribute");
|
|
1562
|
-
const attributeValue = attributeOption?.type === AST_NODE_TYPES16.Literal && typeof attributeOption.value === "string" ? attributeOption.value : void 0;
|
|
1563
|
-
if (attributeOption === void 0 || attributeValue === void 0) {
|
|
1564
|
-
return;
|
|
1565
|
-
}
|
|
1566
|
-
const propertyName = getName(property);
|
|
1567
|
-
if (propertyName === void 0) {
|
|
1568
|
-
return;
|
|
1569
|
-
}
|
|
1570
|
-
const inferredName = camelToKebab(propertyName);
|
|
1571
|
-
if (attributeValue === inferredName) {
|
|
1572
|
-
context.report({
|
|
1573
|
-
node: attributeOption,
|
|
1574
|
-
messageId: "noUnnecessaryAttributeName",
|
|
1575
|
-
fix(fixer) {
|
|
1576
|
-
const nextToken = context.sourceCode.getTokenAfter(attributeOption.parent);
|
|
1577
|
-
const isTrailingComma = nextToken && nextToken.value === ",";
|
|
1578
|
-
return isTrailingComma ? fixer.removeRange([attributeOption.parent.range[0], nextToken.range[1]]) : fixer.remove(attributeOption.parent);
|
|
1579
|
-
}
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
};
|
|
1584
|
-
}
|
|
1585
|
-
});
|
|
1586
|
-
|
|
1587
|
-
// src/plugins/lumina/rules/no-unnecessary-bind-this.ts
|
|
1588
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES17 } from "@typescript-eslint/utils";
|
|
1589
|
-
var description16 = `.bind(this) is not necessary in Lit's event listener callbacks and ref callbacks as it is handled automatically.`;
|
|
1590
|
-
var noUnnecessaryBindThis = createRule({
|
|
1591
|
-
name: "no-unnecessary-bind-this",
|
|
1592
|
-
meta: {
|
|
1593
|
-
docs: {
|
|
1594
|
-
description: description16,
|
|
1595
|
-
defaultLevel: "warn"
|
|
1596
|
-
},
|
|
1597
|
-
messages: {
|
|
1598
|
-
noUnnecessaryBindThis: description16
|
|
1599
|
-
},
|
|
1600
|
-
type: "problem",
|
|
1601
|
-
schema: [],
|
|
1602
|
-
fixable: "code"
|
|
1603
|
-
},
|
|
1604
|
-
defaultOptions: [],
|
|
1605
|
-
create(context) {
|
|
1606
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1607
|
-
return {
|
|
1608
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1609
|
-
JSXExpressionContainer(node) {
|
|
1610
|
-
if (!luminaJsxCheck.isLuminaJsx || node.parent.type !== AST_NODE_TYPES17.JSXAttribute || node.parent.name.type !== AST_NODE_TYPES17.JSXIdentifier) {
|
|
1611
|
-
return;
|
|
1612
|
-
}
|
|
1613
|
-
const name = node.parent.name.name;
|
|
1614
|
-
const isAutoBindable = name.startsWith("on") || name === "ref";
|
|
1615
|
-
if (!isAutoBindable) {
|
|
1616
|
-
return;
|
|
1617
|
-
}
|
|
1618
|
-
const expression = node.expression.type === AST_NODE_TYPES17.ChainExpression ? node.expression.expression : node.expression;
|
|
1619
|
-
const isCallWithThis = (
|
|
1620
|
-
// expression(...)
|
|
1621
|
-
expression.type === AST_NODE_TYPES17.CallExpression && // expression(expression)
|
|
1622
|
-
expression.arguments.length === 1 && // expression(this)
|
|
1623
|
-
expression.arguments[0].type === AST_NODE_TYPES17.ThisExpression
|
|
1624
|
-
);
|
|
1625
|
-
if (!isCallWithThis) {
|
|
1626
|
-
return;
|
|
1627
|
-
}
|
|
1628
|
-
const callee = expression.callee;
|
|
1629
|
-
if (!isBindThisCallee(callee)) {
|
|
1630
|
-
return;
|
|
1631
|
-
}
|
|
1632
|
-
const tagName = context.sourceCode.getAncestors(node.parent).find((ancestor) => ancestor.type === AST_NODE_TYPES17.JSXOpeningElement)?.name;
|
|
1633
|
-
const tagNameString = tagName?.type === AST_NODE_TYPES17.JSXIdentifier ? tagName.name : void 0;
|
|
1634
|
-
if (tagNameString === void 0) {
|
|
1635
|
-
return;
|
|
1636
|
-
}
|
|
1637
|
-
const isHtmlElement = tagNameString.startsWith(tagNameString.charAt(0).toLowerCase()) || tagNameString === "DynamicHtmlTag" || tagNameString === "DynamicSvgTag";
|
|
1638
|
-
if (!isHtmlElement) {
|
|
1639
|
-
return;
|
|
1640
|
-
}
|
|
1641
|
-
context.report({
|
|
1642
|
-
messageId: "noUnnecessaryBindThis",
|
|
1643
|
-
node: callee.property,
|
|
1644
|
-
fix(fixer) {
|
|
1645
|
-
return fixer.replaceText(expression, context.sourceCode.getText(callee.object));
|
|
1646
|
-
}
|
|
1647
|
-
});
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
});
|
|
1652
|
-
|
|
1653
|
-
// src/plugins/lumina/rules/no-unnecessary-key.ts
|
|
1654
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES18 } from "@typescript-eslint/utils";
|
|
1655
|
-
var description17 = `In most cases, key={index} is not necessary in Lumina in .map(). Details: https://qawebgis.esri.com/components/lumina/jsx#key-prop`;
|
|
1656
|
-
var noUnnecessaryKey = createRule({
|
|
1657
|
-
name: "no-unnecessary-key",
|
|
1658
|
-
meta: {
|
|
1659
|
-
docs: {
|
|
1660
|
-
description: description17,
|
|
1661
|
-
defaultLevel: "warn"
|
|
1662
|
-
},
|
|
1663
|
-
messages: {
|
|
1664
|
-
noUnnecessaryKey: description17
|
|
1665
|
-
},
|
|
1666
|
-
type: "suggestion",
|
|
1667
|
-
schema: [],
|
|
1668
|
-
fixable: "code"
|
|
1669
|
-
},
|
|
1670
|
-
defaultOptions: [],
|
|
1671
|
-
create(context) {
|
|
1672
|
-
const luminaJsxCheck = checkForLuminaJsx();
|
|
1673
|
-
return {
|
|
1674
|
-
ImportDeclaration: luminaJsxCheck,
|
|
1675
|
-
JSXExpressionContainer(node) {
|
|
1676
|
-
if (!luminaJsxCheck.isLuminaJsx) {
|
|
1677
|
-
return;
|
|
1678
|
-
}
|
|
1679
|
-
const keyValue = node.expression;
|
|
1680
|
-
if (keyValue.type !== AST_NODE_TYPES18.Identifier) {
|
|
1681
|
-
return;
|
|
1682
|
-
}
|
|
1683
|
-
const keyAttribute = node.parent;
|
|
1684
|
-
if (keyAttribute?.type !== AST_NODE_TYPES18.JSXAttribute || keyAttribute.name.type !== AST_NODE_TYPES18.JSXIdentifier || keyAttribute.name.name !== "key") {
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
|
-
const mapArrowFunction = context.sourceCode.getAncestors(keyAttribute).find(
|
|
1688
|
-
(ancestor) => ancestor.type === AST_NODE_TYPES18.ArrowFunctionExpression && ancestor.parent?.type === AST_NODE_TYPES18.CallExpression && ancestor.parent?.callee.type === AST_NODE_TYPES18.MemberExpression && ancestor.parent?.callee.property.type === AST_NODE_TYPES18.Identifier && ancestor.parent?.callee.property.name === "map"
|
|
1689
|
-
);
|
|
1690
|
-
if (mapArrowFunction === void 0) {
|
|
1691
|
-
return;
|
|
1692
|
-
}
|
|
1693
|
-
const keyParameter = mapArrowFunction.params.at(1);
|
|
1694
|
-
if (keyParameter?.type !== AST_NODE_TYPES18.Identifier || keyParameter.name !== keyValue.name) {
|
|
1695
|
-
return;
|
|
1696
|
-
}
|
|
1697
|
-
context.report({
|
|
1698
|
-
messageId: "noUnnecessaryKey",
|
|
1699
|
-
node: keyAttribute,
|
|
1700
|
-
fix(fixer) {
|
|
1701
|
-
const usesIndexOutsideKey = Array.from(
|
|
1702
|
-
context.sourceCode.getText(mapArrowFunction.body).matchAll(new RegExp(`\\b${keyValue.name}\\b`, "ug"))
|
|
1703
|
-
).length > 1;
|
|
1704
|
-
const withoutAttribute = fixer.remove(keyAttribute);
|
|
1705
|
-
if (usesIndexOutsideKey || mapArrowFunction.params.length > 2) {
|
|
1706
|
-
return withoutAttribute;
|
|
1707
|
-
} else {
|
|
1708
|
-
return [withoutAttribute, fixer.remove(keyParameter)];
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
});
|
|
1712
|
-
}
|
|
1713
|
-
};
|
|
1714
|
-
}
|
|
1715
|
-
});
|
|
1716
|
-
|
|
1717
|
-
// src/plugins/lumina/rules/tag-name-rules.ts
|
|
1718
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES19 } from "@typescript-eslint/utils";
|
|
1719
|
-
var description18 = `Validate component tag name`;
|
|
1720
|
-
var defaultOptions2 = [
|
|
1721
|
-
{
|
|
1722
|
-
namespaces: ["arcgis-"]
|
|
1723
|
-
}
|
|
1724
|
-
];
|
|
1725
|
-
var tagNameRules = createRule({
|
|
1726
|
-
name: "tag-name-rules",
|
|
1727
|
-
meta: {
|
|
1728
|
-
docs: {
|
|
1729
|
-
description: description18,
|
|
1730
|
-
defaultLevel: "error"
|
|
1731
|
-
},
|
|
1732
|
-
messages: {
|
|
1733
|
-
requireNamespace: "Custom element tag names in this project must start with one of the following namespaces: {{namespaces}}",
|
|
1734
|
-
noComputedTagName: "Computed tag names are not allowed",
|
|
1735
|
-
noNonStringTagName: 'Tag names must be strings like "arcgis-click" rather than numbers',
|
|
1736
|
-
noTagNameIdentifier: "Tag name must include a dash",
|
|
1737
|
-
unexpectedDeclareElementsEntry: "Unexpected entry in declare elements interface. Expected a property signature",
|
|
1738
|
-
unexpectedDeclarationType: "Unexpected declaration type. Expected component class identifier",
|
|
1739
|
-
duplicateDeclaration: "The same component may only be assigned to one class name. If you need multiple tag names, consider sub-classing the component",
|
|
1740
|
-
missingClassDeclaration: "Missing class declaration",
|
|
1741
|
-
unexpectedTypeArguments: "Unexpected type arguments in the component tag name declaration. Type arguments should be specified in the component class declaration",
|
|
1742
|
-
reservedTagName: "This is a reserved html element tag name. Declaring components with this name is forbidden by the custom elements specification.",
|
|
1743
|
-
duplicateDeclareGlobal: `There should only be a single "declare global" block in a file. Declaring multiple components in a single file is supported, but they should share the same "declare global {" block. Example:
|
|
1744
|
-
declare global {
|
|
1745
|
-
interface DeclareElements {
|
|
1746
|
-
"arcgis-test1": ArcgisTest1;
|
|
1747
|
-
"arcgis-test2": ArcgisTest2;
|
|
1748
|
-
}
|
|
1749
|
-
}`,
|
|
1750
|
-
mustSubclass: "Lumina component is required to subclass LitElement or a subclass of LitElement",
|
|
1751
|
-
mustNotSubclassHtmlElement: "Lumina component is not allowed to subclass HTMLElement classes directly. Subclass LitElement or a subclass of LitElement instead",
|
|
1752
|
-
tagNameClassNameMismatch: 'The custom element tag name "{{tagName}}" does not seem to match the class name it is assigned to: "{{className}}". Make sure tag name and class name use the same characters in the same order (case insensitive, hyphens removed). {{namespaceNotice}}',
|
|
1753
|
-
missingHyphen: "Custom element tag names need to include a hyphen",
|
|
1754
|
-
lowercaseTagName: "For consistency, custom element tag names should be defined in lowercase",
|
|
1755
|
-
invalidTagName: "Potentially invalid custom element name. Expected tag name to match regex: {{regex}}. This regex is stricter than what the custom elements spec allows in order to catch possible typos. Please contact Lumina maintainers if you need to loosen this check."
|
|
1756
|
-
},
|
|
1757
|
-
type: "problem",
|
|
1758
|
-
schema: [
|
|
1759
|
-
{
|
|
1760
|
-
type: "object",
|
|
1761
|
-
properties: {
|
|
1762
|
-
namespaces: {
|
|
1763
|
-
type: "array",
|
|
1764
|
-
items: {
|
|
1765
|
-
type: "string"
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
},
|
|
1769
|
-
additionalProperties: false
|
|
1770
|
-
}
|
|
1771
|
-
],
|
|
1772
|
-
fixable: "code"
|
|
1773
|
-
},
|
|
1774
|
-
defaultOptions: defaultOptions2,
|
|
1775
|
-
create(context, options) {
|
|
1776
|
-
const declaredComponents = /* @__PURE__ */ new Map();
|
|
1777
|
-
let seenDeclareGlobal = false;
|
|
1778
|
-
return {
|
|
1779
|
-
"TSModuleDeclaration"(node) {
|
|
1780
|
-
const luminaDeclarationInterface = extractDeclareElementsInterface(node);
|
|
1781
|
-
if (luminaDeclarationInterface === void 0) {
|
|
1782
|
-
return;
|
|
1783
|
-
}
|
|
1784
|
-
if (seenDeclareGlobal) {
|
|
1785
|
-
context.report({
|
|
1786
|
-
messageId: "duplicateDeclareGlobal",
|
|
1787
|
-
node
|
|
1788
|
-
});
|
|
1789
|
-
return;
|
|
1790
|
-
}
|
|
1791
|
-
seenDeclareGlobal = true;
|
|
1792
|
-
luminaDeclarationInterface.body.body.forEach((member) => {
|
|
1793
|
-
if (member.type !== AST_NODE_TYPES19.TSPropertySignature) {
|
|
1794
|
-
context.report({
|
|
1795
|
-
messageId: "unexpectedDeclareElementsEntry",
|
|
1796
|
-
node: member
|
|
1797
|
-
});
|
|
1798
|
-
return;
|
|
1799
|
-
}
|
|
1800
|
-
if (member.computed) {
|
|
1801
|
-
context.report({
|
|
1802
|
-
messageId: "noComputedTagName",
|
|
1803
|
-
node: member.key
|
|
1804
|
-
});
|
|
1805
|
-
return;
|
|
1806
|
-
}
|
|
1807
|
-
if (member.key.type === AST_NODE_TYPES19.Identifier) {
|
|
1808
|
-
context.report({
|
|
1809
|
-
messageId: "noTagNameIdentifier",
|
|
1810
|
-
node: member.key
|
|
1811
|
-
});
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
if (typeof member.key.value !== "string") {
|
|
1815
|
-
context.report({
|
|
1816
|
-
messageId: "noNonStringTagName",
|
|
1817
|
-
node: member.key
|
|
1818
|
-
});
|
|
1819
|
-
return;
|
|
1820
|
-
}
|
|
1821
|
-
const tagName = member.key.value;
|
|
1822
|
-
let namespaceFreeTagName = tagName;
|
|
1823
|
-
const namespaces = options[0].namespaces;
|
|
1824
|
-
if (namespaces.length > 0) {
|
|
1825
|
-
const namespace = namespaces.find((ns) => tagName.startsWith(ns));
|
|
1826
|
-
if (namespace === void 0) {
|
|
1827
|
-
context.report({
|
|
1828
|
-
messageId: "requireNamespace",
|
|
1829
|
-
node: member.key,
|
|
1830
|
-
data: {
|
|
1831
|
-
namespaces: namespaces.join(", ")
|
|
1832
|
-
}
|
|
1833
|
-
});
|
|
1834
|
-
return;
|
|
1835
|
-
} else {
|
|
1836
|
-
namespaceFreeTagName = tagName.slice(namespace.length);
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
if (!tagName.includes("-")) {
|
|
1840
|
-
context.report({
|
|
1841
|
-
messageId: "missingHyphen",
|
|
1842
|
-
node: member.key
|
|
1843
|
-
});
|
|
1844
|
-
return;
|
|
1845
|
-
}
|
|
1846
|
-
if (tagName.toLowerCase() !== tagName) {
|
|
1847
|
-
context.report({
|
|
1848
|
-
messageId: "lowercaseTagName",
|
|
1849
|
-
node: member.key
|
|
1850
|
-
});
|
|
1851
|
-
return;
|
|
1852
|
-
}
|
|
1853
|
-
if (!reCustomElementName.test(tagName)) {
|
|
1854
|
-
context.report({
|
|
1855
|
-
messageId: "invalidTagName",
|
|
1856
|
-
node: member.key,
|
|
1857
|
-
data: {
|
|
1858
|
-
regex: reCustomElementName.toString()
|
|
1859
|
-
}
|
|
1860
|
-
});
|
|
1861
|
-
return;
|
|
1862
|
-
}
|
|
1863
|
-
if (blockListedCustomElementNames.has(tagName)) {
|
|
1864
|
-
context.report({
|
|
1865
|
-
messageId: "reservedTagName",
|
|
1866
|
-
node: member.key
|
|
1867
|
-
});
|
|
1868
|
-
return;
|
|
1869
|
-
}
|
|
1870
|
-
const type = member.typeAnnotation?.typeAnnotation;
|
|
1871
|
-
if (type?.type !== AST_NODE_TYPES19.TSTypeReference || type.typeName.type !== AST_NODE_TYPES19.Identifier) {
|
|
1872
|
-
context.report({
|
|
1873
|
-
messageId: "unexpectedDeclarationType",
|
|
1874
|
-
node: type ?? member
|
|
1875
|
-
});
|
|
1876
|
-
return;
|
|
1877
|
-
}
|
|
1878
|
-
if (type.typeArguments !== void 0) {
|
|
1879
|
-
context.report({
|
|
1880
|
-
messageId: "unexpectedTypeArguments",
|
|
1881
|
-
node: type
|
|
1882
|
-
});
|
|
1883
|
-
return;
|
|
1884
|
-
}
|
|
1885
|
-
const className = type.typeName.name;
|
|
1886
|
-
const classNameFromTagName = tagNameToNormalizedClassName(tagName);
|
|
1887
|
-
const classNameFromShortTagName = tagNameToNormalizedClassName(namespaceFreeTagName);
|
|
1888
|
-
if (classNameFromTagName !== className.toLowerCase() && classNameFromShortTagName !== className.toLowerCase()) {
|
|
1889
|
-
context.report({
|
|
1890
|
-
messageId: "tagNameClassNameMismatch",
|
|
1891
|
-
node: type.typeName,
|
|
1892
|
-
data: {
|
|
1893
|
-
tagName,
|
|
1894
|
-
className,
|
|
1895
|
-
namespaceNotice: namespaces.length > 0 ? `In addition, the following tag name prefixes are expected: ${namespaces.join(", ")}` : ""
|
|
1896
|
-
}
|
|
1897
|
-
});
|
|
1898
|
-
return;
|
|
1899
|
-
}
|
|
1900
|
-
if (declaredComponents.has(className)) {
|
|
1901
|
-
context.report({
|
|
1902
|
-
messageId: "duplicateDeclaration",
|
|
1903
|
-
node: type.typeName
|
|
1904
|
-
});
|
|
1905
|
-
return;
|
|
1906
|
-
}
|
|
1907
|
-
declaredComponents.set(className, type.typeName);
|
|
1908
|
-
});
|
|
1909
|
-
},
|
|
1910
|
-
"ClassDeclaration"(node) {
|
|
1911
|
-
if (node.id !== null && declaredComponents.has(node.id.name)) {
|
|
1912
|
-
declaredComponents.delete(node.id.name);
|
|
1913
|
-
if (node.superClass === null) {
|
|
1914
|
-
context.report({
|
|
1915
|
-
messageId: "mustSubclass",
|
|
1916
|
-
node
|
|
1917
|
-
});
|
|
1918
|
-
} else if (node.superClass.type === AST_NODE_TYPES19.Identifier && node.superClass.name.startsWith("HTML") && node.superClass.name.endsWith("Element")) {
|
|
1919
|
-
context.report({
|
|
1920
|
-
messageId: "mustNotSubclassHtmlElement",
|
|
1921
|
-
node
|
|
1922
|
-
});
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
},
|
|
1926
|
-
"Program:exit"() {
|
|
1927
|
-
for (const identifier of declaredComponents.values()) {
|
|
1928
|
-
context.report({
|
|
1929
|
-
messageId: "missingClassDeclaration",
|
|
1930
|
-
node: identifier
|
|
1931
|
-
});
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
});
|
|
1937
|
-
var blockListedCustomElementNames = /* @__PURE__ */ new Set([
|
|
1938
|
-
"annotation-xml",
|
|
1939
|
-
"color-profile",
|
|
1940
|
-
"font-face",
|
|
1941
|
-
"font-face-src",
|
|
1942
|
-
"font-face-uri",
|
|
1943
|
-
"font-face-format",
|
|
1944
|
-
"font-face-name",
|
|
1945
|
-
"missing-glyph"
|
|
1946
|
-
]);
|
|
1947
|
-
var tagNameToNormalizedClassName = (tagName) => tagName.replaceAll("-", "").toLowerCase();
|
|
1948
|
-
var reCustomElementName = /^[a-z]+(?:-[a-z\d]+)+$/u;
|
|
1949
|
-
|
|
1950
|
-
// src/plugins/lumina/index.ts
|
|
1951
|
-
var lumina_default = makeEslintPlugin("lumina", {
|
|
1952
|
-
"add-missing-jsx-import": addMissingJsxImport,
|
|
1953
|
-
"auto-add-type": autoAddType,
|
|
1954
|
-
"component-placement-rules": componentPlacementRules,
|
|
1955
|
-
"consistent-event-naming": consistentEventNaming,
|
|
1956
|
-
"decorators-context": decoratorsContext,
|
|
1957
|
-
"member-ordering": memberOrdering,
|
|
1958
|
-
"no-ignore-jsdoc-tag": noIgnoreJsDocTag,
|
|
1959
|
-
"no-incorrect-dynamic-tag-name": noIncorrectDynamicTagName,
|
|
1960
|
-
"no-inline-arrow-in-ref": noInlineArrowInRef,
|
|
1961
|
-
"no-invalid-directives-prop": noInvalidDirectivesProp,
|
|
1962
|
-
"no-jsx-spread": noJsxSpread,
|
|
1963
|
-
"no-listen-in-connected-callback": noListenInConnectedCallback,
|
|
1964
|
-
"no-non-component-exports": noNonComponentExports,
|
|
1965
|
-
"no-property-name-start-with-on": noPropertyNameStartWithOn,
|
|
1966
|
-
"no-render-false": noRenderFalse,
|
|
1967
|
-
"no-unnecessary-attribute-name": noUnnecessaryAttributeName,
|
|
1968
|
-
"no-unnecessary-bind-this": noUnnecessaryBindThis,
|
|
1969
|
-
"no-unnecessary-key": noUnnecessaryKey,
|
|
1970
|
-
"tag-name-rules": tagNameRules
|
|
1971
|
-
});
|
|
1972
|
-
|
|
1973
|
-
export {
|
|
1974
|
-
lumina_default
|
|
1975
|
-
};
|