@lark-apaas/fullstack-presets 1.1.25 → 1.1.26-alpha.20261002143152
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/lib/custom-eslint-rules/index.d.ts +1 -0
- package/lib/custom-eslint-rules/index.js +2 -0
- package/lib/custom-eslint-rules/validated-non-primitive-needs-element-type.d.ts +3 -0
- package/lib/custom-eslint-rules/validated-non-primitive-needs-element-type.js +330 -0
- package/lib/recommend/eslint/eslint-client.d.ts +1 -0
- package/lib/recommend/eslint/index.d.ts +1 -0
- package/lib/simple/recommend/eslint/eslint-server.d.ts +2 -0
- package/lib/simple/recommend/eslint/eslint-server.js +3 -0
- package/lib/simple/recommend/eslint/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -11,4 +11,5 @@ export declare const customRules: {
|
|
|
11
11
|
'no-welcome-index-route': import("eslint").Rule.RuleModule;
|
|
12
12
|
'require-index-route': import("eslint").Rule.RuleModule;
|
|
13
13
|
'no-duplicate-route-component': import("eslint").Rule.RuleModule;
|
|
14
|
+
'validated-non-primitive-needs-element-type': import("eslint").Rule.RuleModule;
|
|
14
15
|
};
|
|
@@ -16,6 +16,7 @@ const require_shared_request_type_1 = __importDefault(require("./require-shared-
|
|
|
16
16
|
const no_welcome_index_route_1 = __importDefault(require("./no-welcome-index-route"));
|
|
17
17
|
const require_index_route_1 = __importDefault(require("./require-index-route"));
|
|
18
18
|
const no_duplicate_route_component_1 = __importDefault(require("./no-duplicate-route-component"));
|
|
19
|
+
const validated_non_primitive_needs_element_type_1 = __importDefault(require("./validated-non-primitive-needs-element-type"));
|
|
19
20
|
exports.customRules = {
|
|
20
21
|
'no-nested-styled-jsx': no_nested_styled_jsx_1.default,
|
|
21
22
|
'no-styled-jsx-data-uri-url-ref': no_styled_jsx_data_uri_url_ref_1.default,
|
|
@@ -29,4 +30,5 @@ exports.customRules = {
|
|
|
29
30
|
'no-welcome-index-route': no_welcome_index_route_1.default,
|
|
30
31
|
'require-index-route': require_index_route_1.default,
|
|
31
32
|
'no-duplicate-route-component': no_duplicate_route_component_1.default,
|
|
33
|
+
'validated-non-primitive-needs-element-type': validated_non_primitive_needs_element_type_1.default,
|
|
32
34
|
};
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
7
|
+
const primitiveTypeNodes = new Set([
|
|
8
|
+
'TSStringKeyword',
|
|
9
|
+
'TSBooleanKeyword',
|
|
10
|
+
'TSNumberKeyword',
|
|
11
|
+
'TSLiteralType',
|
|
12
|
+
'TSNullKeyword',
|
|
13
|
+
'TSUnknownKeyword',
|
|
14
|
+
'TSAnyKeyword',
|
|
15
|
+
'TSObjectKeyword',
|
|
16
|
+
'TSTypeLiteral',
|
|
17
|
+
]);
|
|
18
|
+
const semanticPrimitiveFlags = typescript_1.default.TypeFlags.StringLike |
|
|
19
|
+
typescript_1.default.TypeFlags.NumberLike |
|
|
20
|
+
typescript_1.default.TypeFlags.BooleanLike |
|
|
21
|
+
typescript_1.default.TypeFlags.BigIntLike |
|
|
22
|
+
typescript_1.default.TypeFlags.ESSymbolLike |
|
|
23
|
+
typescript_1.default.TypeFlags.Null |
|
|
24
|
+
typescript_1.default.TypeFlags.Undefined |
|
|
25
|
+
typescript_1.default.TypeFlags.Void |
|
|
26
|
+
typescript_1.default.TypeFlags.Never |
|
|
27
|
+
typescript_1.default.TypeFlags.Any |
|
|
28
|
+
typescript_1.default.TypeFlags.Unknown;
|
|
29
|
+
const rule = {
|
|
30
|
+
meta: {
|
|
31
|
+
type: 'problem',
|
|
32
|
+
docs: {
|
|
33
|
+
description: 'Require validated non-primitive DTO properties to declare a usable class-transformer Type',
|
|
34
|
+
category: 'Possible Errors',
|
|
35
|
+
recommended: true,
|
|
36
|
+
},
|
|
37
|
+
schema: [
|
|
38
|
+
{
|
|
39
|
+
type: 'object',
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
properties: {
|
|
42
|
+
additionalTypeDecorators: {
|
|
43
|
+
type: 'array',
|
|
44
|
+
items: { type: 'string', minLength: 1 },
|
|
45
|
+
},
|
|
46
|
+
additionalCustomValidatorDecorators: {
|
|
47
|
+
type: 'array',
|
|
48
|
+
items: { type: 'string', minLength: 1 },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
messages: {
|
|
54
|
+
missingElementType: 'This validated object array needs an element transformer. Add @Type(() => Object) for ordinary objects, or introduce a runtime DTO class and use @Type(() => ChildDto). @IsObject({ each: true }) and @ValidateNested({ each: true }) validate elements but do not transform them.',
|
|
55
|
+
missingRuntimeElementType: 'This validated DTO array needs @Type(() => {{typeName}}) so class-transformer can construct each element. Add @ValidateNested({ each: true }) separately only when child fields must also be validated.',
|
|
56
|
+
missingAliasedRuntimeElementType: 'This validated DTO array needs @Type using the actual in-scope runtime DTO class value for its elements. Do not pass a TypeScript-only alias. Add @ValidateNested({ each: true }) separately only when child fields must also be validated.',
|
|
57
|
+
invalidElementType: 'The @Type decorator does not describe this ordinary object array. Use @Type(() => Object); TypeScript interfaces cannot be used as runtime constructors.',
|
|
58
|
+
invalidRuntimeElementType: 'The @Type decorator does not describe this nested DTO array. Use @Type(() => {{typeName}}) with the runtime DTO class.',
|
|
59
|
+
invalidAliasedRuntimeElementType: 'The @Type decorator does not describe this nested DTO array. Pass the actual in-scope runtime DTO class value, not a TypeScript-only alias.',
|
|
60
|
+
missingType: 'A validated non-primitive property needs a class-transformer @Type decorator with a runtime constructor. TypeScript interfaces cannot be used as runtime constructors.',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
create(context) {
|
|
64
|
+
const parserServices = context.sourceCode.parserServices;
|
|
65
|
+
if (!parserServices?.program || !parserServices.esTreeNodeToTSNodeMap) {
|
|
66
|
+
throw new Error('@lark-apaas/validated-non-primitive-needs-element-type requires type information. Configure parserOptions.project for the server files.');
|
|
67
|
+
}
|
|
68
|
+
const checker = parserServices.program.getTypeChecker();
|
|
69
|
+
const nodeMap = parserServices.esTreeNodeToTSNodeMap;
|
|
70
|
+
const classValidatorDecoratorNames = new Set();
|
|
71
|
+
const options = (context.options[0] ?? {});
|
|
72
|
+
const customValidatorNames = new Set(options.additionalCustomValidatorDecorators ?? []);
|
|
73
|
+
const customTypeDecoratorNames = new Set(options.additionalTypeDecorators ?? []);
|
|
74
|
+
return {
|
|
75
|
+
// Match the upstream rule's import-aware class-validator detection.
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
ImportDeclaration(node) {
|
|
78
|
+
if (typeof node.source.value !== 'string' ||
|
|
79
|
+
!node.source.value.startsWith('class-validator')) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const specifier of node.specifiers) {
|
|
83
|
+
if (specifier.type === 'ImportSpecifier') {
|
|
84
|
+
classValidatorDecoratorNames.add(specifier.local.name);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
|
+
PropertyDefinition(node) {
|
|
90
|
+
const annotation = node.typeAnnotation?.typeAnnotation;
|
|
91
|
+
if (!annotation)
|
|
92
|
+
return;
|
|
93
|
+
const validationDecorators = node.decorators.filter((decorator) => {
|
|
94
|
+
const name = getDecoratorName(decorator);
|
|
95
|
+
return (name !== null &&
|
|
96
|
+
(classValidatorDecoratorNames.has(name) ||
|
|
97
|
+
customValidatorNames.has(name)));
|
|
98
|
+
});
|
|
99
|
+
if (validationDecorators.length === 0)
|
|
100
|
+
return;
|
|
101
|
+
const validationNames = new Set(validationDecorators.map(getDecoratorName));
|
|
102
|
+
if (validationNames.has('IsEnum'))
|
|
103
|
+
return;
|
|
104
|
+
const annotationType = getSemanticType(annotation, nodeMap, checker);
|
|
105
|
+
const arrayElementTypes = annotationType
|
|
106
|
+
? getArrayElementTypes(annotationType, checker)
|
|
107
|
+
: null;
|
|
108
|
+
const syntacticElementType = getSyntacticArrayElementType(annotation);
|
|
109
|
+
const isArray = arrayElementTypes !== null || syntacticElementType !== null;
|
|
110
|
+
if (isArray) {
|
|
111
|
+
if (arrayElementTypes?.every(elementType => isSemanticPrimitiveType(elementType, checker))) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (arrayElementTypes?.every(elementType => isSemanticEnumType(elementType, checker))) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
if (isSyntacticPrimitiveType(annotation))
|
|
120
|
+
return;
|
|
121
|
+
if (annotationType && isSemanticEnumType(annotationType, checker)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// A scalar plain object intentionally needs only runtime object validation.
|
|
126
|
+
// Semantic array resolution ensures aliases and nullable arrays never take this exemption.
|
|
127
|
+
if (!isArray && validationNames.has('IsObject'))
|
|
128
|
+
return;
|
|
129
|
+
const typeDecorators = node.decorators.filter((decorator) => {
|
|
130
|
+
const name = getDecoratorName(decorator);
|
|
131
|
+
return (name === 'Type' ||
|
|
132
|
+
(name !== null && customTypeDecoratorNames.has(name)));
|
|
133
|
+
});
|
|
134
|
+
if (!isArray) {
|
|
135
|
+
if (typeDecorators.length === 0) {
|
|
136
|
+
context.report({ node: node.key, messageId: 'missingType' });
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const runtimeConstructor = arrayElementTypes
|
|
141
|
+
? getSharedRuntimeConstructor(arrayElementTypes, syntacticElementType, nodeMap, checker)
|
|
142
|
+
: null;
|
|
143
|
+
const expectedTypeName = runtimeConstructor?.name ?? 'Object';
|
|
144
|
+
const hasValidType = typeDecorators.some((decorator) => {
|
|
145
|
+
const name = getDecoratorName(decorator);
|
|
146
|
+
if (name !== 'Type')
|
|
147
|
+
return true;
|
|
148
|
+
return runtimeConstructor
|
|
149
|
+
? typeDecoratorTargetsConstructor(decorator, runtimeConstructor.symbol, nodeMap, checker)
|
|
150
|
+
: getTypeDecoratorTargetName(decorator) === 'Object';
|
|
151
|
+
});
|
|
152
|
+
if (hasValidType)
|
|
153
|
+
return;
|
|
154
|
+
if (typeDecorators.length > 0) {
|
|
155
|
+
context.report({
|
|
156
|
+
node: node.key,
|
|
157
|
+
messageId: runtimeConstructor
|
|
158
|
+
? runtimeConstructor.name
|
|
159
|
+
? 'invalidRuntimeElementType'
|
|
160
|
+
: 'invalidAliasedRuntimeElementType'
|
|
161
|
+
: 'invalidElementType',
|
|
162
|
+
data: { typeName: expectedTypeName },
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
context.report({
|
|
167
|
+
node: node.key,
|
|
168
|
+
messageId: runtimeConstructor
|
|
169
|
+
? runtimeConstructor.name
|
|
170
|
+
? 'missingRuntimeElementType'
|
|
171
|
+
: 'missingAliasedRuntimeElementType'
|
|
172
|
+
: 'missingElementType',
|
|
173
|
+
data: { typeName: expectedTypeName },
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
180
|
+
function getDecoratorName(decorator) {
|
|
181
|
+
const expression = decorator?.expression;
|
|
182
|
+
if (expression?.type !== 'CallExpression' ||
|
|
183
|
+
expression.callee?.type !== 'Identifier') {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
return expression.callee.name;
|
|
187
|
+
}
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
+
function getTypeDecoratorTarget(decorator) {
|
|
190
|
+
const factory = decorator.expression?.arguments?.[0];
|
|
191
|
+
if (factory?.type !== 'ArrowFunctionExpression')
|
|
192
|
+
return null;
|
|
193
|
+
if (factory.body?.type !== 'BlockStatement')
|
|
194
|
+
return factory.body ?? null;
|
|
195
|
+
if (factory.body.body?.length === 1 &&
|
|
196
|
+
factory.body.body[0].type === 'ReturnStatement') {
|
|
197
|
+
return factory.body.body[0].argument ?? null;
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
202
|
+
function getTypeDecoratorTargetName(decorator) {
|
|
203
|
+
const target = getTypeDecoratorTarget(decorator);
|
|
204
|
+
return target?.type === 'Identifier' ? target.name : null;
|
|
205
|
+
}
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
207
|
+
function getSyntacticArrayElementType(annotation) {
|
|
208
|
+
if (annotation.type === 'TSArrayType')
|
|
209
|
+
return annotation.elementType;
|
|
210
|
+
if (annotation.type === 'TSTypeReference' &&
|
|
211
|
+
annotation.typeName?.type === 'Identifier' &&
|
|
212
|
+
(annotation.typeName.name === 'Array' ||
|
|
213
|
+
annotation.typeName.name === 'ReadonlyArray') &&
|
|
214
|
+
annotation.typeArguments?.params?.length === 1) {
|
|
215
|
+
return annotation.typeArguments.params[0];
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
220
|
+
function isSyntacticPrimitiveType(typeNode) {
|
|
221
|
+
if (primitiveTypeNodes.has(typeNode.type))
|
|
222
|
+
return true;
|
|
223
|
+
return (typeNode.type === 'TSUnionType' &&
|
|
224
|
+
typeNode.types.some((member) => primitiveTypeNodes.has(member.type)));
|
|
225
|
+
}
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
function getSemanticType(node, nodeMap, checker) {
|
|
228
|
+
const tsNode = nodeMap.get(node);
|
|
229
|
+
return tsNode ? checker.getTypeAtLocation(tsNode) : null;
|
|
230
|
+
}
|
|
231
|
+
function getArrayElementTypes(annotationType, checker) {
|
|
232
|
+
const nonNullable = checker.getNonNullableType(annotationType);
|
|
233
|
+
// Nullable arrays collapse to one non-nullable array. Other heterogeneous unions
|
|
234
|
+
// remain outside this rule because there is no single safe element transformer.
|
|
235
|
+
if (nonNullable.isUnion() || !checker.isArrayType(nonNullable))
|
|
236
|
+
return null;
|
|
237
|
+
const typeArguments = checker.getTypeArguments(nonNullable);
|
|
238
|
+
const elementType = typeArguments[0] ??
|
|
239
|
+
checker.getIndexTypeOfType(nonNullable, typescript_1.default.IndexKind.Number);
|
|
240
|
+
return elementType ? [elementType] : null;
|
|
241
|
+
}
|
|
242
|
+
function isSemanticPrimitiveType(type, checker) {
|
|
243
|
+
if ((type.flags & semanticPrimitiveFlags) !== 0)
|
|
244
|
+
return true;
|
|
245
|
+
const nonNullable = checker.getNonNullableType(type);
|
|
246
|
+
if (nonNullable.isUnion()) {
|
|
247
|
+
return nonNullable.types.every(member => isSemanticPrimitiveType(member, checker));
|
|
248
|
+
}
|
|
249
|
+
return (nonNullable.flags & semanticPrimitiveFlags) !== 0;
|
|
250
|
+
}
|
|
251
|
+
function isSemanticEnumType(type, checker) {
|
|
252
|
+
const nonNullable = checker.getNonNullableType(type);
|
|
253
|
+
if ((nonNullable.flags & typescript_1.default.TypeFlags.EnumLike) !== 0)
|
|
254
|
+
return true;
|
|
255
|
+
const symbol = nonNullable.aliasSymbol ?? nonNullable.getSymbol();
|
|
256
|
+
if (symbol?.declarations?.some(declaration => typescript_1.default.isEnumDeclaration(declaration))) {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
return (nonNullable.isUnion() &&
|
|
260
|
+
nonNullable.types.length > 0 &&
|
|
261
|
+
nonNullable.types.every(member => member.symbol?.declarations?.some(declaration => typescript_1.default.isEnumMember(declaration) &&
|
|
262
|
+
typescript_1.default.isEnumDeclaration(declaration.parent))));
|
|
263
|
+
}
|
|
264
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
265
|
+
function getSharedRuntimeConstructor(elementTypes, syntacticElementType, nodeMap, checker) {
|
|
266
|
+
const candidates = elementTypes.flatMap(elementType => {
|
|
267
|
+
const nonNullable = checker.getNonNullableType(elementType);
|
|
268
|
+
return nonNullable.isUnion() ? nonNullable.types : [nonNullable];
|
|
269
|
+
});
|
|
270
|
+
if (candidates.length === 0)
|
|
271
|
+
return null;
|
|
272
|
+
const symbols = candidates.map(type => getRuntimeConstructorSymbol(type, checker));
|
|
273
|
+
const symbol = symbols[0];
|
|
274
|
+
if (!symbol || symbols.some(candidate => candidate !== symbol))
|
|
275
|
+
return null;
|
|
276
|
+
return {
|
|
277
|
+
symbol,
|
|
278
|
+
name: getUsableRuntimeConstructorName(syntacticElementType, symbol, nodeMap, checker),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
function getRuntimeConstructorSymbol(instanceType, checker) {
|
|
282
|
+
const symbol = instanceType.getSymbol();
|
|
283
|
+
if (!symbol?.valueDeclaration)
|
|
284
|
+
return null;
|
|
285
|
+
const valueType = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
|
|
286
|
+
return valueType.getConstructSignatures().length > 0 ? symbol : null;
|
|
287
|
+
}
|
|
288
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
289
|
+
function getUsableRuntimeConstructorName(typeNode, expectedSymbol, nodeMap, checker) {
|
|
290
|
+
if (typeNode?.type !== 'TSTypeReference' ||
|
|
291
|
+
typeNode.typeName?.type !== 'Identifier') {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const tsTypeName = nodeMap.get(typeNode.typeName);
|
|
295
|
+
if (!tsTypeName)
|
|
296
|
+
return null;
|
|
297
|
+
const localSymbol = checker.getSymbolAtLocation(tsTypeName);
|
|
298
|
+
if (!localSymbol ||
|
|
299
|
+
isTypeOnlyImport(localSymbol) ||
|
|
300
|
+
resolveAlias(localSymbol, checker) !== expectedSymbol) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
return typeNode.typeName.name;
|
|
304
|
+
}
|
|
305
|
+
function isTypeOnlyImport(symbol) {
|
|
306
|
+
return (symbol.declarations?.some(declaration => {
|
|
307
|
+
if (typescript_1.default.isImportSpecifier(declaration)) {
|
|
308
|
+
return declaration.isTypeOnly || declaration.parent.parent.isTypeOnly;
|
|
309
|
+
}
|
|
310
|
+
return typescript_1.default.isImportClause(declaration) && declaration.isTypeOnly;
|
|
311
|
+
}) ?? false);
|
|
312
|
+
}
|
|
313
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
314
|
+
function typeDecoratorTargetsConstructor(decorator, expectedSymbol, nodeMap, checker) {
|
|
315
|
+
const target = getTypeDecoratorTarget(decorator);
|
|
316
|
+
const tsTarget = target ? nodeMap.get(target) : undefined;
|
|
317
|
+
if (!tsTarget)
|
|
318
|
+
return false;
|
|
319
|
+
const localSymbol = checker.getSymbolAtLocation(tsTarget);
|
|
320
|
+
return (localSymbol !== undefined &&
|
|
321
|
+
!isTypeOnlyImport(localSymbol) &&
|
|
322
|
+
resolveAlias(localSymbol, checker) === expectedSymbol);
|
|
323
|
+
}
|
|
324
|
+
function resolveAlias(symbol, checker) {
|
|
325
|
+
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias) !== 0) {
|
|
326
|
+
return checker.getAliasedSymbol(symbol);
|
|
327
|
+
}
|
|
328
|
+
return symbol;
|
|
329
|
+
}
|
|
330
|
+
exports.default = rule;
|
|
@@ -27,6 +27,7 @@ declare const _default: {
|
|
|
27
27
|
'no-welcome-index-route': import("eslint").Rule.RuleModule;
|
|
28
28
|
'require-index-route': import("eslint").Rule.RuleModule;
|
|
29
29
|
'no-duplicate-route-component': import("eslint").Rule.RuleModule;
|
|
30
|
+
'validated-non-primitive-needs-element-type': import("eslint").Rule.RuleModule;
|
|
30
31
|
};
|
|
31
32
|
};
|
|
32
33
|
};
|
|
@@ -30,6 +30,7 @@ export declare const eslintPresets: {
|
|
|
30
30
|
'no-welcome-index-route': import("eslint").Rule.RuleModule;
|
|
31
31
|
'require-index-route': import("eslint").Rule.RuleModule;
|
|
32
32
|
'no-duplicate-route-component': import("eslint").Rule.RuleModule;
|
|
33
|
+
'validated-non-primitive-needs-element-type': import("eslint").Rule.RuleModule;
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
36
|
};
|
|
@@ -48,6 +48,8 @@ declare const _default: {
|
|
|
48
48
|
'@darraghor/nestjs-typed/api-property-returning-array-should-set-array': string;
|
|
49
49
|
'@darraghor/nestjs-typed/api-property-matches-property-optionality': string;
|
|
50
50
|
'@darraghor/nestjs-typed/all-properties-have-explicit-defined': string;
|
|
51
|
+
'@darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator': string;
|
|
52
|
+
'@lark-apaas/validated-non-primitive-needs-element-type': string;
|
|
51
53
|
'@darraghor/nestjs-typed/controllers-should-supply-api-tags': string;
|
|
52
54
|
'@darraghor/nestjs-typed/api-method-should-specify-api-response': string;
|
|
53
55
|
'@darraghor/nestjs-typed/api-method-should-specify-api-operation': string;
|
|
@@ -69,6 +69,9 @@ exports.default = {
|
|
|
69
69
|
'@darraghor/nestjs-typed/api-property-returning-array-should-set-array': 'off',
|
|
70
70
|
'@darraghor/nestjs-typed/api-property-matches-property-optionality': 'off',
|
|
71
71
|
'@darraghor/nestjs-typed/all-properties-have-explicit-defined': 'off',
|
|
72
|
+
// 本地兼容规则保留上游的非原始类型检查,并修复对象数组的 IsObject(each) 豁免与 interface 建议。
|
|
73
|
+
'@darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator': 'off',
|
|
74
|
+
'@lark-apaas/validated-non-primitive-needs-element-type': 'error',
|
|
72
75
|
// 关闭 Swagger 相关规则
|
|
73
76
|
'@darraghor/nestjs-typed/controllers-should-supply-api-tags': 'off',
|
|
74
77
|
'@darraghor/nestjs-typed/api-method-should-specify-api-response': 'off',
|
|
@@ -57,6 +57,7 @@ export declare const eslintPresets: {
|
|
|
57
57
|
'no-welcome-index-route': import("eslint").Rule.RuleModule;
|
|
58
58
|
'require-index-route': import("eslint").Rule.RuleModule;
|
|
59
59
|
'no-duplicate-route-component': import("eslint").Rule.RuleModule;
|
|
60
|
+
'validated-non-primitive-needs-element-type': import("eslint").Rule.RuleModule;
|
|
60
61
|
};
|
|
61
62
|
};
|
|
62
63
|
};
|
|
@@ -82,6 +83,7 @@ export declare const eslintPresets: {
|
|
|
82
83
|
'no-welcome-index-route': import("eslint").Rule.RuleModule;
|
|
83
84
|
'require-index-route': import("eslint").Rule.RuleModule;
|
|
84
85
|
'no-duplicate-route-component': import("eslint").Rule.RuleModule;
|
|
86
|
+
'validated-non-primitive-needs-element-type': import("eslint").Rule.RuleModule;
|
|
85
87
|
};
|
|
86
88
|
};
|
|
87
89
|
};
|