@darraghor/eslint-plugin-nestjs-typed 7.3.3 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,14 +73,17 @@ Awesome! [Click here](https://github.com/darraghoriordan/eslint-plugin-nestjs-ty
73
73
  | | [`api-property-returning-array-should-set-array`](./src/docs/rules/api-property-returning-array-should-set-array.md) | ✅ |
74
74
  | | [`api-property-should-have-api-extra-models`](./src/docs/rules/api-property-should-have-api-extra-models.md) | ✅ |
75
75
  | | [`api-operation-summary-description-capitalized`](./src/docs/rules/api-operation-summary-description-capitalized.md) | ✅ |
76
+ | | [`swagger-file-upload-should-be-documented`](./src/docs/rules/swagger-file-upload-should-be-documented.md) | ✅ |
76
77
  | | | |
77
78
  | Preventing bugs | [`param-decorator-name-matches-route-param`](./src/docs/rules/param-decorator-name-matches-route-param.md) | ✅ |
79
+ | | [`forward-ref-injection-should-use-wrapper-type`](./src/docs/rules/forward-ref-injection-should-use-wrapper-type.md) | ✅ |
80
+ | | [`uploaded-file-should-be-validated`](./src/docs/rules/uploaded-file-should-be-validated.md) | ✅ |
78
81
  | | [`validate-nested-of-array-should-set-each`](./src/docs/rules/validate-nested-of-array-should-set-each.md) | ✅ |
79
82
  | | [`validated-non-primitive-property-needs-type-decorator`](./src/docs/rules/validated-non-primitive-property-needs-type-decorator.md) | ✅ |
80
83
  | | [`all-properties-are-whitelisted`](./src/docs/rules/all-properties-are-whitelisted.md) | ✅ |
81
84
  | | [`all-properties-have-explicit-defined`](./src/docs/rules/all-properties-have-explicit-defined.md) | ✅ |
82
85
  | | [`no-duplicate-decorators`](./src/docs/rules/no-duplicate-decorators.md) | ✅ |
83
- | | [`validation-pipe-should-use-forbid-unknown`](./src/docs/rules/validation-pipe-should-use-forbid-unknown.md) | ✅ |
86
+ | | [`validation-pipe-should-use-forbid-unknown`](./src/docs/rules/validation-pipe-should-use-forbid-unknown.md) | ✅ |
84
87
  | | | |
85
88
  | Security | [`api-methods-should-be-guarded`](./src/docs/rules/api-methods-should-be-guarded.md) | ❌ |
86
89
  | | | |
@@ -6,10 +6,11 @@ export const rules = {
6
6
  "@darraghor/nestjs-typed/controllers-should-supply-api-tags": "off",
7
7
  "@darraghor/nestjs-typed/api-enum-property-best-practices": "off",
8
8
  "@darraghor/nestjs-typed/api-property-returning-array-should-set-array": "off",
9
+ "@darraghor/nestjs-typed/swagger-file-upload-should-be-documented": "off",
9
10
  };
10
11
  const config = {
11
12
  extends: ["./configs/base"],
12
13
  rules,
13
14
  };
14
15
  export default config;
15
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9Td2FnZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZ3Mvbm9Td2FnZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLG9FQUFvRTtBQUNwRSxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQWdEO0lBQzlELG1FQUFtRSxFQUFFLEtBQUs7SUFDMUUsZ0VBQWdFLEVBQUUsS0FBSztJQUN2RSxpRUFBaUUsRUFBRSxLQUFLO0lBQ3hFLDREQUE0RCxFQUFFLEtBQUs7SUFDbkUsMERBQTBELEVBQUUsS0FBSztJQUNqRSx1RUFBdUUsRUFDbkUsS0FBSztDQUNaLENBQUM7QUFFRixNQUFNLE1BQU0sR0FBRztJQUNYLE9BQU8sRUFBRSxDQUFDLGdCQUFnQixDQUFDO0lBQzNCLEtBQUs7Q0FDUixDQUFDO0FBRUYsZUFBZSxNQUF1QyxDQUFDIn0=
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9Td2FnZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZ3Mvbm9Td2FnZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLG9FQUFvRTtBQUNwRSxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQWdEO0lBQzlELG1FQUFtRSxFQUFFLEtBQUs7SUFDMUUsZ0VBQWdFLEVBQUUsS0FBSztJQUN2RSxpRUFBaUUsRUFBRSxLQUFLO0lBQ3hFLDREQUE0RCxFQUFFLEtBQUs7SUFDbkUsMERBQTBELEVBQUUsS0FBSztJQUNqRSx1RUFBdUUsRUFDbkUsS0FBSztJQUNULGtFQUFrRSxFQUFFLEtBQUs7Q0FDNUUsQ0FBQztBQUVGLE1BQU0sTUFBTSxHQUFHO0lBQ1gsT0FBTyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7SUFDM0IsS0FBSztDQUNSLENBQUM7QUFFRixlQUFlLE1BQXVDLENBQUMifQ==
@@ -27,9 +27,12 @@ export const rules = {
27
27
  "@darraghor/nestjs-typed/api-operation-summary-description-capitalized": "error",
28
28
  "@darraghor/nestjs-typed/use-dependency-injection": "off",
29
29
  "@darraghor/nestjs-typed/use-correct-endpoint-naming-convention": "off",
30
+ "@darraghor/nestjs-typed/forward-ref-injection-should-use-wrapper-type": "error",
31
+ "@darraghor/nestjs-typed/swagger-file-upload-should-be-documented": "error",
32
+ "@darraghor/nestjs-typed/uploaded-file-should-be-validated": "error",
30
33
  };
31
34
  export default {
32
35
  extends: ["./configs/base"],
33
36
  rules,
34
37
  };
35
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb21tZW5kZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlncy9yZWNvbW1lbmRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQWdDO0lBQzlDLDJFQUEyRSxFQUN2RSxPQUFPO0lBQ1gsdURBQXVELEVBQUU7UUFDckQsT0FBTztRQUNQO1lBQ0ksR0FBRyxFQUFFLENBQUMsYUFBYSxDQUFDO1lBQ3BCLGVBQWUsRUFBRSxDQUFDLGNBQWMsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDO1NBQ3hEO0tBQ0o7SUFDRCxtRUFBbUUsRUFDL0QsT0FBTztJQUNYLGdFQUFnRSxFQUFFLE9BQU87SUFDekUsNERBQTRELEVBQUUsT0FBTztJQUNyRSwwREFBMEQsRUFBRSxPQUFPO0lBQ25FLHVFQUF1RSxFQUNuRSxPQUFPO0lBQ1gsbUVBQW1FLEVBQy9ELE9BQU87SUFDWCxrRUFBa0UsRUFBRSxPQUFPO0lBQzNFLCtFQUErRSxFQUMzRSxPQUFPO0lBQ1gsa0VBQWtFLEVBQUUsT0FBTztJQUMzRSx3REFBd0QsRUFBRSxPQUFPO0lBQ2pFLDhEQUE4RCxFQUFFLE9BQU87SUFDdkUsdURBQXVELEVBQUUsS0FBSztJQUM5RCxpRUFBaUUsRUFBRSxLQUFLO0lBQ3hFLHFEQUFxRCxFQUFFLEtBQUs7SUFDNUQsaURBQWlELEVBQUUsT0FBTztJQUMxRCx1REFBdUQsRUFBRSxPQUFPO0lBQ2hFLG1FQUFtRSxFQUMvRCxPQUFPO0lBQ1gsdUVBQXVFLEVBQ25FLE9BQU87SUFDWCxrREFBa0QsRUFBRSxLQUFLO0lBQ3pELGdFQUFnRSxFQUFFLEtBQUs7Q0FDMUUsQ0FBQztBQUNGLGVBQWU7SUFDWCxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztJQUMzQixLQUFLO0NBQ1IsQ0FBQyJ9
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb21tZW5kZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlncy9yZWNvbW1lbmRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQWdDO0lBQzlDLDJFQUEyRSxFQUN2RSxPQUFPO0lBQ1gsdURBQXVELEVBQUU7UUFDckQsT0FBTztRQUNQO1lBQ0ksR0FBRyxFQUFFLENBQUMsYUFBYSxDQUFDO1lBQ3BCLGVBQWUsRUFBRSxDQUFDLGNBQWMsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDO1NBQ3hEO0tBQ0o7SUFDRCxtRUFBbUUsRUFDL0QsT0FBTztJQUNYLGdFQUFnRSxFQUFFLE9BQU87SUFDekUsNERBQTRELEVBQUUsT0FBTztJQUNyRSwwREFBMEQsRUFBRSxPQUFPO0lBQ25FLHVFQUF1RSxFQUNuRSxPQUFPO0lBQ1gsbUVBQW1FLEVBQy9ELE9BQU87SUFDWCxrRUFBa0UsRUFBRSxPQUFPO0lBQzNFLCtFQUErRSxFQUMzRSxPQUFPO0lBQ1gsa0VBQWtFLEVBQUUsT0FBTztJQUMzRSx3REFBd0QsRUFBRSxPQUFPO0lBQ2pFLDhEQUE4RCxFQUFFLE9BQU87SUFDdkUsdURBQXVELEVBQUUsS0FBSztJQUM5RCxpRUFBaUUsRUFBRSxLQUFLO0lBQ3hFLHFEQUFxRCxFQUFFLEtBQUs7SUFDNUQsaURBQWlELEVBQUUsT0FBTztJQUMxRCx1REFBdUQsRUFBRSxPQUFPO0lBQ2hFLG1FQUFtRSxFQUMvRCxPQUFPO0lBQ1gsdUVBQXVFLEVBQ25FLE9BQU87SUFDWCxrREFBa0QsRUFBRSxLQUFLO0lBQ3pELGdFQUFnRSxFQUFFLEtBQUs7SUFDdkUsdUVBQXVFLEVBQ25FLE9BQU87SUFDWCxrRUFBa0UsRUFBRSxPQUFPO0lBQzNFLDJEQUEyRCxFQUFFLE9BQU87Q0FDdkUsQ0FBQztBQUNGLGVBQWU7SUFDWCxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztJQUMzQixLQUFLO0NBQ1IsQ0FBQyJ9
package/dist/index.d.ts CHANGED
@@ -92,6 +92,15 @@ declare const _default: {
92
92
  "use-dependency-injection": TSESLint.RuleModule<"useDependencyInjection", [], unknown, TSESLint.RuleListener> & {
93
93
  name: string;
94
94
  };
95
+ "forward-ref-injection-should-use-wrapper-type": TSESLint.RuleModule<"useWrapperType", [], unknown, TSESLint.RuleListener> & {
96
+ name: string;
97
+ };
98
+ "swagger-file-upload-should-be-documented": TSESLint.RuleModule<"missingApiBody" | "missingApiConsumes", import("./rules/swaggerFileUploadShouldBeDocumented/swaggerFileUploadShouldBeDocumented.js").SwaggerFileUploadShouldBeDocumentedOptions, unknown, TSESLint.RuleListener> & {
99
+ name: string;
100
+ };
101
+ "uploaded-file-should-be-validated": TSESLint.RuleModule<"missingFileValidation", import("./rules/uploadedFileShouldBeValidated/uploadedFileShouldBeValidated.js").UploadedFileShouldBeValidatedOptions, unknown, TSESLint.RuleListener> & {
102
+ name: string;
103
+ };
95
104
  };
96
105
  plugin: FlatConfig.Plugin;
97
106
  configs: {
@@ -0,0 +1,4 @@
1
+ declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"useWrapperType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
+ name: string;
3
+ };
4
+ export default rule;
@@ -0,0 +1,88 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ import ts from "typescript";
3
+ import { createRule } from "../../utils/createRule.js";
4
+ import { getParameterDecorators } from "../../utils/decorators.js";
5
+ const getForwardRefTargetName = (decorator) => {
6
+ if (decorator.expression.type !== AST_NODE_TYPES.CallExpression ||
7
+ decorator.expression.callee.type !== AST_NODE_TYPES.Identifier ||
8
+ decorator.expression.callee.name !== "Inject") {
9
+ return null;
10
+ }
11
+ const forwardRefCall = decorator.expression.arguments[0];
12
+ if (forwardRefCall?.type !== AST_NODE_TYPES.CallExpression ||
13
+ forwardRefCall.callee.type !== AST_NODE_TYPES.Identifier ||
14
+ forwardRefCall.callee.name !== "forwardRef") {
15
+ return null;
16
+ }
17
+ const callback = forwardRefCall.arguments[0];
18
+ if (callback?.type !== AST_NODE_TYPES.ArrowFunctionExpression ||
19
+ callback.body.type !== AST_NODE_TYPES.Identifier) {
20
+ return null;
21
+ }
22
+ return callback.body.name;
23
+ };
24
+ const getDirectTypeReference = (parameter) => {
25
+ const innerParameter = parameter.type === AST_NODE_TYPES.TSParameterProperty
26
+ ? parameter.parameter
27
+ : parameter;
28
+ if (innerParameter.type !== AST_NODE_TYPES.Identifier) {
29
+ return null;
30
+ }
31
+ const typeNode = innerParameter.typeAnnotation?.typeAnnotation;
32
+ if (typeNode?.type !== AST_NODE_TYPES.TSTypeReference ||
33
+ typeNode.typeName.type !== AST_NODE_TYPES.Identifier) {
34
+ return null;
35
+ }
36
+ return { name: typeNode.typeName.name, node: typeNode };
37
+ };
38
+ const rule = createRule({
39
+ name: "forward-ref-injection-should-use-wrapper-type",
40
+ meta: {
41
+ docs: {
42
+ description: "Requires forwardRef constructor injections to avoid a direct runtime type reference that can fail with ESM decorator metadata.",
43
+ },
44
+ messages: {
45
+ useWrapperType: "The type '{{typeName}}' is also referenced by forwardRef(). Wrap the parameter type (for example WrapperType<{{typeName}}>) or refactor the circular dependency to prevent an ESM initialization error.",
46
+ },
47
+ schema: [],
48
+ hasSuggestions: false,
49
+ type: "problem",
50
+ },
51
+ defaultOptions: [],
52
+ create(context) {
53
+ const program = context.sourceCode.parserServices?.program;
54
+ const compilerOptions = program?.getCompilerOptions();
55
+ const sourceFile = program?.getSourceFile(context.filename);
56
+ const isEsmDecoratorMetadataProject = compilerOptions?.emitDecoratorMetadata === true &&
57
+ compilerOptions.module !== undefined &&
58
+ compilerOptions.module !== ts.ModuleKind.CommonJS &&
59
+ sourceFile?.impliedNodeFormat !== ts.ModuleKind.CommonJS;
60
+ if (!isEsmDecoratorMetadataProject) {
61
+ return {};
62
+ }
63
+ return {
64
+ MethodDefinition(node) {
65
+ if (node.kind !== "constructor") {
66
+ return;
67
+ }
68
+ for (const parameter of node.value.params) {
69
+ const directType = getDirectTypeReference(parameter);
70
+ if (!directType) {
71
+ continue;
72
+ }
73
+ const matchingDecorator = getParameterDecorators(parameter).find((decorator) => getForwardRefTargetName(decorator) ===
74
+ directType.name);
75
+ if (matchingDecorator) {
76
+ context.report({
77
+ node: directType.node,
78
+ messageId: "useWrapperType",
79
+ data: { typeName: directType.name },
80
+ });
81
+ }
82
+ }
83
+ },
84
+ };
85
+ },
86
+ });
87
+ export default rule;
88
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yd2FyZFJlZkluamVjdGlvblNob3VsZFVzZVdyYXBwZXJUeXBlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3J1bGVzL2ZvcndhcmRSZWZJbmplY3Rpb25TaG91bGRVc2VXcmFwcGVyVHlwZS9mb3J3YXJkUmVmSW5qZWN0aW9uU2hvdWxkVXNlV3JhcHBlclR5cGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGNBQWMsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUM1QixPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sMkJBQTJCLENBQUM7QUFDckQsT0FBTyxFQUFDLHNCQUFzQixFQUFDLE1BQU0sMkJBQTJCLENBQUM7QUFFakUsTUFBTSx1QkFBdUIsR0FBRyxDQUM1QixTQUE2QixFQUNoQixFQUFFO0lBQ2YsSUFDSSxTQUFTLENBQUMsVUFBVSxDQUFDLElBQUksS0FBSyxjQUFjLENBQUMsY0FBYztRQUMzRCxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssY0FBYyxDQUFDLFVBQVU7UUFDOUQsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFDL0MsQ0FBQztRQUNDLE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFFRCxNQUFNLGNBQWMsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN6RCxJQUNJLGNBQWMsRUFBRSxJQUFJLEtBQUssY0FBYyxDQUFDLGNBQWM7UUFDdEQsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssY0FBYyxDQUFDLFVBQVU7UUFDeEQsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssWUFBWSxFQUM3QyxDQUFDO1FBQ0MsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUVELE1BQU0sUUFBUSxHQUFH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
@@ -79,5 +79,14 @@ declare const allRules: {
79
79
  "use-dependency-injection": import("@typescript-eslint/utils/ts-eslint").RuleModule<"useDependencyInjection", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
80
80
  name: string;
81
81
  };
82
+ "forward-ref-injection-should-use-wrapper-type": import("@typescript-eslint/utils/ts-eslint").RuleModule<"useWrapperType", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
83
+ name: string;
84
+ };
85
+ "swagger-file-upload-should-be-documented": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingApiBody" | "missingApiConsumes", import("./swaggerFileUploadShouldBeDocumented/swaggerFileUploadShouldBeDocumented.js").SwaggerFileUploadShouldBeDocumentedOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
86
+ name: string;
87
+ };
88
+ "uploaded-file-should-be-validated": import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingFileValidation", import("./uploadedFileShouldBeValidated/uploadedFileShouldBeValidated.js").UploadedFileShouldBeValidatedOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
89
+ name: string;
90
+ };
82
91
  };
