@cedarjs/eslint-plugin 9.0.0-canary.1784 → 9.0.0-canary.3124
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/cell-type-annotations.d.ts +3 -0
- package/dist/cell-type-annotations.d.ts.map +1 -0
- package/dist/cell-type-annotations.js +348 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -36
- package/dist/process-env-computed.js +6 -30
- package/dist/service-type-annotations.js +10 -34
- package/dist/unsupported-route-components.js +11 -35
- package/package.json +14 -11
- package/LICENSE +0 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cell-type-annotations.d.ts","sourceRoot":"","sources":["../src/cell-type-annotations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAA;AAwHlE,eAAO,MAAM,mBAAmB,8GAiZ9B,CAAA"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
3
|
+
const createRule = ESLintUtils.RuleCreator.withoutDocs;
|
|
4
|
+
const LIFECYCLE_EXPORTS = /* @__PURE__ */ new Set(["beforeQuery", "afterQuery", "isEmpty"]);
|
|
5
|
+
const RENDER_PROP_EXPORTS = /* @__PURE__ */ new Set(["Loading", "Failure", "Success"]);
|
|
6
|
+
function getParamPattern(param) {
|
|
7
|
+
return param.type === AST_NODE_TYPES.AssignmentPattern ? param.left : param;
|
|
8
|
+
}
|
|
9
|
+
function paramHasTypeAnnotation(param) {
|
|
10
|
+
const pattern = getParamPattern(param);
|
|
11
|
+
return "typeAnnotation" in pattern && !!pattern.typeAnnotation;
|
|
12
|
+
}
|
|
13
|
+
function getParamsClosingParen(sourceCode, fn) {
|
|
14
|
+
if (fn.params.length > 0) {
|
|
15
|
+
const lastParam = fn.params[fn.params.length - 1];
|
|
16
|
+
return sourceCode.getTokenAfter(lastParam, (token) => token.value === ")");
|
|
17
|
+
}
|
|
18
|
+
return sourceCode.getFirstToken(fn, (token) => token.value === ")");
|
|
19
|
+
}
|
|
20
|
+
function isUnparenthesizedArrowParam(fn, param, sourceCode) {
|
|
21
|
+
if (fn.type !== AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (fn.params.length !== 1 || fn.params[0] !== param) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return sourceCode.getTokenBefore(param)?.value !== "(";
|
|
28
|
+
}
|
|
29
|
+
function* insertWrappedAnnotations(fixer, param, paramTypeText, returnTypeText) {
|
|
30
|
+
yield fixer.insertTextBefore(param, "(");
|
|
31
|
+
const paramPart = paramTypeText ? `: ${paramTypeText}` : "";
|
|
32
|
+
const returnPart = returnTypeText ? `: ${returnTypeText}` : "";
|
|
33
|
+
yield fixer.insertTextAfter(param, `${paramPart})${returnPart}`);
|
|
34
|
+
}
|
|
35
|
+
function extractTypedDocumentNodeArgs(typeAnnotation, sourceCode) {
|
|
36
|
+
const type = typeAnnotation?.typeAnnotation;
|
|
37
|
+
if (type?.type !== AST_NODE_TYPES.TSTypeReference) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (type.typeName.type !== AST_NODE_TYPES.Identifier || type.typeName.name !== "TypedDocumentNode") {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const args = type.typeArguments?.params;
|
|
44
|
+
if (!args || args.length < 2) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
data: sourceCode.getText(args[0]),
|
|
49
|
+
variables: sourceCode.getText(args[1])
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function isImportSpecifier(specifier) {
|
|
53
|
+
return specifier.type === AST_NODE_TYPES.ImportSpecifier;
|
|
54
|
+
}
|
|
55
|
+
const cellTypeAnnotations = createRule({
|
|
56
|
+
meta: {
|
|
57
|
+
type: "suggestion",
|
|
58
|
+
docs: {
|
|
59
|
+
description: "Sets the types on a Cell file's lifecycle hooks and render props to the correct @cedarjs/web Cell types"
|
|
60
|
+
},
|
|
61
|
+
messages: {
|
|
62
|
+
needsTypeAnnotation: "The `{{name}}` {{kind}} needs a type annotation of `{{typeName}}` ({{location}}).",
|
|
63
|
+
beforeQueryParamNeedsType: "`beforeQuery`'s first parameter needs a type annotation. Cedar infers the Cell's external props from it, so leaving it untyped degrades type checking at every call site of this Cell."
|
|
64
|
+
},
|
|
65
|
+
fixable: "code",
|
|
66
|
+
schema: []
|
|
67
|
+
},
|
|
68
|
+
defaultOptions: [],
|
|
69
|
+
create(context) {
|
|
70
|
+
const sourceCode = context.sourceCode;
|
|
71
|
+
const filename = basename(context.filename);
|
|
72
|
+
const filenameIndicatesCell = filename.endsWith("Cell.tsx");
|
|
73
|
+
let hasQueryOrFragment = false;
|
|
74
|
+
let hasSuccessExport = false;
|
|
75
|
+
let derivedQueryTypes = null;
|
|
76
|
+
let webTypeImport = null;
|
|
77
|
+
const importedWebTypeNames = /* @__PURE__ */ new Set();
|
|
78
|
+
const checks = [];
|
|
79
|
+
const claimedImportNames = /* @__PURE__ */ new Set();
|
|
80
|
+
function needsImportEdit(importName) {
|
|
81
|
+
if (!importName) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (importedWebTypeNames.has(importName)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (claimedImportNames.has(importName)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
claimedImportNames.add(importName);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function* importEdit(fixer, importName) {
|
|
94
|
+
const specifiers = webTypeImport?.specifiers.filter(isImportSpecifier) ?? [];
|
|
95
|
+
const lastSpecifier = specifiers[specifiers.length - 1];
|
|
96
|
+
if (lastSpecifier) {
|
|
97
|
+
yield fixer.insertTextAfter(lastSpecifier, `, ${importName}`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
yield fixer.insertTextBeforeRange(
|
|
101
|
+
[0, 0],
|
|
102
|
+
`import type { ${importName} } from '@cedarjs/web'
|
|
103
|
+
`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
function checkBeforeQuery(fn, reportNode) {
|
|
107
|
+
const variablesType = derivedQueryTypes?.variables ?? "Record<string, unknown>";
|
|
108
|
+
if (!fn.returnType) {
|
|
109
|
+
const typeName = `CellBeforeQueryResult<${variablesType}>`;
|
|
110
|
+
const shouldImport = needsImportEdit("CellBeforeQueryResult");
|
|
111
|
+
context.report({
|
|
112
|
+
node: reportNode,
|
|
113
|
+
messageId: "needsTypeAnnotation",
|
|
114
|
+
data: {
|
|
115
|
+
name: "beforeQuery",
|
|
116
|
+
typeName,
|
|
117
|
+
kind: "function",
|
|
118
|
+
location: "return type"
|
|
119
|
+
},
|
|
120
|
+
*fix(fixer) {
|
|
121
|
+
const [firstParam2] = fn.params;
|
|
122
|
+
if (firstParam2 && isUnparenthesizedArrowParam(fn, firstParam2, sourceCode)) {
|
|
123
|
+
yield* insertWrappedAnnotations(fixer, firstParam2, null, typeName);
|
|
124
|
+
} else {
|
|
125
|
+
const closingParen = getParamsClosingParen(sourceCode, fn);
|
|
126
|
+
if (!closingParen) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
yield fixer.insertTextAfter(closingParen, `: ${typeName}`);
|
|
130
|
+
}
|
|
131
|
+
if (shouldImport) {
|
|
132
|
+
yield* importEdit(fixer, "CellBeforeQueryResult");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const firstParam = fn.params[0];
|
|
138
|
+
if (firstParam && !paramHasTypeAnnotation(firstParam)) {
|
|
139
|
+
context.report({
|
|
140
|
+
node: reportNode,
|
|
141
|
+
messageId: "beforeQueryParamNeedsType"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function checkAfterQuery(fn, reportNode) {
|
|
146
|
+
const firstParam = fn.params[0];
|
|
147
|
+
const missingParam = !!firstParam && !paramHasTypeAnnotation(firstParam);
|
|
148
|
+
if (!missingParam) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const shouldImport = needsImportEdit("DataObject");
|
|
152
|
+
context.report({
|
|
153
|
+
node: reportNode,
|
|
154
|
+
messageId: "needsTypeAnnotation",
|
|
155
|
+
data: {
|
|
156
|
+
name: "afterQuery",
|
|
157
|
+
typeName: "DataObject",
|
|
158
|
+
kind: "function",
|
|
159
|
+
location: "parameter"
|
|
160
|
+
},
|
|
161
|
+
*fix(fixer) {
|
|
162
|
+
if (firstParam && isUnparenthesizedArrowParam(fn, firstParam, sourceCode)) {
|
|
163
|
+
yield* insertWrappedAnnotations(
|
|
164
|
+
fixer,
|
|
165
|
+
firstParam,
|
|
166
|
+
"DataObject",
|
|
167
|
+
null
|
|
168
|
+
);
|
|
169
|
+
} else if (firstParam) {
|
|
170
|
+
yield fixer.insertTextAfter(
|
|
171
|
+
getParamPattern(firstParam),
|
|
172
|
+
": DataObject"
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
if (shouldImport) {
|
|
176
|
+
yield* importEdit(fixer, "DataObject");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function checkIsEmpty(fn, reportNode) {
|
|
182
|
+
const [responseParam, optionsParam] = fn.params;
|
|
183
|
+
const missingResponseType = !!responseParam && !paramHasTypeAnnotation(responseParam);
|
|
184
|
+
const missingOptionsType = !!optionsParam && !paramHasTypeAnnotation(optionsParam);
|
|
185
|
+
if (!missingResponseType && !missingOptionsType) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const shouldImport = needsImportEdit("DataObject");
|
|
189
|
+
context.report({
|
|
190
|
+
node: reportNode,
|
|
191
|
+
messageId: "needsTypeAnnotation",
|
|
192
|
+
data: {
|
|
193
|
+
name: "isEmpty",
|
|
194
|
+
typeName: "DataObject",
|
|
195
|
+
kind: "function",
|
|
196
|
+
location: "parameters"
|
|
197
|
+
},
|
|
198
|
+
*fix(fixer) {
|
|
199
|
+
if (responseParam && isUnparenthesizedArrowParam(fn, responseParam, sourceCode)) {
|
|
200
|
+
yield* insertWrappedAnnotations(
|
|
201
|
+
fixer,
|
|
202
|
+
responseParam,
|
|
203
|
+
missingResponseType ? "DataObject" : null,
|
|
204
|
+
null
|
|
205
|
+
);
|
|
206
|
+
} else {
|
|
207
|
+
if (missingResponseType && responseParam) {
|
|
208
|
+
yield fixer.insertTextAfter(
|
|
209
|
+
getParamPattern(responseParam),
|
|
210
|
+
": DataObject"
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (missingOptionsType && optionsParam) {
|
|
214
|
+
yield fixer.insertTextAfter(
|
|
215
|
+
getParamPattern(optionsParam),
|
|
216
|
+
": { isDataEmpty: (data: DataObject) => boolean }"
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (shouldImport) {
|
|
221
|
+
yield* importEdit(fixer, "DataObject");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function checkRenderProp(name, fn, reportNode) {
|
|
227
|
+
const [propsParam] = fn.params;
|
|
228
|
+
if (!propsParam || paramHasTypeAnnotation(propsParam)) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const variablesType = derivedQueryTypes?.variables;
|
|
232
|
+
let insertText;
|
|
233
|
+
if (name === "Success") {
|
|
234
|
+
insertText = derivedQueryTypes ? `CellSuccessProps<${derivedQueryTypes.data}, ${derivedQueryTypes.variables}>` : "CellSuccessProps";
|
|
235
|
+
} else if (name === "Failure") {
|
|
236
|
+
insertText = variablesType ? `CellFailureProps<${variablesType}>` : "CellFailureProps";
|
|
237
|
+
} else {
|
|
238
|
+
insertText = variablesType ? `CellLoadingProps<${variablesType}>` : "CellLoadingProps";
|
|
239
|
+
}
|
|
240
|
+
const importName = `Cell${name}Props`;
|
|
241
|
+
const shouldImport = needsImportEdit(importName);
|
|
242
|
+
context.report({
|
|
243
|
+
node: reportNode,
|
|
244
|
+
messageId: "needsTypeAnnotation",
|
|
245
|
+
data: {
|
|
246
|
+
name,
|
|
247
|
+
typeName: insertText,
|
|
248
|
+
kind: "component",
|
|
249
|
+
location: "parameter"
|
|
250
|
+
},
|
|
251
|
+
*fix(fixer) {
|
|
252
|
+
if (isUnparenthesizedArrowParam(fn, propsParam, sourceCode)) {
|
|
253
|
+
yield* insertWrappedAnnotations(fixer, propsParam, insertText, null);
|
|
254
|
+
} else {
|
|
255
|
+
yield fixer.insertTextAfter(
|
|
256
|
+
getParamPattern(propsParam),
|
|
257
|
+
`: ${insertText}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
if (shouldImport) {
|
|
261
|
+
yield* importEdit(fixer, importName);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function checkExport(name, fn, reportNode) {
|
|
267
|
+
if (name === "beforeQuery") {
|
|
268
|
+
checkBeforeQuery(fn, reportNode);
|
|
269
|
+
} else if (name === "afterQuery") {
|
|
270
|
+
checkAfterQuery(fn, reportNode);
|
|
271
|
+
} else if (name === "isEmpty") {
|
|
272
|
+
checkIsEmpty(fn, reportNode);
|
|
273
|
+
} else if (RENDER_PROP_EXPORTS.has(name)) {
|
|
274
|
+
checkRenderProp(name, fn, reportNode);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
ImportDeclaration(node) {
|
|
279
|
+
if (node.source.value !== "@cedarjs/web") {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (node.importKind === "type") {
|
|
283
|
+
webTypeImport = node;
|
|
284
|
+
}
|
|
285
|
+
node.specifiers.filter(isImportSpecifier).forEach((specifier) => {
|
|
286
|
+
if (node.importKind === "type" || specifier.importKind === "type") {
|
|
287
|
+
importedWebTypeNames.add(specifier.local.name);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
ExportNamedDeclaration(node) {
|
|
292
|
+
if (node.declaration?.type === AST_NODE_TYPES.FunctionDeclaration) {
|
|
293
|
+
const fn = node.declaration;
|
|
294
|
+
const idNode = fn.id;
|
|
295
|
+
if (!idNode) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const name = idNode.name;
|
|
299
|
+
if (name === "Success") {
|
|
300
|
+
hasSuccessExport = true;
|
|
301
|
+
}
|
|
302
|
+
if (LIFECYCLE_EXPORTS.has(name) || RENDER_PROP_EXPORTS.has(name)) {
|
|
303
|
+
checks.push(() => checkExport(name, fn, idNode));
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (node.declaration?.type !== AST_NODE_TYPES.VariableDeclaration) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
node.declaration.declarations.forEach((vd) => {
|
|
311
|
+
if (vd.type !== AST_NODE_TYPES.VariableDeclarator || vd.id.type !== AST_NODE_TYPES.Identifier) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const name = vd.id.name;
|
|
315
|
+
if (name === "QUERY") {
|
|
316
|
+
derivedQueryTypes ||= extractTypedDocumentNodeArgs(
|
|
317
|
+
vd.id.typeAnnotation,
|
|
318
|
+
sourceCode
|
|
319
|
+
);
|
|
320
|
+
hasQueryOrFragment = true;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (name === "FRAGMENT") {
|
|
324
|
+
hasQueryOrFragment = true;
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (name === "Success") {
|
|
328
|
+
hasSuccessExport = true;
|
|
329
|
+
}
|
|
330
|
+
if ((LIFECYCLE_EXPORTS.has(name) || RENDER_PROP_EXPORTS.has(name)) && (vd.init?.type === AST_NODE_TYPES.ArrowFunctionExpression || vd.init?.type === AST_NODE_TYPES.FunctionExpression)) {
|
|
331
|
+
const fn = vd.init;
|
|
332
|
+
checks.push(() => checkExport(name, fn, vd.id));
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
"Program:exit"() {
|
|
337
|
+
const isCellFile = filenameIndicatesCell && hasQueryOrFragment && hasSuccessExport;
|
|
338
|
+
if (!isCellFile) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
checks.forEach((check) => check());
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
export {
|
|
347
|
+
cellTypeAnnotations
|
|
348
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
2
|
export declare const meta: {
|
|
3
3
|
name: string;
|
|
4
|
-
version:
|
|
4
|
+
version: string;
|
|
5
5
|
};
|
|
6
6
|
export declare const rules: {
|
|
7
|
+
'cell-type-annotations': ESLintUtils.RuleModule<"needsTypeAnnotation" | "beforeQueryParamNeedsType", [], unknown, ESLintUtils.RuleListener>;
|
|
7
8
|
'process-env-computed': ESLintUtils.RuleModule<"unexpected", [], unknown, ESLintUtils.RuleListener>;
|
|
8
9
|
'service-type-annotations': ESLintUtils.RuleModule<"needsType", [], unknown, ESLintUtils.RuleListener>;
|
|
9
10
|
'unsupported-route-components': ESLintUtils.RuleModule<"unexpected", [], unknown, ESLintUtils.RuleListener>;
|
|
@@ -11,9 +12,10 @@ export declare const rules: {
|
|
|
11
12
|
declare const plugin: {
|
|
12
13
|
meta: {
|
|
13
14
|
name: string;
|
|
14
|
-
version:
|
|
15
|
+
version: string;
|
|
15
16
|
};
|
|
16
17
|
rules: {
|
|
18
|
+
'cell-type-annotations': ESLintUtils.RuleModule<"needsTypeAnnotation" | "beforeQueryParamNeedsType", [], unknown, ESLintUtils.RuleListener>;
|
|
17
19
|
'process-env-computed': ESLintUtils.RuleModule<"unexpected", [], unknown, ESLintUtils.RuleListener>;
|
|
18
20
|
'service-type-annotations': ESLintUtils.RuleModule<"needsType", [], unknown, ESLintUtils.RuleListener>;
|
|
19
21
|
'unsupported-route-components': ESLintUtils.RuleModule<"unexpected", [], unknown, ESLintUtils.RuleListener>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAS3D,eAAO,MAAM,IAAI;;;CAGhB,CAAA;AAED,eAAO,MAAM,KAAK;;;;;CAKwC,CAAA;AAE1D,QAAA,MAAM,MAAM;;;;;;;;;;;CAAkB,CAAA;AAE9B,eAAe,MAAM,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,44 +1,22 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var src_exports = {};
|
|
20
|
-
__export(src_exports, {
|
|
21
|
-
default: () => src_default,
|
|
22
|
-
meta: () => meta,
|
|
23
|
-
rules: () => rules
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(src_exports);
|
|
26
|
-
var import_process_env_computed = require("./process-env-computed.js");
|
|
27
|
-
var import_service_type_annotations = require("./service-type-annotations.js");
|
|
28
|
-
var import_unsupported_route_components = require("./unsupported-route-components.js");
|
|
1
|
+
import pkgJson from "../package.json" with { type: "json" };
|
|
2
|
+
import { cellTypeAnnotations } from "./cell-type-annotations.js";
|
|
3
|
+
import { processEnvComputedRule } from "./process-env-computed.js";
|
|
4
|
+
import { serviceTypeAnnotations } from "./service-type-annotations.js";
|
|
5
|
+
import { unsupportedRouteComponents } from "./unsupported-route-components.js";
|
|
29
6
|
const meta = {
|
|
30
7
|
name: "@cedarjs/eslint-plugin",
|
|
31
|
-
version:
|
|
8
|
+
version: pkgJson.version
|
|
32
9
|
};
|
|
33
10
|
const rules = {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
11
|
+
"cell-type-annotations": cellTypeAnnotations,
|
|
12
|
+
"process-env-computed": processEnvComputedRule,
|
|
13
|
+
"service-type-annotations": serviceTypeAnnotations,
|
|
14
|
+
"unsupported-route-components": unsupportedRouteComponents
|
|
37
15
|
};
|
|
38
16
|
const plugin = { meta, rules };
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
var index_default = plugin;
|
|
18
|
+
export {
|
|
19
|
+
index_default as default,
|
|
42
20
|
meta,
|
|
43
21
|
rules
|
|
44
|
-
}
|
|
22
|
+
};
|
|
@@ -1,33 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var process_env_computed_exports = {};
|
|
20
|
-
__export(process_env_computed_exports, {
|
|
21
|
-
processEnvComputedRule: () => processEnvComputedRule
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(process_env_computed_exports);
|
|
24
|
-
var import_utils = require("@typescript-eslint/utils");
|
|
25
|
-
const createRule = import_utils.ESLintUtils.RuleCreator.withoutDocs;
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
+
const createRule = ESLintUtils.RuleCreator.withoutDocs;
|
|
26
3
|
function isProcessEnv(node) {
|
|
27
|
-
return node.type ===
|
|
4
|
+
return node.type === AST_NODE_TYPES.MemberExpression && hasName(node.object, "process") && hasName(node.property, "env");
|
|
28
5
|
}
|
|
29
6
|
function hasName(node, name) {
|
|
30
|
-
return node.type ===
|
|
7
|
+
return node.type === AST_NODE_TYPES.Identifier && node.name === name;
|
|
31
8
|
}
|
|
32
9
|
function isTestFile(filename) {
|
|
33
10
|
return filename.endsWith(".test.ts") || filename.endsWith(".test.js") || filename.endsWith(".test.tsx") || filename.endsWith(".test.jsx") || filename.endsWith(".test.mts") || filename.endsWith(".test.mjs") || filename.endsWith(".test.cjs") || filename.endsWith(".spec.ts") || filename.endsWith(".spec.js") || filename.endsWith(".spec.tsx") || filename.endsWith(".spec.jsx") || filename.endsWith(".spec.mts") || filename.endsWith(".spec.mjs") || filename.endsWith(".spec.cjs") || filename.includes("/__tests__/");
|
|
@@ -59,7 +36,6 @@ const processEnvComputedRule = createRule({
|
|
|
59
36
|
};
|
|
60
37
|
}
|
|
61
38
|
});
|
|
62
|
-
|
|
63
|
-
0 && (module.exports = {
|
|
39
|
+
export {
|
|
64
40
|
processEnvComputedRule
|
|
65
|
-
}
|
|
41
|
+
};
|
|
@@ -1,29 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var service_type_annotations_exports = {};
|
|
20
|
-
__export(service_type_annotations_exports, {
|
|
21
|
-
serviceTypeAnnotations: () => serviceTypeAnnotations
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(service_type_annotations_exports);
|
|
24
|
-
var import_node_path = require("node:path");
|
|
25
|
-
var import_utils = require("@typescript-eslint/utils");
|
|
26
|
-
const createRule = import_utils.ESLintUtils.RuleCreator.withoutDocs;
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
3
|
+
const createRule = ESLintUtils.RuleCreator.withoutDocs;
|
|
27
4
|
const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
28
5
|
const serviceTypeAnnotations = createRule({
|
|
29
6
|
meta: {
|
|
@@ -39,7 +16,7 @@ const serviceTypeAnnotations = createRule({
|
|
|
39
16
|
},
|
|
40
17
|
defaultOptions: [],
|
|
41
18
|
create(context) {
|
|
42
|
-
const thisFilename =
|
|
19
|
+
const thisFilename = basename(context.filename);
|
|
43
20
|
const sansTS = thisFilename.replace(".ts", "");
|
|
44
21
|
const thisFileCorrespondingImport = `types/${sansTS}`;
|
|
45
22
|
let importForThisFile = null;
|
|
@@ -51,18 +28,18 @@ const serviceTypeAnnotations = createRule({
|
|
|
51
28
|
},
|
|
52
29
|
// Then start looking at every exported fn/const
|
|
53
30
|
ExportNamedDeclaration(node) {
|
|
54
|
-
if (node.declaration?.type !==
|
|
31
|
+
if (node.declaration?.type !== AST_NODE_TYPES.VariableDeclaration) {
|
|
55
32
|
return;
|
|
56
33
|
}
|
|
57
34
|
node.declaration.declarations.forEach((vd) => {
|
|
58
|
-
if (vd.type ===
|
|
35
|
+
if (vd.type === AST_NODE_TYPES.VariableDeclarator && vd.id.type === AST_NODE_TYPES.Identifier) {
|
|
59
36
|
if (vd.id.name.startsWith("_")) {
|
|
60
37
|
return;
|
|
61
38
|
}
|
|
62
39
|
const isGlobalOrMutationResolver = /^[a-z]/.test(vd.id.name);
|
|
63
40
|
const suffix = isGlobalOrMutationResolver ? "Resolver" : "TypeResolvers";
|
|
64
41
|
const typeName = capitalizeFirstLetter(vd.id.name) + suffix;
|
|
65
|
-
if (isGlobalOrMutationResolver && vd.init?.type !==
|
|
42
|
+
if (isGlobalOrMutationResolver && vd.init?.type !== AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
66
43
|
return;
|
|
67
44
|
}
|
|
68
45
|
const tsID = vd.id;
|
|
@@ -98,7 +75,7 @@ const serviceTypeAnnotations = createRule({
|
|
|
98
75
|
if (!("typeName" in type)) {
|
|
99
76
|
return;
|
|
100
77
|
}
|
|
101
|
-
const isCorrectType = type.typeName?.type ===
|
|
78
|
+
const isCorrectType = type.typeName?.type === AST_NODE_TYPES.Identifier && type.typeName?.name === typeName;
|
|
102
79
|
if (isCorrectType) {
|
|
103
80
|
return;
|
|
104
81
|
}
|
|
@@ -134,7 +111,6 @@ const serviceTypeAnnotations = createRule({
|
|
|
134
111
|
};
|
|
135
112
|
}
|
|
136
113
|
});
|
|
137
|
-
|
|
138
|
-
0 && (module.exports = {
|
|
114
|
+
export {
|
|
139
115
|
serviceTypeAnnotations
|
|
140
|
-
}
|
|
116
|
+
};
|
|
@@ -1,35 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var unsupported_route_components_exports = {};
|
|
20
|
-
__export(unsupported_route_components_exports, {
|
|
21
|
-
unsupportedRouteComponents: () => unsupportedRouteComponents
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(unsupported_route_components_exports);
|
|
24
|
-
var import_utils = require("@typescript-eslint/utils");
|
|
25
|
-
const createRule = import_utils.ESLintUtils.RuleCreator.withoutDocs;
|
|
1
|
+
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
+
const createRule = ESLintUtils.RuleCreator.withoutDocs;
|
|
26
3
|
function isAllowedElement(name) {
|
|
27
4
|
const allowedElements = ["Router", "Route", "Set", "PrivateSet", "Private"];
|
|
28
5
|
return allowedElements.includes(name);
|
|
29
6
|
}
|
|
30
7
|
function checkNodes(nodesToCheck, context) {
|
|
31
|
-
if (nodesToCheck.type ===
|
|
32
|
-
const name = nodesToCheck.openingElement.name.type ===
|
|
8
|
+
if (nodesToCheck.type === AST_NODE_TYPES.JSXElement) {
|
|
9
|
+
const name = nodesToCheck.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier ? nodesToCheck.openingElement.name.name : null;
|
|
33
10
|
if (name && !isAllowedElement(name)) {
|
|
34
11
|
context.report({
|
|
35
12
|
node: nodesToCheck,
|
|
@@ -59,11 +36,11 @@ const unsupportedRouteComponents = createRule({
|
|
|
59
36
|
VariableDeclaration(node) {
|
|
60
37
|
if (isRoutesRenderBlock(node.declarations[0])) {
|
|
61
38
|
const routesDeclaration = node.declarations[0].init;
|
|
62
|
-
if (routesDeclaration?.type ===
|
|
63
|
-
if (routesDeclaration.body.type ===
|
|
39
|
+
if (routesDeclaration?.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
40
|
+
if (routesDeclaration.body.type === AST_NODE_TYPES.JSXElement) {
|
|
64
41
|
checkNodes(routesDeclaration.body, context);
|
|
65
|
-
} else if (routesDeclaration.body.type ===
|
|
66
|
-
if (routesDeclaration.body.body[0].type ===
|
|
42
|
+
} else if (routesDeclaration.body.type === AST_NODE_TYPES.BlockStatement) {
|
|
43
|
+
if (routesDeclaration.body.body[0].type === AST_NODE_TYPES.ReturnStatement && routesDeclaration.body.body[0].argument?.type === AST_NODE_TYPES.JSXElement) {
|
|
67
44
|
const routesReturnStatement = routesDeclaration.body.body[0].argument;
|
|
68
45
|
checkNodes(routesReturnStatement, context);
|
|
69
46
|
}
|
|
@@ -75,9 +52,8 @@ const unsupportedRouteComponents = createRule({
|
|
|
75
52
|
}
|
|
76
53
|
});
|
|
77
54
|
function isRoutesRenderBlock(node) {
|
|
78
|
-
return node?.type ===
|
|
55
|
+
return node?.type === AST_NODE_TYPES.VariableDeclarator && node?.id.type === AST_NODE_TYPES.Identifier && node?.id.name === "Routes";
|
|
79
56
|
}
|
|
80
|
-
|
|
81
|
-
0 && (module.exports = {
|
|
57
|
+
export {
|
|
82
58
|
unsupportedRouteComponents
|
|
83
|
-
}
|
|
59
|
+
};
|
package/package.json
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/eslint-plugin",
|
|
3
|
-
"version": "9.0.0-canary.
|
|
3
|
+
"version": "9.0.0-canary.3124",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/cedarjs/cedar.git",
|
|
7
7
|
"directory": "packages/eslint-plugin"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
|
+
"type": "module",
|
|
10
11
|
"main": "./dist/index.js",
|
|
11
12
|
"types": "./dist/index.d.ts",
|
|
12
13
|
"files": [
|
|
13
14
|
"dist"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
|
-
"build": "
|
|
17
|
+
"build": "node ./build.mts",
|
|
17
18
|
"build:pack": "yarn pack -o cedarjs-eslint-plugin.tgz",
|
|
18
|
-
"build:types": "tsc --build --verbose",
|
|
19
|
+
"build:types": "tsc --build --verbose ./tsconfig.build.json",
|
|
19
20
|
"build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx\" --ignore dist --exec \"yarn build\"",
|
|
20
21
|
"prepublishOnly": "NODE_ENV=production yarn build",
|
|
21
22
|
"test": "vitest run",
|
|
22
23
|
"test:watch": "vitest watch"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"@typescript-eslint/utils": "8.
|
|
26
|
+
"@typescript-eslint/utils": "8.69.0",
|
|
26
27
|
"eslint": "8.57.1"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@cedarjs/framework-tools": "9.0.0-canary.
|
|
30
|
+
"@cedarjs/framework-tools": "9.0.0-canary.3124",
|
|
30
31
|
"@types/eslint": "8.56.12",
|
|
31
|
-
"@types/estree": "1.0.
|
|
32
|
-
"@typescript-eslint/parser": "8.
|
|
33
|
-
"@typescript-eslint/rule-tester": "8.
|
|
34
|
-
"tsx": "4.21.0",
|
|
32
|
+
"@types/estree": "1.0.9",
|
|
33
|
+
"@typescript-eslint/parser": "8.69.0",
|
|
34
|
+
"@typescript-eslint/rule-tester": "8.69.0",
|
|
35
35
|
"typescript": "5.9.3",
|
|
36
|
-
"vitest": "
|
|
36
|
+
"vitest": "4.1.11"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=24"
|
|
37
40
|
},
|
|
38
41
|
"publishConfig": {
|
|
39
42
|
"access": "public"
|
|
40
43
|
},
|
|
41
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
|
|
42
45
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Cedar
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|