@composurecdk/eslint-plugin 0.10.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/LICENSE +21 -0
- package/README.md +138 -0
- package/dist/commonjs/configs/presets.d.ts +42 -0
- package/dist/commonjs/configs/presets.d.ts.map +1 -0
- package/dist/commonjs/configs/presets.js +58 -0
- package/dist/commonjs/configs/presets.js.map +1 -0
- package/dist/commonjs/index.d.ts +84 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +63 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/rules/builder-must-be-tagged.d.ts +15 -0
- package/dist/commonjs/rules/builder-must-be-tagged.d.ts.map +1 -0
- package/dist/commonjs/rules/builder-must-be-tagged.js +70 -0
- package/dist/commonjs/rules/builder-must-be-tagged.js.map +1 -0
- package/dist/commonjs/rules/builder-must-implement-copy-state.d.ts +13 -0
- package/dist/commonjs/rules/builder-must-implement-copy-state.d.ts.map +1 -0
- package/dist/commonjs/rules/builder-must-implement-copy-state.js +123 -0
- package/dist/commonjs/rules/builder-must-implement-copy-state.js.map +1 -0
- package/dist/commonjs/rules/constraint-metadata-required.d.ts +16 -0
- package/dist/commonjs/rules/constraint-metadata-required.d.ts.map +1 -0
- package/dist/commonjs/rules/constraint-metadata-required.js +79 -0
- package/dist/commonjs/rules/constraint-metadata-required.js.map +1 -0
- package/dist/commonjs/rules/index.d.ts +14 -0
- package/dist/commonjs/rules/index.d.ts.map +1 -0
- package/dist/commonjs/rules/index.js +52 -0
- package/dist/commonjs/rules/index.js.map +1 -0
- package/dist/commonjs/rules/lib/imports.d.ts +24 -0
- package/dist/commonjs/rules/lib/imports.d.ts.map +1 -0
- package/dist/commonjs/rules/lib/imports.js +76 -0
- package/dist/commonjs/rules/lib/imports.js.map +1 -0
- package/dist/commonjs/rules/lifecycle-build-context-required.d.ts +14 -0
- package/dist/commonjs/rules/lifecycle-build-context-required.d.ts.map +1 -0
- package/dist/commonjs/rules/lifecycle-build-context-required.js +46 -0
- package/dist/commonjs/rules/lifecycle-build-context-required.js.map +1 -0
- package/dist/commonjs/rules/lifecycle-build-must-forward-context.d.ts +18 -0
- package/dist/commonjs/rules/lifecycle-build-must-forward-context.d.ts.map +1 -0
- package/dist/commonjs/rules/lifecycle-build-must-forward-context.js +54 -0
- package/dist/commonjs/rules/lifecycle-build-must-forward-context.js.map +1 -0
- package/dist/commonjs/rules/no-cdk-api-above-floor.d.ts +15 -0
- package/dist/commonjs/rules/no-cdk-api-above-floor.d.ts.map +1 -0
- package/dist/commonjs/rules/no-cdk-api-above-floor.js +80 -0
- package/dist/commonjs/rules/no-cdk-api-above-floor.js.map +1 -0
- package/dist/commonjs/rules/no-cjs-incompatible-syntax.d.ts +14 -0
- package/dist/commonjs/rules/no-cjs-incompatible-syntax.d.ts.map +1 -0
- package/dist/commonjs/rules/no-cjs-incompatible-syntax.js +55 -0
- package/dist/commonjs/rules/no-cjs-incompatible-syntax.js.map +1 -0
- package/dist/commonjs/rules/no-realm-bound-instanceof.d.ts +25 -0
- package/dist/commonjs/rules/no-realm-bound-instanceof.d.ts.map +1 -0
- package/dist/commonjs/rules/no-realm-bound-instanceof.js +98 -0
- package/dist/commonjs/rules/no-realm-bound-instanceof.js.map +1 -0
- package/dist/commonjs/rules/no-typescript-private-modifier.d.ts +17 -0
- package/dist/commonjs/rules/no-typescript-private-modifier.d.ts.map +1 -0
- package/dist/commonjs/rules/no-typescript-private-modifier.js +91 -0
- package/dist/commonjs/rules/no-typescript-private-modifier.js.map +1 -0
- package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.d.ts +17 -0
- package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.d.ts.map +1 -0
- package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.js +152 -0
- package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.js.map +1 -0
- package/dist/esm/configs/presets.d.ts +42 -0
- package/dist/esm/configs/presets.d.ts.map +1 -0
- package/dist/esm/configs/presets.js +55 -0
- package/dist/esm/configs/presets.js.map +1 -0
- package/dist/esm/index.d.ts +84 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +60 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/rules/builder-must-be-tagged.d.ts +15 -0
- package/dist/esm/rules/builder-must-be-tagged.d.ts.map +1 -0
- package/dist/esm/rules/builder-must-be-tagged.js +67 -0
- package/dist/esm/rules/builder-must-be-tagged.js.map +1 -0
- package/dist/esm/rules/builder-must-implement-copy-state.d.ts +13 -0
- package/dist/esm/rules/builder-must-implement-copy-state.d.ts.map +1 -0
- package/dist/esm/rules/builder-must-implement-copy-state.js +120 -0
- package/dist/esm/rules/builder-must-implement-copy-state.js.map +1 -0
- package/dist/esm/rules/constraint-metadata-required.d.ts +16 -0
- package/dist/esm/rules/constraint-metadata-required.d.ts.map +1 -0
- package/dist/esm/rules/constraint-metadata-required.js +76 -0
- package/dist/esm/rules/constraint-metadata-required.js.map +1 -0
- package/dist/esm/rules/index.d.ts +14 -0
- package/dist/esm/rules/index.d.ts.map +1 -0
- package/dist/esm/rules/index.js +49 -0
- package/dist/esm/rules/index.js.map +1 -0
- package/dist/esm/rules/lib/imports.d.ts +24 -0
- package/dist/esm/rules/lib/imports.d.ts.map +1 -0
- package/dist/esm/rules/lib/imports.js +70 -0
- package/dist/esm/rules/lib/imports.js.map +1 -0
- package/dist/esm/rules/lifecycle-build-context-required.d.ts +14 -0
- package/dist/esm/rules/lifecycle-build-context-required.d.ts.map +1 -0
- package/dist/esm/rules/lifecycle-build-context-required.js +43 -0
- package/dist/esm/rules/lifecycle-build-context-required.js.map +1 -0
- package/dist/esm/rules/lifecycle-build-must-forward-context.d.ts +18 -0
- package/dist/esm/rules/lifecycle-build-must-forward-context.d.ts.map +1 -0
- package/dist/esm/rules/lifecycle-build-must-forward-context.js +51 -0
- package/dist/esm/rules/lifecycle-build-must-forward-context.js.map +1 -0
- package/dist/esm/rules/no-cdk-api-above-floor.d.ts +15 -0
- package/dist/esm/rules/no-cdk-api-above-floor.d.ts.map +1 -0
- package/dist/esm/rules/no-cdk-api-above-floor.js +77 -0
- package/dist/esm/rules/no-cdk-api-above-floor.js.map +1 -0
- package/dist/esm/rules/no-cjs-incompatible-syntax.d.ts +14 -0
- package/dist/esm/rules/no-cjs-incompatible-syntax.d.ts.map +1 -0
- package/dist/esm/rules/no-cjs-incompatible-syntax.js +52 -0
- package/dist/esm/rules/no-cjs-incompatible-syntax.js.map +1 -0
- package/dist/esm/rules/no-realm-bound-instanceof.d.ts +25 -0
- package/dist/esm/rules/no-realm-bound-instanceof.d.ts.map +1 -0
- package/dist/esm/rules/no-realm-bound-instanceof.js +95 -0
- package/dist/esm/rules/no-realm-bound-instanceof.js.map +1 -0
- package/dist/esm/rules/no-typescript-private-modifier.d.ts +17 -0
- package/dist/esm/rules/no-typescript-private-modifier.d.ts.map +1 -0
- package/dist/esm/rules/no-typescript-private-modifier.js +88 -0
- package/dist/esm/rules/no-typescript-private-modifier.js.map +1 -0
- package/dist/esm/rules/redeclared-prop-must-track-cdk-type.d.ts +17 -0
- package/dist/esm/rules/redeclared-prop-must-track-cdk-type.d.ts.map +1 -0
- package/dist/esm/rules/redeclared-prop-must-track-cdk-type.js +149 -0
- package/dist/esm/rules/redeclared-prop-must-track-cdk-type.js.map +1 -0
- package/docs/rules/builder-must-be-tagged.md +46 -0
- package/docs/rules/builder-must-implement-copy-state.md +50 -0
- package/docs/rules/constraint-metadata-required.md +44 -0
- package/docs/rules/lifecycle-build-context-required.md +39 -0
- package/docs/rules/lifecycle-build-must-forward-context.md +50 -0
- package/docs/rules/no-cdk-api-above-floor.md +56 -0
- package/docs/rules/no-cjs-incompatible-syntax.md +48 -0
- package/docs/rules/no-realm-bound-instanceof.md +87 -0
- package/docs/rules/no-typescript-private-modifier.md +72 -0
- package/docs/rules/redeclared-prop-must-track-cdk-type.md +60 -0
- package/package.json +81 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = void 0;
|
|
4
|
+
function readIgnoreMarker(fieldNode, sourceCode) {
|
|
5
|
+
const comments = sourceCode.getCommentsBefore(fieldNode);
|
|
6
|
+
for (const comment of comments) {
|
|
7
|
+
const match = /@copy-state:\s*ignore(.*)$/i.exec(comment.value);
|
|
8
|
+
if (!match)
|
|
9
|
+
continue;
|
|
10
|
+
const tail = match[1];
|
|
11
|
+
return /--\s*\S/.test(tail) ? "valid" : "missing-justification";
|
|
12
|
+
}
|
|
13
|
+
return "absent";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Flags a builder class holding private state with no `[COPY_STATE]` hook.
|
|
17
|
+
*
|
|
18
|
+
* `.copy()` shallow-clones the builder's props. State held in private fields sits
|
|
19
|
+
* outside that copy, so without the hook it is silently dropped: the clone looks
|
|
20
|
+
* correct and behaves differently. Implement `[COPY_STATE]` to carry such state
|
|
21
|
+
* onto the clone.
|
|
22
|
+
*
|
|
23
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/builder-must-implement-copy-state.md | the rule documentation}.
|
|
24
|
+
*/
|
|
25
|
+
exports.rule = {
|
|
26
|
+
meta: {
|
|
27
|
+
type: "problem",
|
|
28
|
+
docs: {
|
|
29
|
+
description: "Builder classes with private fields must implement `[COPY_STATE]` " +
|
|
30
|
+
"(or annotate fields with `// @copy-state: ignore -- reason`). See ADR-0005.",
|
|
31
|
+
},
|
|
32
|
+
schema: [],
|
|
33
|
+
messages: {
|
|
34
|
+
missingHook: "Builder class `{{className}}` has private field(s) {{fields}} but no `[COPY_STATE]` hook. " +
|
|
35
|
+
"`.copy()` shallow-clones props only, so these fields are silently dropped from the " +
|
|
36
|
+
"clone. Implement `[COPY_STATE](target) { … }` to carry them across, or annotate each " +
|
|
37
|
+
"field with `// @copy-state: ignore -- reason`.",
|
|
38
|
+
ignoreMarkerNeedsJustification: "`@copy-state: ignore` on field `{{field}}` must include a justification after `--` " +
|
|
39
|
+
"(e.g. `// @copy-state: ignore -- regenerated per build`). The reason survives refactors " +
|
|
40
|
+
"and shows up in code review.",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
create(ctx) {
|
|
44
|
+
const sourceCode = ctx.sourceCode;
|
|
45
|
+
const builderFactoryNames = new Set();
|
|
46
|
+
const classNodes = new Map();
|
|
47
|
+
const builderClassNames = new Set();
|
|
48
|
+
return {
|
|
49
|
+
ImportDeclaration(node) {
|
|
50
|
+
if (node.source.value !== "@composurecdk/core" &&
|
|
51
|
+
node.source.value !== "@composurecdk/cloudformation") {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const spec of node.specifiers) {
|
|
55
|
+
if (spec.type !== "ImportSpecifier")
|
|
56
|
+
continue;
|
|
57
|
+
if (spec.imported.type !== "Identifier")
|
|
58
|
+
continue;
|
|
59
|
+
if (spec.imported.name === "Builder" || spec.imported.name === "taggedBuilder") {
|
|
60
|
+
builderFactoryNames.add(spec.local.name);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
ClassDeclaration(node) {
|
|
65
|
+
classNodes.set(node.id.name, node);
|
|
66
|
+
},
|
|
67
|
+
CallExpression(node) {
|
|
68
|
+
if (node.callee.type !== "Identifier")
|
|
69
|
+
return;
|
|
70
|
+
if (!builderFactoryNames.has(node.callee.name))
|
|
71
|
+
return;
|
|
72
|
+
if (node.arguments.length === 0)
|
|
73
|
+
return;
|
|
74
|
+
const arg = node.arguments[0];
|
|
75
|
+
if (arg.type === "Identifier")
|
|
76
|
+
builderClassNames.add(arg.name);
|
|
77
|
+
},
|
|
78
|
+
"Program:exit"() {
|
|
79
|
+
for (const className of builderClassNames) {
|
|
80
|
+
const classNode = classNodes.get(className);
|
|
81
|
+
if (!classNode)
|
|
82
|
+
continue;
|
|
83
|
+
const privateFields = [];
|
|
84
|
+
let hasCopyStateHook = false;
|
|
85
|
+
for (const member of classNode.body.body) {
|
|
86
|
+
if (member.type === "PropertyDefinition" && member.key.type === "PrivateIdentifier") {
|
|
87
|
+
privateFields.push(member);
|
|
88
|
+
}
|
|
89
|
+
else if (member.type === "MethodDefinition" &&
|
|
90
|
+
member.computed &&
|
|
91
|
+
member.key.type === "Identifier" &&
|
|
92
|
+
member.key.name === "COPY_STATE") {
|
|
93
|
+
hasCopyStateHook = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const fieldsNeedingHook = [];
|
|
97
|
+
for (const field of privateFields) {
|
|
98
|
+
const ignoreState = readIgnoreMarker(field, sourceCode);
|
|
99
|
+
if (ignoreState === "valid")
|
|
100
|
+
continue;
|
|
101
|
+
if (ignoreState === "missing-justification") {
|
|
102
|
+
ctx.report({
|
|
103
|
+
node: field,
|
|
104
|
+
messageId: "ignoreMarkerNeedsJustification",
|
|
105
|
+
data: { field: `#${field.key.name}` },
|
|
106
|
+
});
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
fieldsNeedingHook.push(`#${field.key.name}`);
|
|
110
|
+
}
|
|
111
|
+
if (!hasCopyStateHook && fieldsNeedingHook.length > 0) {
|
|
112
|
+
ctx.report({
|
|
113
|
+
node: classNode.id,
|
|
114
|
+
messageId: "missingHook",
|
|
115
|
+
data: { className, fields: fieldsNeedingHook.join(", ") },
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=builder-must-implement-copy-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-must-implement-copy-state.js","sourceRoot":"","sources":["../../../src/rules/builder-must-implement-copy-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Requires every `stringConstraint({ … })` call to set a non-empty `name`,
|
|
4
|
+
* `allowed` and `source`.
|
|
5
|
+
*
|
|
6
|
+
* Those three fields are what turn a synth-time validation failure into
|
|
7
|
+
* something actionable — they name the offending property, list the characters
|
|
8
|
+
* it accepts, and link the AWS documentation. The factory's type already makes
|
|
9
|
+
* the keys required, so the gap this closes is the one the type checker cannot
|
|
10
|
+
* see: a present-but-empty string compiles happily while degrading every message
|
|
11
|
+
* the constraint will ever produce.
|
|
12
|
+
*
|
|
13
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/constraint-metadata-required.md | the rule documentation}.
|
|
14
|
+
*/
|
|
15
|
+
export declare const rule: Rule.RuleModule;
|
|
16
|
+
//# sourceMappingURL=constraint-metadata-required.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraint-metadata-required.d.ts","sourceRoot":"","sources":["../../../src/rules/constraint-metadata-required.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAgBnC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAgDvB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = void 0;
|
|
4
|
+
const REQUIRED_FIELDS = ["name", "allowed", "source"];
|
|
5
|
+
function propertyKey(property) {
|
|
6
|
+
if (property.computed)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (property.key.type === "Identifier")
|
|
9
|
+
return property.key.name;
|
|
10
|
+
if (property.key.type === "Literal")
|
|
11
|
+
return String(property.key.value);
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
function isEmptyStringLiteral(value) {
|
|
15
|
+
return value.type === "Literal" && typeof value.value === "string" && value.value.trim() === "";
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Requires every `stringConstraint({ … })` call to set a non-empty `name`,
|
|
19
|
+
* `allowed` and `source`.
|
|
20
|
+
*
|
|
21
|
+
* Those three fields are what turn a synth-time validation failure into
|
|
22
|
+
* something actionable — they name the offending property, list the characters
|
|
23
|
+
* it accepts, and link the AWS documentation. The factory's type already makes
|
|
24
|
+
* the keys required, so the gap this closes is the one the type checker cannot
|
|
25
|
+
* see: a present-but-empty string compiles happily while degrading every message
|
|
26
|
+
* the constraint will ever produce.
|
|
27
|
+
*
|
|
28
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/constraint-metadata-required.md | the rule documentation}.
|
|
29
|
+
*/
|
|
30
|
+
exports.rule = {
|
|
31
|
+
meta: {
|
|
32
|
+
type: "problem",
|
|
33
|
+
docs: {
|
|
34
|
+
description: "stringConstraint() must set a non-empty name, allowed, and source so every validation error names the allowed set and links the AWS doc",
|
|
35
|
+
},
|
|
36
|
+
schema: [],
|
|
37
|
+
messages: {
|
|
38
|
+
missingField: "stringConstraint() is missing required `{{field}}`. Every catalogue entry must set " +
|
|
39
|
+
"name, allowed and source, so a synth-time error can name the allowed set and link the AWS doc.",
|
|
40
|
+
emptyField: "stringConstraint() `{{field}}` is empty. It is surfaced verbatim in the validation " +
|
|
41
|
+
"error message — give it a meaningful value.",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
create(ctx) {
|
|
45
|
+
return {
|
|
46
|
+
CallExpression(node) {
|
|
47
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "stringConstraint") {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (node.arguments.length === 0)
|
|
51
|
+
return;
|
|
52
|
+
const arg = node.arguments[0];
|
|
53
|
+
if (arg.type !== "ObjectExpression")
|
|
54
|
+
return;
|
|
55
|
+
// A spread could supply any of the required fields — can't verify statically.
|
|
56
|
+
if (arg.properties.some((p) => p.type === "SpreadElement"))
|
|
57
|
+
return;
|
|
58
|
+
const values = new Map();
|
|
59
|
+
for (const property of arg.properties) {
|
|
60
|
+
if (property.type !== "Property")
|
|
61
|
+
continue;
|
|
62
|
+
const key = propertyKey(property);
|
|
63
|
+
if (key !== undefined)
|
|
64
|
+
values.set(key, property.value);
|
|
65
|
+
}
|
|
66
|
+
for (const field of REQUIRED_FIELDS) {
|
|
67
|
+
const value = values.get(field);
|
|
68
|
+
if (value === undefined) {
|
|
69
|
+
ctx.report({ node, messageId: "missingField", data: { field } });
|
|
70
|
+
}
|
|
71
|
+
else if (isEmptyStringLiteral(value)) {
|
|
72
|
+
ctx.report({ node: value, messageId: "emptyField", data: { field } });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=constraint-metadata-required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraint-metadata-required.js","sourceRoot":"","sources":["../../../src/rules/constraint-metadata-required.ts"],"names":[],"mappings":";;;AAGA,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAC;AAE/D,SAAS,WAAW,CAAC,QAAkB;IACrC,IAAI,QAAQ,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IACjE,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,oBAAoB,CAAC,KAA2B;IACvD,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAClG,CAAC;AAED;;;;;;;;;;;;GAYG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,yIAAyI;SAC5I;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,YAAY,EACV,qFAAqF;gBACrF,gGAAgG;YAClG,UAAU,EACR,qFAAqF;gBACrF,6CAA6C;SAChD;KACF;IACD,MAAM,CAAC,GAAG;QACR,OAAO;YACL,cAAc,CAAC,IAAoB;gBACjC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBACjF,OAAO;gBACT,CAAC;gBACD,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBACxC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,GAAG,CAAC,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBAE5C,8EAA8E;gBAC9E,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC;oBAAE,OAAO;gBAEnE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAgC,CAAC;gBACvD,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;oBACtC,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU;wBAAE,SAAS;oBAC3C,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;oBAClC,IAAI,GAAG,KAAK,SAAS;wBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;gBACzD,CAAC;gBAED,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;oBACpC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxB,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;oBACnE,CAAC;yBAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;wBACvC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;oBACxE,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
export declare const rules: {
|
|
3
|
+
"builder-must-be-tagged": Rule.RuleModule;
|
|
4
|
+
"builder-must-implement-copy-state": Rule.RuleModule;
|
|
5
|
+
"constraint-metadata-required": Rule.RuleModule;
|
|
6
|
+
"lifecycle-build-context-required": Rule.RuleModule;
|
|
7
|
+
"lifecycle-build-must-forward-context": Rule.RuleModule;
|
|
8
|
+
"no-cdk-api-above-floor": Rule.RuleModule;
|
|
9
|
+
"no-cjs-incompatible-syntax": Rule.RuleModule;
|
|
10
|
+
"no-realm-bound-instanceof": Rule.RuleModule;
|
|
11
|
+
"no-typescript-private-modifier": Rule.RuleModule;
|
|
12
|
+
"redeclared-prop-must-track-cdk-type": Rule.RuleModule;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA6CnC,eAAO,MAAM,KAAK;;;;;;;;;;;CAWhB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rules = void 0;
|
|
4
|
+
const builder_must_be_tagged_js_1 = require("./builder-must-be-tagged.js");
|
|
5
|
+
const builder_must_implement_copy_state_js_1 = require("./builder-must-implement-copy-state.js");
|
|
6
|
+
const constraint_metadata_required_js_1 = require("./constraint-metadata-required.js");
|
|
7
|
+
const lifecycle_build_context_required_js_1 = require("./lifecycle-build-context-required.js");
|
|
8
|
+
const lifecycle_build_must_forward_context_js_1 = require("./lifecycle-build-must-forward-context.js");
|
|
9
|
+
const no_cdk_api_above_floor_js_1 = require("./no-cdk-api-above-floor.js");
|
|
10
|
+
const no_cjs_incompatible_syntax_js_1 = require("./no-cjs-incompatible-syntax.js");
|
|
11
|
+
const no_realm_bound_instanceof_js_1 = require("./no-realm-bound-instanceof.js");
|
|
12
|
+
const no_typescript_private_modifier_js_1 = require("./no-typescript-private-modifier.js");
|
|
13
|
+
const redeclared_prop_must_track_cdk_type_js_1 = require("./redeclared-prop-must-track-cdk-type.js");
|
|
14
|
+
/**
|
|
15
|
+
* Where each rule's documentation lives — the page an editor opens from a
|
|
16
|
+
* reported violation.
|
|
17
|
+
*
|
|
18
|
+
* Pinned to `main` rather than the release tag: reading the package's own
|
|
19
|
+
* version needs a JSON import, which does not emit cleanly to CommonJS
|
|
20
|
+
* (ADR-0007). The cost is that a consumer on an older version is shown current
|
|
21
|
+
* docs, which is the same trade most published plugins make.
|
|
22
|
+
*/
|
|
23
|
+
const DOCS_BASE = "https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules";
|
|
24
|
+
/**
|
|
25
|
+
* Attaches `meta.docs.url` to every rule, derived from the name it is
|
|
26
|
+
* registered under.
|
|
27
|
+
*
|
|
28
|
+
* Deriving beats writing it per rule: the link an editor offers cannot disagree
|
|
29
|
+
* with the rule id ESLint reports, and adding a rule cannot forget it.
|
|
30
|
+
*/
|
|
31
|
+
function withDocsUrl(entries) {
|
|
32
|
+
return Object.fromEntries(Object.entries(entries).map(([name, rule]) => [
|
|
33
|
+
name,
|
|
34
|
+
{
|
|
35
|
+
...rule,
|
|
36
|
+
meta: { ...rule.meta, docs: { ...rule.meta?.docs, url: `${DOCS_BASE}/${name}.md` } },
|
|
37
|
+
},
|
|
38
|
+
]));
|
|
39
|
+
}
|
|
40
|
+
exports.rules = withDocsUrl({
|
|
41
|
+
"builder-must-be-tagged": builder_must_be_tagged_js_1.rule,
|
|
42
|
+
"builder-must-implement-copy-state": builder_must_implement_copy_state_js_1.rule,
|
|
43
|
+
"constraint-metadata-required": constraint_metadata_required_js_1.rule,
|
|
44
|
+
"lifecycle-build-context-required": lifecycle_build_context_required_js_1.rule,
|
|
45
|
+
"lifecycle-build-must-forward-context": lifecycle_build_must_forward_context_js_1.rule,
|
|
46
|
+
"no-cdk-api-above-floor": no_cdk_api_above_floor_js_1.rule,
|
|
47
|
+
"no-cjs-incompatible-syntax": no_cjs_incompatible_syntax_js_1.rule,
|
|
48
|
+
"no-realm-bound-instanceof": no_realm_bound_instanceof_js_1.rule,
|
|
49
|
+
"no-typescript-private-modifier": no_typescript_private_modifier_js_1.rule,
|
|
50
|
+
"redeclared-prop-must-track-cdk-type": redeclared_prop_must_track_cdk_type_js_1.rule,
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":";;;AACA,2EAA0E;AAC1E,iGAA+F;AAC/F,uFAAuF;AACvF,+FAA8F;AAC9F,uGAAqG;AACrG,2EAAyE;AACzE,mFAAkF;AAClF,iFAAgF;AAChF,2FAA0F;AAC1F,qGAAkG;AAElG;;;;;;;;GAQG;AACH,MAAM,SAAS,GACb,oFAAoF,CAAC;AAEvF;;;;;;GAMG;AACH,SAAS,WAAW,CAA4C,OAAU;IACxE,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI;QACJ;YACE,GAAG,IAAI;YACP,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,IAAI,IAAI,KAAK,EAAE,EAAE;SACrF;KACF,CAAC,CAGE,CAAC;AACT,CAAC;AAEY,QAAA,KAAK,GAAG,WAAW,CAAC;IAC/B,wBAAwB,EAAE,gCAAmB;IAC7C,mCAAmC,EAAE,2CAA6B;IAClE,8BAA8B,EAAE,sCAA0B;IAC1D,kCAAkC,EAAE,0CAA6B;IACjE,sCAAsC,EAAE,8CAAgC;IACxE,wBAAwB,EAAE,gCAAkB;IAC5C,4BAA4B,EAAE,oCAAuB;IACrD,2BAA2B,EAAE,mCAAsB;IACnD,gCAAgC,EAAE,wCAA2B;IAC7D,qCAAqC,EAAE,6CAA8B;CACtE,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Scope } from "eslint";
|
|
2
|
+
import type { Identifier, MemberExpression } from "estree";
|
|
3
|
+
/** Strip any TS-only wrappers from an expression, returning the node inside. */
|
|
4
|
+
export declare function unwrapWrappers<T>(expr: T): T;
|
|
5
|
+
/**
|
|
6
|
+
* The leftmost identifier a member chain reads from — `CfnAlarm` in
|
|
7
|
+
* `cdk.aws_cloudwatch.CfnAlarm`, unwrapping TS wrappers as it goes.
|
|
8
|
+
*
|
|
9
|
+
* Returns `undefined` when a call or other expression breaks the chain:
|
|
10
|
+
* `f().CfnAlarm` reads a runtime value rather than the imported binding, so no
|
|
11
|
+
* rule that reasons about imports should fire on it.
|
|
12
|
+
*/
|
|
13
|
+
export declare function chainRoot(expr: MemberExpression["object"]): Identifier | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The module specifier `name` was imported from, or `undefined` when it
|
|
16
|
+
* resolves to anything else — a global, a local declaration, a parameter.
|
|
17
|
+
*
|
|
18
|
+
* Walks outward through the scope chain so a local that shadows an import name
|
|
19
|
+
* wins, matching what the runtime would do.
|
|
20
|
+
*/
|
|
21
|
+
export declare function importSourceOf(scope: Scope.Scope, name: string): string | undefined;
|
|
22
|
+
/** True for `aws-cdk-lib` and any submodule of it. */
|
|
23
|
+
export declare function isCdkSource(source: string): boolean;
|
|
24
|
+
//# sourceMappingURL=imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../../../src/rules/lib/imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AA4B3D,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAM5C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAAG,UAAU,GAAG,SAAS,CAMlF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmBnF;AAED,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unwrapWrappers = unwrapWrappers;
|
|
4
|
+
exports.chainRoot = chainRoot;
|
|
5
|
+
exports.importSourceOf = importSourceOf;
|
|
6
|
+
exports.isCdkSource = isCdkSource;
|
|
7
|
+
/**
|
|
8
|
+
* TS-only wrappers a developer might use to silence types. Peeled by
|
|
9
|
+
* {@link unwrapWrappers} and {@link chainRoot} so they cannot smuggle an
|
|
10
|
+
* expression past a rule.
|
|
11
|
+
*/
|
|
12
|
+
const TS_WRAPPERS = new Set([
|
|
13
|
+
"ChainExpression",
|
|
14
|
+
"TSAsExpression",
|
|
15
|
+
"TSNonNullExpression",
|
|
16
|
+
"TSSatisfiesExpression",
|
|
17
|
+
"TSTypeAssertion",
|
|
18
|
+
]);
|
|
19
|
+
/** Strip any TS-only wrappers from an expression, returning the node inside. */
|
|
20
|
+
function unwrapWrappers(expr) {
|
|
21
|
+
let current = expr;
|
|
22
|
+
while (TS_WRAPPERS.has(current.type)) {
|
|
23
|
+
current = current.expression;
|
|
24
|
+
}
|
|
25
|
+
return current;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The leftmost identifier a member chain reads from — `CfnAlarm` in
|
|
29
|
+
* `cdk.aws_cloudwatch.CfnAlarm`, unwrapping TS wrappers as it goes.
|
|
30
|
+
*
|
|
31
|
+
* Returns `undefined` when a call or other expression breaks the chain:
|
|
32
|
+
* `f().CfnAlarm` reads a runtime value rather than the imported binding, so no
|
|
33
|
+
* rule that reasons about imports should fire on it.
|
|
34
|
+
*/
|
|
35
|
+
function chainRoot(expr) {
|
|
36
|
+
let current = unwrapWrappers(expr);
|
|
37
|
+
while (current.type === "MemberExpression") {
|
|
38
|
+
current = unwrapWrappers(current.object);
|
|
39
|
+
}
|
|
40
|
+
return current.type === "Identifier" ? current : undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The module specifier `name` was imported from, or `undefined` when it
|
|
44
|
+
* resolves to anything else — a global, a local declaration, a parameter.
|
|
45
|
+
*
|
|
46
|
+
* Walks outward through the scope chain so a local that shadows an import name
|
|
47
|
+
* wins, matching what the runtime would do.
|
|
48
|
+
*/
|
|
49
|
+
function importSourceOf(scope, name) {
|
|
50
|
+
for (let current = scope; current !== null; current = current.upper) {
|
|
51
|
+
const variable = current.set.get(name);
|
|
52
|
+
if (variable === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
// `.at(0)` (not `[0]`) — defs can be empty at runtime for predefined
|
|
55
|
+
// globals (e.g. `console`), even though `Variable.defs: Definition[]` says
|
|
56
|
+
// otherwise; `.at` gives us the honest `Definition | undefined`.
|
|
57
|
+
const def = variable.defs.at(0);
|
|
58
|
+
if (def?.type !== "ImportBinding")
|
|
59
|
+
return undefined;
|
|
60
|
+
// `def.parent` is typed as `ImportDeclaration` but at runtime
|
|
61
|
+
// typescript-eslint also reports `ImportBinding` for `import x =
|
|
62
|
+
// require(...)`, whose parent is a `TSImportEqualsDeclaration` with no
|
|
63
|
+
// `.source`. Widen and check the discriminator before reading `source`.
|
|
64
|
+
const parent = def.parent;
|
|
65
|
+
if (parent.type !== "ImportDeclaration")
|
|
66
|
+
return undefined;
|
|
67
|
+
const source = parent.source?.value;
|
|
68
|
+
return typeof source === "string" ? source : undefined;
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/** True for `aws-cdk-lib` and any submodule of it. */
|
|
73
|
+
function isCdkSource(source) {
|
|
74
|
+
return source === "aws-cdk-lib" || source.startsWith("aws-cdk-lib/");
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.js","sourceRoot":"","sources":["../../../../src/rules/lib/imports.ts"],"names":[],"mappings":";;AA8BA,wCAMC;AAUD,8BAMC;AASD,wCAmBC;AAGD,kCAEC;AArED;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,iBAAiB;IACjB,gBAAgB;IAChB,qBAAqB;IACrB,uBAAuB;IACvB,iBAAiB;CAClB,CAAC,CAAC;AAEH,gFAAgF;AAChF,SAAgB,cAAc,CAAI,IAAO;IACvC,IAAI,OAAO,GAAG,IAA2B,CAAC;IAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,OAAO,GAAG,OAAO,CAAC,UAAsB,CAAC;IAC3C,CAAC;IACD,OAAO,OAAuB,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,SAAS,CAAC,IAAgC;IACxD,IAAI,OAAO,GAAG,cAAc,CAAC,IAAI,CAAwB,CAAC;IAC1D,OAAO,OAAO,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAC3C,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAa,CAAC;IACvD,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAE,OAAiC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxF,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,KAAkB,EAAE,IAAY;IAC7D,KAAK,IAAI,OAAO,GAAuB,KAAK,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACxF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS;QACrC,qEAAqE;QACrE,2EAA2E;QAC3E,iEAAiE;QACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,GAAG,EAAE,IAAI,KAAK,eAAe;YAAE,OAAO,SAAS,CAAC;QACpD,8DAA8D;QAC9D,iEAAiE;QACjE,uEAAuE;QACvE,wEAAwE;QACxE,MAAM,MAAM,GAAG,GAAG,CAAC,MAAwD,CAAC;QAC5E,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB;YAAE,OAAO,SAAS,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QACpC,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,sDAAsD;AACtD,SAAgB,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,KAAK,aAAa,IAAI,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Flags a `Lifecycle` class whose `build` takes no `context` parameter although
|
|
4
|
+
* the class body uses `Resolvable<…>`.
|
|
5
|
+
*
|
|
6
|
+
* A builder holding a `Resolvable<…>` accepts refs when it is configured, but
|
|
7
|
+
* resolving one needs the build context. With no `context` parameter the
|
|
8
|
+
* resolution receives `undefined` and the ref throws at synth, so the builder
|
|
9
|
+
* offers an API it cannot honour.
|
|
10
|
+
*
|
|
11
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/lifecycle-build-context-required.md | the rule documentation}.
|
|
12
|
+
*/
|
|
13
|
+
export declare const rule: Rule.RuleModule;
|
|
14
|
+
//# sourceMappingURL=lifecycle-build-context-required.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-build-context-required.d.ts","sourceRoot":"","sources":["../../../src/rules/lifecycle-build-context-required.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAiCvB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Flags a `Lifecycle` class whose `build` takes no `context` parameter although
|
|
6
|
+
* the class body uses `Resolvable<…>`.
|
|
7
|
+
*
|
|
8
|
+
* A builder holding a `Resolvable<…>` accepts refs when it is configured, but
|
|
9
|
+
* resolving one needs the build context. With no `context` parameter the
|
|
10
|
+
* resolution receives `undefined` and the ref throws at synth, so the builder
|
|
11
|
+
* offers an API it cannot honour.
|
|
12
|
+
*
|
|
13
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/lifecycle-build-context-required.md | the rule documentation}.
|
|
14
|
+
*/
|
|
15
|
+
exports.rule = {
|
|
16
|
+
meta: {
|
|
17
|
+
type: "problem",
|
|
18
|
+
docs: {
|
|
19
|
+
description: "Lifecycle.build() must accept context when the builder uses Resolvable<…>",
|
|
20
|
+
},
|
|
21
|
+
schema: [],
|
|
22
|
+
messages: {
|
|
23
|
+
missingContext: "`build()` is missing the `context` parameter, but this class uses `Resolvable<…>`. " +
|
|
24
|
+
"Refs need context to resolve — add `context?: Record<string, object>` (or a typed dependency record) and pass it to `resolve(value, context)`.",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
create(ctx) {
|
|
28
|
+
const sourceCode = ctx.sourceCode;
|
|
29
|
+
return {
|
|
30
|
+
ClassBody(node) {
|
|
31
|
+
const build = node.body.find((member) => member.type === "MethodDefinition" &&
|
|
32
|
+
member.key.type === "Identifier" &&
|
|
33
|
+
member.key.name === "build");
|
|
34
|
+
if (!build)
|
|
35
|
+
return;
|
|
36
|
+
// Lifecycle.build(scope, id, context?) — 3rd param is context.
|
|
37
|
+
if (build.value.params.length >= 3)
|
|
38
|
+
return;
|
|
39
|
+
if (/\bResolvable\s*</.test(sourceCode.getText(node))) {
|
|
40
|
+
ctx.report({ node: build, messageId: "missingContext" });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=lifecycle-build-context-required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-build-context-required.js","sourceRoot":"","sources":["../../../src/rules/lifecycle-build-context-required.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;GAUG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,2EAA2E;SACzF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,cAAc,EACZ,qFAAqF;gBACrF,gJAAgJ;SACnJ;KACF;IACD,MAAM,CAAC,GAAG;QACR,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;QAClC,OAAO;YACL,SAAS,CAAC,IAAe;gBACvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAC1B,CAAC,MAAM,EAA8B,EAAE,CACrC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;oBAChC,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAC9B,CAAC;gBACF,IAAI,CAAC,KAAK;oBAAE,OAAO;gBACnB,+DAA+D;gBAC/D,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC;oBAAE,OAAO;gBAE3C,IAAI,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;oBACtD,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Flags a two-argument `builder.build(scope, id)` call, which gives the
|
|
4
|
+
* sub-builder no context to resolve refs against.
|
|
5
|
+
*
|
|
6
|
+
* A builder that delegates must pass its context on. When it does not, the
|
|
7
|
+
* sub-builder resolves against an empty context, and any ref the caller supplied
|
|
8
|
+
* through a `configure` callback fails at synth with "component not found in
|
|
9
|
+
* context".
|
|
10
|
+
*
|
|
11
|
+
* This is the call-site counterpart to `lifecycle-build-context-required`, which
|
|
12
|
+
* checks the declaration. Accepting the parameter is not enough — the common
|
|
13
|
+
* failure is a builder that takes `context` and then drops it on the way down.
|
|
14
|
+
*
|
|
15
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/lifecycle-build-must-forward-context.md | the rule documentation}.
|
|
16
|
+
*/
|
|
17
|
+
export declare const rule: Rule.RuleModule;
|
|
18
|
+
//# sourceMappingURL=lifecycle-build-must-forward-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-build-must-forward-context.d.ts","sourceRoot":"","sources":["../../../src/rules/lifecycle-build-must-forward-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAgCvB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Flags a two-argument `builder.build(scope, id)` call, which gives the
|
|
6
|
+
* sub-builder no context to resolve refs against.
|
|
7
|
+
*
|
|
8
|
+
* A builder that delegates must pass its context on. When it does not, the
|
|
9
|
+
* sub-builder resolves against an empty context, and any ref the caller supplied
|
|
10
|
+
* through a `configure` callback fails at synth with "component not found in
|
|
11
|
+
* context".
|
|
12
|
+
*
|
|
13
|
+
* This is the call-site counterpart to `lifecycle-build-context-required`, which
|
|
14
|
+
* checks the declaration. Accepting the parameter is not enough — the common
|
|
15
|
+
* failure is a builder that takes `context` and then drops it on the way down.
|
|
16
|
+
*
|
|
17
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/lifecycle-build-must-forward-context.md | the rule documentation}.
|
|
18
|
+
*/
|
|
19
|
+
exports.rule = {
|
|
20
|
+
meta: {
|
|
21
|
+
type: "problem",
|
|
22
|
+
docs: {
|
|
23
|
+
description: "A Lifecycle build() call must forward the build context to sub-builders",
|
|
24
|
+
},
|
|
25
|
+
schema: [],
|
|
26
|
+
messages: {
|
|
27
|
+
missingContext: "`build(scope, id)` drops the build context. A sub-builder resolves refs against `{}` " +
|
|
28
|
+
"without it, so a `ref()` passed through a `configure` callback throws " +
|
|
29
|
+
'"component not found in context". Pass the context as the third argument — ' +
|
|
30
|
+
"threading it through any helper function in between. If this is a deliberate root " +
|
|
31
|
+
"build with no context to forward, disable this rule on the line and say why.",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
create(ctx) {
|
|
35
|
+
return {
|
|
36
|
+
CallExpression(node) {
|
|
37
|
+
const callee = node.callee;
|
|
38
|
+
if (callee.type !== "MemberExpression")
|
|
39
|
+
return;
|
|
40
|
+
if (callee.computed)
|
|
41
|
+
return;
|
|
42
|
+
if (callee.property.type !== "Identifier" || callee.property.name !== "build")
|
|
43
|
+
return;
|
|
44
|
+
// Exactly (scope, id) — see the "Why exactly two arguments" note above.
|
|
45
|
+
if (node.arguments.length !== 2)
|
|
46
|
+
return;
|
|
47
|
+
if (node.arguments.some((arg) => arg.type === "SpreadElement"))
|
|
48
|
+
return;
|
|
49
|
+
ctx.report({ node: node, messageId: "missingContext" });
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=lifecycle-build-must-forward-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle-build-must-forward-context.js","sourceRoot":"","sources":["../../../src/rules/lifecycle-build-must-forward-context.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;GAcG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,yEAAyE;SACvF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,cAAc,EACZ,uFAAuF;gBACvF,wEAAwE;gBACxE,6EAA6E;gBAC7E,oFAAoF;gBACpF,8EAA8E;SACjF;KACF;IACD,MAAM,CAAC,GAAG;QACR,OAAO;YACL,cAAc,CAAC,IAAoB;gBACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBAC/C,IAAI,MAAM,CAAC,QAAQ;oBAAE,OAAO;gBAC5B,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO;oBAAE,OAAO;gBAEtF,wEAAwE;gBACxE,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO;gBACxC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC;oBAAE,OAAO;gBAEvE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAuB,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAC7E,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Flags an `aws-cdk-lib` API newer than the oldest CDK version this package
|
|
4
|
+
* supports.
|
|
5
|
+
*
|
|
6
|
+
* Such a call type-checks and passes tests, because both run against whichever
|
|
7
|
+
* CDK is installed here — the newest. It then throws at runtime for anyone whose
|
|
8
|
+
* own `aws-cdk-lib` is older, while still inside the range the package declares
|
|
9
|
+
* it supports. The fix is a form of the same check that works across the whole
|
|
10
|
+
* range; the rule's message names one per banned API.
|
|
11
|
+
*
|
|
12
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-cdk-api-above-floor.md | the rule documentation}.
|
|
13
|
+
*/
|
|
14
|
+
export declare const rule: Rule.RuleModule;
|
|
15
|
+
//# sourceMappingURL=no-cdk-api-above-floor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-cdk-api-above-floor.d.ts","sourceRoot":"","sources":["../../../src/rules/no-cdk-api-above-floor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAqDnC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAiCvB,CAAC"}
|