83
92
  export default allRules;
@@ -20,6 +20,9 @@ import useInjectableProvidedToken from "./useInjectableProvidedToken/useInjectab
20
20
  import apiPropertyShouldHaveApiExtraModels from "./apiPropertyShouldHaveApiExtraModels/apiPropertyShouldHaveApiExtraModels.js";
21
21
  import apiOperationSummaryDescriptionCapitalized from "./apiOperationSummaryDescriptionCapitalized/apiOperationSummaryDescriptionCapitalized.js";
22
22
  import useDependencyInjection from "./useDependencyInjection/useDependencyInjection.js";
23
+ import forwardRefInjectionShouldUseWrapperType from "./forwardRefInjectionShouldUseWrapperType/forwardRefInjectionShouldUseWrapperType.js";
24
+ import swaggerFileUploadShouldBeDocumented from "./swaggerFileUploadShouldBeDocumented/swaggerFileUploadShouldBeDocumented.js";
25
+ import uploadedFileShouldBeValidated from "./uploadedFileShouldBeValidated/uploadedFileShouldBeValidated.js";
23
26
  const allRules = {
24
27
  "all-properties-have-explicit-defined": allPropertiesHaveExplicitDefined,
25
28
  "api-property-matches-property-optionality": apiPropertyMatchesPropertyOptionality,
@@ -43,6 +46,9 @@ const allRules = {
43
46
  "api-property-should-have-api-extra-models": apiPropertyShouldHaveApiExtraModels,
44
47
  "api-operation-summary-description-capitalized": apiOperationSummaryDescriptionCapitalized,
45
48
  "use-dependency-injection": useDependencyInjection,
49
+ "forward-ref-injection-should-use-wrapper-type": forwardRefInjectionShouldUseWrapperType,
50
+ "swagger-file-upload-should-be-documented": swaggerFileUploadShouldBeDocumented,
51
+ "uploaded-file-should-be-validated": uploadedFileShouldBeValidated,
46
52
  };
47
53
  export default allRules;
48
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVsZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTywwQkFBMEIsTUFBTSw2REFBNkQsQ0FBQztBQUNyRyxPQUFPLDRDQUE0QyxNQUFNLDRFQUE0RSxDQUFDO0FBQ3RJLE9BQU8scUNBQXFDLE1BQU0sa0ZBQWtGLENBQUM7QUFDckksT0FBTyw2QkFBNkIsTUFBTSxrRUFBa0UsQ0FBQztBQUM3RyxPQUFPLGtDQUFrQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzVILE9BQU8sNEJBQTRCLE1BQU0sZ0VBQWdFLENBQUM7QUFDMUcsT0FBTyx1Q0FBdUMsTUFBTSxzRkFBc0YsQ0FBQztBQUMzSSxPQUFPLGdDQUFnQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzFILE9BQU8sdUNBQXVDLE1BQU0sOEVBQThFLENBQUM7QUFDbkksT0FBTyxtQ0FBbUMsTUFBTSxpRkFBaUYsQ0FBQztBQUNsSSxPQUFPLGtDQUFrQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzVILE9BQU8sMkJBQTJCLE1BQU0sOERBQThELENBQUM7QUFDdkcsT0FBTyxnQ0FBZ0MsTUFBTSx3RUFBd0UsQ0FBQztBQUN0SCxPQUFPLHlCQUF5QixNQUFNLDBEQUEwRCxDQUFDO0FBQ2pHLE9BQU8sbUNBQW1DLE1BQU0sOEVBQThFLENBQUM7QUFDL0gsT0FBTyx3QkFBd0IsTUFBTSx3REFBd0QsQ0FBQztBQUM5RixPQUFPLHFCQUFxQixNQUFNLGtEQUFrRCxDQUFDO0FBQ3JGLE9BQU8sa0NBQWtDLE1BQU0sNEVBQTRFLENBQUM7QUFDNUgsT0FBTywwQkFBMEIsTUFBTSw0REFBNEQsQ0FBQztBQUNwRyxPQUFPLG1DQUFtQyxNQUFNLDhFQUE4RSxDQUFDO0FBQy9ILE9BQU8seUNBQXlDLE1BQU0sMEZBQTBGLENBQUM7QUFDakosT0FBTyxzQkFBc0IsTUFBTSxvREFBb0QsQ0FBQztBQUN4RixNQUFNLFFBQVEsR0FBRztJQUNiLHNDQUFzQyxFQUFFLGdDQUFnQztJQUN4RSwyQ0FBMkMsRUFDdkMscUNBQXFDO0lBQ3pDLCtCQUErQixFQUFFLDBCQUEwQjtJQUMzRCx5QkFBeUIsRUFBRSxxQkFBcUI7SUFDaEQsbURBQW1ELEVBQy9DLDRDQUE0QztJQUNoRCxvQ0FBb0MsRUFBRSw2QkFBNkI7SUFDbkUsd0NBQXdDLEVBQ3BDLGtDQUFrQztJQUN0Qyx5Q0FBeUMsRUFDckMsbUNBQW1DO0lBQ3ZDLGtDQUFrQyxFQUFFLDRCQUE0QjtJQUNoRSwrQ0FBK0MsRUFDM0MsdUNBQXVDO0lBQzNDLDJDQUEyQyxFQUN2QyxnQ0FBZ0M7SUFDcEMsMENBQTBDLEVBQ3RDLHVDQUF1QztJQUMzQyx1REFBdUQsRUFDbkQsbUNBQW1DO0lBQ3ZDLDBDQUEwQyxFQUN0QyxrQ0FBa0M7SUFDdEMsZ0NBQWdDLEVBQUUsMkJBQTJCO0lBQzdELCtCQUErQixFQUFFLHlCQUF5QjtJQUMxRCw2QkFBNkIsRUFBRSx3QkFBd0I7SUFDdkQsd0NBQXdDLEVBQ3BDLGtDQUFrQztJQUN0QywrQkFBK0IsRUFBRSwwQkFBMEI7SUFDM0QsMkNBQTJDLEVBQ3ZDLG1DQUFtQztJQUN2QywrQ0FBK0MsRUFDM0MseUNBQXlDO0lBQzdDLDBCQUEwQixFQUFFLHNCQUFzQjtDQUNyRCxDQUFDO0FBRUYsZUFBZSxRQUFRLENBQUMifQ==
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVsZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTywwQkFBMEIsTUFBTSw2REFBNkQsQ0FBQztBQUNyRyxPQUFPLDRDQUE0QyxNQUFNLDRFQUE0RSxDQUFDO0FBQ3RJLE9BQU8scUNBQXFDLE1BQU0sa0ZBQWtGLENBQUM7QUFDckksT0FBTyw2QkFBNkIsTUFBTSxrRUFBa0UsQ0FBQztBQUM3RyxPQUFPLGtDQUFrQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzVILE9BQU8sNEJBQTRCLE1BQU0sZ0VBQWdFLENBQUM7QUFDMUcsT0FBTyx1Q0FBdUMsTUFBTSxzRkFBc0YsQ0FBQztBQUMzSSxPQUFPLGdDQUFnQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzFILE9BQU8sdUNBQXVDLE1BQU0sOEVBQThFLENBQUM7QUFDbkksT0FBTyxtQ0FBbUMsTUFBTSxpRkFBaUYsQ0FBQztBQUNsSSxPQUFPLGtDQUFrQyxNQUFNLDRFQUE0RSxDQUFDO0FBQzVILE9BQU8sMkJBQTJCLE1BQU0sOERBQThELENBQUM7QUFDdkcsT0FBTyxnQ0FBZ0MsTUFBTSx3RUFBd0UsQ0FBQztBQUN0SCxPQUFPLHlCQUF5QixNQUFNLDBEQUEwRCxDQUFDO0FBQ2pHLE9BQU8sbUNBQW1DLE1BQU0sOEVBQThFLENBQUM7QUFDL0gsT0FBTyx3QkFBd0IsTUFBTSx3REFBd0QsQ0FBQztBQUM5RixPQUFPLHFCQUFxQixNQUFNLGtEQUFrRCxDQUFDO0FBQ3JGLE9BQU8sa0NBQWtDLE1BQU0sNEVBQTRFLENBQUM7QUFDNUgsT0FBTywwQkFBMEIsTUFBTSw0REFBNEQsQ0FBQztBQUNwRyxPQUFPLG1DQUFtQyxNQUFNLDhFQUE4RSxDQUFDO0FBQy9ILE9BQU8seUNBQXlDLE1BQU0sMEZBQTBGLENBQUM7QUFDakosT0FBTyxzQkFBc0IsTUFBTSxvREFBb0QsQ0FBQztBQUN4RixPQUFPLHVDQUF1QyxNQUFNLHNGQUFzRixDQUFDO0FBQzNJLE9BQU8sbUNBQW1DLE1BQU0sOEVBQThFLENBQUM7QUFDL0gsT0FBTyw2QkFBNkIsTUFBTSxrRUFBa0UsQ0FBQztBQUM3RyxNQUFNLFFBQVEsR0FBRztJQUNiLHNDQUFzQyxFQUFFLGdDQUFnQztJQUN4RSwyQ0FBMkMsRUFDdkMscUNBQXFDO0lBQ3pDLCtCQUErQixFQUFFLDBCQUEwQjtJQUMzRCx5QkFBeUIsRUFBRSxxQkFBcUI7SUFDaEQsbURBQW1ELEVBQy9DLDRDQUE0QztJQUNoRCxvQ0FBb0MsRUFBRSw2QkFBNkI7SUFDbkUsd0NBQXdDLEVBQ3BDLGtDQUFrQztJQUN0Qyx5Q0FBeUMsRUFDckMsbUNBQW1DO0lBQ3ZDLGtDQUFrQyxFQUFFLDRCQUE0QjtJQUNoRSwrQ0FBK0MsRUFDM0MsdUNBQXVDO0lBQzNDLDJDQUEyQyxFQUN2QyxnQ0FBZ0M7SUFDcEMsMENBQTBDLEVBQ3RDLHVDQUF1QztJQUMzQyx1REFBdUQsRUFDbkQsbUNBQW1DO0lBQ3ZDLDBDQUEwQyxFQUN0QyxrQ0FBa0M7SUFDdEMsZ0NBQWdDLEVBQUUsMkJBQTJCO0lBQzdELCtCQUErQixFQUFFLHlCQUF5QjtJQUMxRCw2QkFBNkIsRUFBRSx3QkFBd0I7SUFDdkQsd0NBQXdDLEVBQ3BDLGtDQUFrQztJQUN0QywrQkFBK0IsRUFBRSwwQkFBMEI7SUFDM0QsMkNBQTJDLEVBQ3ZDLG1DQUFtQztJQUN2QywrQ0FBK0MsRUFDM0MseUNBQXlDO0lBQzdDLDBCQUEwQixFQUFFLHNCQUFzQjtJQUNsRCwrQ0FBK0MsRUFDM0MsdUNBQXVDO0lBQzNDLDBDQUEwQyxFQUN0QyxtQ0FBbUM7SUFDdkMsbUNBQW1DLEVBQUUsNkJBQTZCO0NBQ3JFLENBQUM7QUFFRixlQUFlLFFBQVEsQ0FBQyJ9
@@ -0,0 +1,9 @@
1
+ export type SwaggerFileUploadShouldBeDocumentedOptions = [
2
+ {
3
+ additionalSwaggerDecorators: string[];
4
+ }
5
+ ];
6
+ declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingApiBody" | "missingApiConsumes", SwaggerFileUploadShouldBeDocumentedOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
7
+ name: string;
8
+ };
9
+ export default rule;
@@ -0,0 +1,91 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ import { createRule } from "../../utils/createRule.js";
3
+ import { getUploadedFileDecorators, nodeHasAnyDecoratorNamed, } from "../../utils/nestFileUpload.js";
4
+ import { typedTokenHelpers } from "../../utils/typedTokenHelpers.js";
5
+ const httpMethodDecoratorNames = [
6
+ "Get",
7
+ "Post",
8
+ "Put",
9
+ "Delete",
10
+ "Patch",
11
+ "Options",
12
+ "Head",
13
+ "All",
14
+ ];
15
+ const hasMultipartConsumesDecorator = (node) => typedTokenHelpers
16
+ .getDecoratorsNamed(node, ["ApiConsumes"])
17
+ .some((decorator) => {
18
+ if (decorator.expression.type !== AST_NODE_TYPES.CallExpression) {
19
+ return false;
20
+ }
21
+ return decorator.expression.arguments.some((argument) => argument.type === AST_NODE_TYPES.Literal &&
22
+ argument.value === "multipart/form-data");
23
+ });
24
+ const rule = createRule({
25
+ name: "swagger-file-upload-should-be-documented",
26
+ meta: {
27
+ docs: {
28
+ description: "Requires Swagger file-upload endpoints to declare multipart consumption and an API body schema.",
29
+ },
30
+ messages: {
31
+ missingApiConsumes: "File-upload endpoints should use @ApiConsumes('multipart/form-data') so the generated OpenAPI operation declares the correct content type.",
32
+ missingApiBody: "File-upload endpoints should use @ApiBody() with a binary file schema so the uploaded file is represented in OpenAPI.",
33
+ },
34
+ schema: [
35
+ {
36
+ type: "object",
37
+ additionalProperties: false,
38
+ properties: {
39
+ additionalSwaggerDecorators: {
40
+ description: "Custom method or controller decorators that provide both multipart consumption and the upload body schema.",
41
+ type: "array",
42
+ items: { type: "string", minLength: 1 },
43
+ minItems: 0,
44
+ },
45
+ },
46
+ },
47
+ ],
48
+ hasSuggestions: false,
49
+ type: "suggestion",
50
+ },
51
+ defaultOptions: [{ additionalSwaggerDecorators: [] }],
52
+ create(context) {
53
+ const { additionalSwaggerDecorators } = context.options[0] ?? {
54
+ additionalSwaggerDecorators: [],
55
+ };
56
+ return {
57
+ MethodDefinition(node) {
58
+ if (getUploadedFileDecorators(node).length === 0 ||
59
+ !typedTokenHelpers.nodeHasDecoratorsNamed(node, httpMethodDecoratorNames)) {
60
+ return;
61
+ }
62
+ const containingClass = node.parent.parent;
63
+ if (containingClass.type !== AST_NODE_TYPES.ClassDeclaration) {
64
+ return;
65
+ }
66
+ if (typedTokenHelpers.nodeHasDecoratorsNamed(containingClass, [
67
+ "ApiExcludeController",
68
+ ]) ||
69
+ typedTokenHelpers.nodeHasDecoratorsNamed(node, [
70
+ "ApiExcludeEndpoint",
71
+ ]) ||
72
+ nodeHasAnyDecoratorNamed(node, additionalSwaggerDecorators) ||
73
+ nodeHasAnyDecoratorNamed(containingClass, additionalSwaggerDecorators)) {
74
+ return;
75
+ }
76
+ if (!hasMultipartConsumesDecorator(node) &&
77
+ !hasMultipartConsumesDecorator(containingClass)) {
78
+ context.report({
79
+ node,
80
+ messageId: "missingApiConsumes",
81
+ });
82
+ }
83
+ if (!typedTokenHelpers.nodeHasDecoratorsNamed(node, ["ApiBody"])) {
84
+ context.report({ node, messageId: "missingApiBody" });
85
+ }
86
+ },
87
+ };
88
+ },
89
+ });
90
+ export default rule;
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3dhZ2dlckZpbGVVcGxvYWRTaG91bGRCZURvY3VtZW50ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcnVsZXMvc3dhZ2dlckZpbGVVcGxvYWRTaG91bGRCZURvY3VtZW50ZWQvc3dhZ2dlckZpbGVVcGxvYWRTaG91bGRCZURvY3VtZW50ZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGNBQWMsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBQ2xFLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRCxPQUFPLEVBQ0gseUJBQXlCLEVBQ3pCLHdCQUF3QixHQUMzQixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGtDQUFrQyxDQUFDO0FBUW5FLE1BQU0sd0JBQXdCLEdBQUc7SUFDN0IsS0FBSztJQUNMLE1BQU07SUFDTixLQUFLO0lBQ0wsUUFBUTtJQUNSLE9BQU87SUFDUCxTQUFTO0lBQ1QsTUFBTTtJQUNOLEtBQUs7Q0FDUixDQUFDO0FBRUYsTUFBTSw2QkFBNkIsR0FBRyxDQUNsQyxJQUEyRCxFQUNwRCxFQUFFLENBQ1QsaUJBQWlCO0tBQ1osa0JBQWtCLENBQUMsSUFBSSxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUM7S0FDekMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUU7SUFDaEIsSUFBSSxTQUFTLENBQUMsVUFBVSxDQUFDLElBQUksS0FBSyxjQUFjLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDOUQsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUN0QyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ1QsUUFBUSxDQUFDLElBQUksS0FBSyxjQUFjLENBQUMsT0FBTztRQUN4QyxRQUFRLENBQUMsS0FBSyxLQUFLLHFCQUFxQixDQUMvQyxD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
@@ -0,0 +1,10 @@
1
+ export type UploadedFileShouldBeValidatedOptions = [
2
+ {
3
+ additionalFileValidationDecorators: string[];
4
+ additionalFileValidationPipes: string[];
5
+ }
6
+ ];
7
+ declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"missingFileValidation", UploadedFileShouldBeValidatedOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
8
+ name: string;
9
+ };
10
+ export default rule;
@@ -0,0 +1,79 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ import { createRule } from "../../utils/createRule.js";
3
+ import { decoratorArgumentsContainNamedConstruct, getUploadedFileDecorators, methodHasMulterFileSizeLimit, nodeHasAnyDecoratorNamed, } from "../../utils/nestFileUpload.js";
4
+ const rule = createRule({
5
+ name: "uploaded-file-should-be-validated",
6
+ meta: {
7
+ docs: {
8
+ description: "Requires uploaded files to be validated by a file pipe or constrained by a Multer file-size limit.",
9
+ },
10
+ messages: {
11
+ missingFileValidation: "Validate this uploaded file with ParseFilePipe/ParseFilePipeBuilder, a configured custom validation pipe, or a Multer limits.fileSize option.",
12
+ },
13
+ schema: [
14
+ {
15
+ type: "object",
16
+ additionalProperties: false,
17
+ properties: {
18
+ additionalFileValidationDecorators: {
19
+ description: "Custom method or controller decorators that establish file-upload validation.",
20
+ type: "array",
21
+ items: { type: "string", minLength: 1 },
22
+ minItems: 0,
23
+ },
24
+ additionalFileValidationPipes: {
25
+ description: "Custom pipe constructor names accepted as uploaded-file validation.",
26
+ type: "array",
27
+ items: { type: "string", minLength: 1 },
28
+ minItems: 0,
29
+ },
30
+ },
31
+ },
32
+ ],
33
+ hasSuggestions: false,
34
+ type: "problem",
35
+ },
36
+ defaultOptions: [
37
+ {
38
+ additionalFileValidationDecorators: [],
39
+ additionalFileValidationPipes: [],
40
+ },
41
+ ],
42
+ create(context) {
43
+ const { additionalFileValidationDecorators, additionalFileValidationPipes, } = context.options[0] ?? {
44
+ additionalFileValidationDecorators: [],
45
+ additionalFileValidationPipes: [],
46
+ };
47
+ const acceptedPipeNames = new Set([
48
+ "ParseFilePipe",
49
+ "ParseFilePipeBuilder",
50
+ ...additionalFileValidationPipes,
51
+ ]);
52
+ return {
53
+ MethodDefinition(node) {
54
+ const uploadDecorators = getUploadedFileDecorators(node);
55
+ if (uploadDecorators.length === 0) {
56
+ return;
57
+ }
58
+ const containingClass = node.parent.parent;
59
+ const hasCustomValidationDecorator = nodeHasAnyDecoratorNamed(node, additionalFileValidationDecorators) ||
60
+ (containingClass.type === AST_NODE_TYPES.ClassDeclaration &&
61
+ nodeHasAnyDecoratorNamed(containingClass, additionalFileValidationDecorators));
62
+ if (hasCustomValidationDecorator ||
63
+ methodHasMulterFileSizeLimit(node)) {
64
+ return;
65
+ }
66
+ for (const decorator of uploadDecorators) {
67
+ if (!decoratorArgumentsContainNamedConstruct(decorator, acceptedPipeNames)) {
68
+ context.report({
69
+ node: decorator,
70
+ messageId: "missingFileValidation",
71
+ });
72
+ }
73
+ }
74
+ },
75
+ };
76
+ },
77
+ });
78
+ export default rule;
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBsb2FkZWRGaWxlU2hvdWxkQmVWYWxpZGF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcnVsZXMvdXBsb2FkZWRGaWxlU2hvdWxkQmVWYWxpZGF0ZWQvdXBsb2FkZWRGaWxlU2hvdWxkQmVWYWxpZGF0ZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGNBQWMsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBQ2xFLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRCxPQUFPLEVBQ0gsdUNBQXVDLEVBQ3ZDLHlCQUF5QixFQUN6Qiw0QkFBNEIsRUFDNUIsd0JBQXdCLEdBQzNCLE1BQU0sK0JBQStCLENBQUM7QUFTdkMsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUdyQjtJQUNFLElBQUksRUFBRSxtQ0FBbUM7SUFDekMsSUFBSSxFQUFFO1FBQ0YsSUFBSSxFQUFFO1lBQ0YsV0FBVyxFQUNQLG9HQUFvRztTQUMzRztRQUNELFFBQVEsRUFBRTtZQUNOLHFCQUFxQixFQUNqQiwrSUFBK0k7U0FDdEo7UUFDRCxNQUFNLEVBQUU7WUFDSjtnQkFDSSxJQUFJLEVBQUUsUUFBUTtnQkFDZCxvQkFBb0IsRUFBRSxLQUFLO2dCQUMzQixVQUFVLEVBQUU7b0JBQ1Isa0NBQWtDLEVBQUU7d0JBQ2hDLFdBQVcsRUFDUCwrRUFBK0U7d0JBQ25GLElBQUksRUFBRSxPQUFPO3dCQUNiLEtBQUssRUFBRSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBQzt3QkFDckMsUUFBUSxFQUFFLENBQUM7cUJBQ2Q7b0JBQ0QsNkJBQTZCLEVBQUU7d0JBQzNCLFdBQVcsRUFDUCxxRUFBcUU7d0JBQ3pFLElBQUksRUFBRSxPQUFPO3dCQUNiLEtBQUssRUFBRSxFQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBQzt3QkFDckMsUUFBUSxFQUFFLENBQUM7cUJBQ2Q7aUJBQ0o7YUFDSjtTQUNKO1FBQ0QsY0FBYyxFQUFFLEtBQUs7UUFDckIsSUFBSSxFQUFFLFNBQVM7S0FDbEI7SUFDRCxjQUFjLEVBQUU7UUFDWjtZQUNJLGtDQUFrQyxFQUFFLEVBQUU7WUFDdEMsNkJBQTZCLEVBQUUsRUFBRTtTQUNwQztLQUNKO0lBQ0QsTUFBTSxDQUFDLE9BQU87UUFDVixNQUFNLEVBQ0Ysa0NBQWtDLEVBQ2xDLDZCQUE2QixHQUNoQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUk7WUFDdEIsa0NBQWtDLEVBQUUsRUFBRTtZQUN0Qyw2QkFBNkIsRUFBRSxFQUFFO1NBQ3BDLENBQUM7UUFDRixNQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxDQUFDO1lBQzlCLGVBQWU7WUFDZixzQkFBc0I7WUFDdEIsR0FBRyw2QkFBNkI7U0FDbkMsQ0FBQyxDQUFDO1FBRUgsT0FBTztZQUNILGdCQUFnQixDQUFDLElBQStCO2dCQUM1QyxNQUFNLGdCQUFnQixHQUFHLHlCQUF5QixDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN6RCxJQUFJLGdCQUFnQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDaEMsT0FBTztnQkFDWCxDQUFDO2dCQUVELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDO2dCQUMzQyxNQUFNLDRCQUE0QixHQUM5Qix3QkFBd0IsQ0FDcEIsSUFBSSxFQUNKLGtDQUFrQyxDQUNyQztvQkFDRCxDQUFDLGVBQWUsQ0FBQyxJQUFJLEtBQUssY0FBYyxDQUFDLGdCQUFnQjt3QkFDckQsd0JBQXdCLENBQ3BCLGVBQWUsRUFDZixrQ0FBa0MsQ0FDckMsQ0FBQyxDQUFDO2dCQUVYLElBQ0ksNEJBQTRCO29CQUM1Qiw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsRUFDcEMsQ0FBQztvQkFDQyxPQUFPO2dCQUNYLENBQUM7Z0JBRUQsS0FBSyxNQUFNLFNBQVMsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO29CQUN2QyxJQUNJLENBQUMsdUNBQXVDLENBQ3BDLFNBQVMsRUFDVCxpQkFBaUIsQ0FDcEIsRUFDSCxDQUFDO3dCQUNDLE9BQU8sQ0FBQyxNQUFNLENBQUM7NEJBQ1gsSUFBSSxFQUFFLFNBQVM7NEJBQ2YsU0FBUyxFQUFFLHVCQUF1Qjt5QkFDckMsQ0FBQyxDQUFDO29CQUNQLENBQUM7Z0JBQ0wsQ0FBQztZQUNMLENBQUM7U0FDSixDQUFDO0lBQ04sQ0FBQztDQUNKLENBQUMsQ0FBQztBQUVILGVBQWUsSUFBSSxDQUFDIn0=
@@ -0,0 +1,2 @@
1
+ import { TSESTree } from "@typescript-eslint/utils";
2
+ export declare const getParameterDecorators: (parameter: TSESTree.Parameter) => TSESTree.Decorator[];
@@ -0,0 +1,8 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ export const getParameterDecorators = (parameter) => {
3
+ if (parameter.type === AST_NODE_TYPES.TSParameterProperty) {
4
+ return parameter.decorators;
5
+ }
6
+ return parameter.decorators ?? [];
7
+ };
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVjb3JhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9kZWNvcmF0b3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBQyxjQUFjLEVBQVcsTUFBTSwwQkFBMEIsQ0FBQztBQUVsRSxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUNsQyxTQUE2QixFQUNULEVBQUU7SUFDdEIsSUFBSSxTQUFTLENBQUMsSUFBSSxLQUFLLGNBQWMsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQ3hELE9BQU8sU0FBUyxDQUFDLFVBQVUsQ0FBQztJQUNoQyxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztBQUN0QyxDQUFDLENBQUMifQ==
@@ -0,0 +1,5 @@
1
+ import { TSESTree } from "@typescript-eslint/utils";
2
+ export declare const getUploadedFileDecorators: (method: TSESTree.MethodDefinition) => TSESTree.Decorator[];
3
+ export declare const decoratorArgumentsContainNamedConstruct: (decorator: TSESTree.Decorator, names: Set<string>) => boolean;
4
+ export declare const methodHasMulterFileSizeLimit: (method: TSESTree.MethodDefinition) => boolean;
5
+ export declare const nodeHasAnyDecoratorNamed: (node: TSESTree.MethodDefinition | TSESTree.ClassDeclaration, decoratorNames: string[]) => boolean;
@@ -0,0 +1,116 @@
1
+ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
2
+ import { getParameterDecorators } from "./decorators.js";
3
+ import { typedTokenHelpers } from "./typedTokenHelpers.js";
4
+ const fileUploadDecoratorNames = new Set(["UploadedFile", "UploadedFiles"]);
5
+ const fileInterceptorNames = new Set([
6
+ "FileInterceptor",
7
+ "FilesInterceptor",
8
+ "FileFieldsInterceptor",
9
+ "AnyFilesInterceptor",
10
+ ]);
11
+ const isNode = (value) => typeof value === "object" &&
12
+ value !== null &&
13
+ "type" in value &&
14
+ typeof value.type === "string";
15
+ const walkNode = (node, predicate) => {
16
+ if (predicate(node)) {
17
+ return true;
18
+ }
19
+ for (const [key, value] of Object.entries(node)) {
20
+ if (["parent", "loc", "range", "tokens", "comments"].includes(key)) {
21
+ continue;
22
+ }
23
+ if (isNode(value) && walkNode(value, predicate)) {
24
+ return true;
25
+ }
26
+ if (Array.isArray(value) &&
27
+ value.some((item) => isNode(item) && walkNode(item, predicate))) {
28
+ return true;
29
+ }
30
+ }
31
+ return false;
32
+ };
33
+ const getCallName = (node) => {
34
+ if (node.callee.type === AST_NODE_TYPES.Identifier) {
35
+ return node.callee.name;
36
+ }
37
+ if (node.callee.type === AST_NODE_TYPES.MemberExpression &&
38
+ node.callee.property.type === AST_NODE_TYPES.Identifier) {
39
+ return node.callee.property.name;
40
+ }
41
+ return null;
42
+ };
43
+ const getPropertyName = (property) => {
44
+ if (property.key.type === AST_NODE_TYPES.Identifier) {
45
+ return property.key.name;
46
+ }
47
+ if (property.key.type === AST_NODE_TYPES.Literal &&
48
+ typeof property.key.value === "string") {
49
+ return property.key.value;
50
+ }
51
+ return null;
52
+ };
53
+ const objectHasFileSizeLimit = (node) => walkNode(node, (candidate) => {
54
+ if (candidate.type !== AST_NODE_TYPES.Property) {
55
+ return false;
56
+ }
57
+ if (getPropertyName(candidate) !== "limits" ||
58
+ candidate.value.type !== AST_NODE_TYPES.ObjectExpression) {
59
+ return false;
60
+ }
61
+ return candidate.value.properties.some((property) => property.type === AST_NODE_TYPES.Property &&
62
+ getPropertyName(property) === "fileSize");
63
+ });
64
+ export const getUploadedFileDecorators = (method) => method.value.params.flatMap((parameter) => getParameterDecorators(parameter).filter((decorator) => {
65
+ const name = typedTokenHelpers.getDecoratorName(decorator);
66
+ return name !== null && fileUploadDecoratorNames.has(name);
67
+ }));
68
+ export const decoratorArgumentsContainNamedConstruct = (decorator, names) => {
69
+ if (decorator.expression.type !== AST_NODE_TYPES.CallExpression) {
70
+ return false;
71
+ }
72
+ return decorator.expression.arguments.some((argument) => argument.type !== AST_NODE_TYPES.SpreadElement &&
73
+ walkNode(argument, (candidate) => {
74
+ if (candidate.type === AST_NODE_TYPES.Identifier) {
75
+ return names.has(candidate.name);
76
+ }
77
+ if (candidate.type !== AST_NODE_TYPES.CallExpression &&
78
+ candidate.type !== AST_NODE_TYPES.NewExpression) {
79
+ return false;
80
+ }
81
+ const name = getCallName(candidate);
82
+ return name !== null && names.has(name);
83
+ }));
84
+ };
85
+ export const methodHasMulterFileSizeLimit = (method) => {
86
+ const containingClass = method.parent.parent;
87
+ const decorators = [
88
+ ...method.decorators,
89
+ ...(containingClass.type === AST_NODE_TYPES.ClassDeclaration ||
90
+ containingClass.type === AST_NODE_TYPES.ClassExpression
91
+ ? containingClass.decorators
92
+ : []),
93
+ ];
94
+ return decorators.some((decorator) => {
95
+ if (typedTokenHelpers.getDecoratorName(decorator) !==
96
+ "UseInterceptors" ||
97
+ decorator.expression.type !== AST_NODE_TYPES.CallExpression) {
98
+ return false;
99
+ }
100
+ return decorator.expression.arguments.some((argument) => argument.type !== AST_NODE_TYPES.SpreadElement &&
101
+ walkNode(argument, (candidate) => {
102
+ if (candidate.type !== AST_NODE_TYPES.CallExpression) {
103
+ return false;
104
+ }
105
+ const callName = getCallName(candidate);
106
+ return (callName !== null &&
107
+ fileInterceptorNames.has(callName) &&
108
+ candidate.arguments.some((callArgument) => callArgument.type !==
109
+ AST_NODE_TYPES.SpreadElement &&
110
+ objectHasFileSizeLimit(callArgument)));
111
+ }));
112
+ });
113
+ };
114
+ export const nodeHasAnyDecoratorNamed = (node, decoratorNames) => decoratorNames.length > 0 &&
115
+ typedTokenHelpers.nodeHasDecoratorsNamed(node, decoratorNames);
116
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVzdEZpbGVVcGxvYWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvbmVzdEZpbGVVcGxvYWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGNBQWMsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBQ2xFLE9BQU8sRUFBQyxzQkFBc0IsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZELE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBRXpELE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxjQUFjLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztBQUM1RSxNQUFNLG9CQUFvQixHQUFHLElBQUksR0FBRyxDQUFDO0lBQ2pDLGlCQUFpQjtJQUNqQixrQkFBa0I7SUFDbEIsdUJBQXVCO0lBQ3ZCLHFCQUFxQjtDQUN4QixDQUFDLENBQUM7QUFFSCxNQUFNLE1BQU0sR0FBRyxDQUFDLEtBQWMsRUFBMEIsRUFBRSxDQUN0RCxPQUFPLEtBQUssS0FBSyxRQUFRO0lBQ3pCLEtBQUssS0FBSyxJQUFJO0lBQ2QsTUFBTSxJQUFJLEtBQUs7SUFDZixPQUFRLEtBQTBCLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQztBQUV6RCxNQUFNLFFBQVEsR0FBRyxDQUNiLElBQW1CLEVBQ25CLFNBQWdELEVBQ3pDLEVBQUU7SUFDVCxJQUFJLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2xCLE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFFRCxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzlDLElBQUksQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darraghor/eslint-plugin-nestjs-typed",
3
- "version": "7.3.3",
3
+ "version": "7.4.0",
4
4
  "description": "Eslint rules for nestjs projects",
5
5
  "scripts": {
6
6
  "clean": "rm -Rf ./dist/",
@@ -81,11 +81,11 @@
81
81
  "@typescript-eslint/parser": "8.67.0",
82
82
  "@typescript-eslint/rule-tester": "8.67.0",
83
83
  "class-validator": "0.15.1",
84
- "eslint": "10.8.0",
84
+ "eslint": "10.9.0",
85
85
  "eslint-config-prettier": "10.1.8",
86
86
  "eslint-plugin-prefer-arrow": "1.2.3",
87
87
  "eslint-plugin-unicorn": "73.0.0",
88
- "globals": "17.10.0",
88
+ "globals": "17.11.0",
89
89
  "husky": "9.1.7",
90
90
  "jest": "30.4.2",
91
91
  "jest-create-mock-instance": "2.0.0",
@@ -114,6 +114,6 @@
114
114
  "lint",
115
115
  "style"
116
116
  ],
117
- "packageManager": "pnpm@10.34.1",
117
+ "packageManager": "pnpm@11.24.0",
118
118
  "license": "ISC"
119
119
  }