@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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +138 -0
  3. package/dist/commonjs/configs/presets.d.ts +42 -0
  4. package/dist/commonjs/configs/presets.d.ts.map +1 -0
  5. package/dist/commonjs/configs/presets.js +58 -0
  6. package/dist/commonjs/configs/presets.js.map +1 -0
  7. package/dist/commonjs/index.d.ts +84 -0
  8. package/dist/commonjs/index.d.ts.map +1 -0
  9. package/dist/commonjs/index.js +63 -0
  10. package/dist/commonjs/index.js.map +1 -0
  11. package/dist/commonjs/package.json +3 -0
  12. package/dist/commonjs/rules/builder-must-be-tagged.d.ts +15 -0
  13. package/dist/commonjs/rules/builder-must-be-tagged.d.ts.map +1 -0
  14. package/dist/commonjs/rules/builder-must-be-tagged.js +70 -0
  15. package/dist/commonjs/rules/builder-must-be-tagged.js.map +1 -0
  16. package/dist/commonjs/rules/builder-must-implement-copy-state.d.ts +13 -0
  17. package/dist/commonjs/rules/builder-must-implement-copy-state.d.ts.map +1 -0
  18. package/dist/commonjs/rules/builder-must-implement-copy-state.js +123 -0
  19. package/dist/commonjs/rules/builder-must-implement-copy-state.js.map +1 -0
  20. package/dist/commonjs/rules/constraint-metadata-required.d.ts +16 -0
  21. package/dist/commonjs/rules/constraint-metadata-required.d.ts.map +1 -0
  22. package/dist/commonjs/rules/constraint-metadata-required.js +79 -0
  23. package/dist/commonjs/rules/constraint-metadata-required.js.map +1 -0
  24. package/dist/commonjs/rules/index.d.ts +14 -0
  25. package/dist/commonjs/rules/index.d.ts.map +1 -0
  26. package/dist/commonjs/rules/index.js +52 -0
  27. package/dist/commonjs/rules/index.js.map +1 -0
  28. package/dist/commonjs/rules/lib/imports.d.ts +24 -0
  29. package/dist/commonjs/rules/lib/imports.d.ts.map +1 -0
  30. package/dist/commonjs/rules/lib/imports.js +76 -0
  31. package/dist/commonjs/rules/lib/imports.js.map +1 -0
  32. package/dist/commonjs/rules/lifecycle-build-context-required.d.ts +14 -0
  33. package/dist/commonjs/rules/lifecycle-build-context-required.d.ts.map +1 -0
  34. package/dist/commonjs/rules/lifecycle-build-context-required.js +46 -0
  35. package/dist/commonjs/rules/lifecycle-build-context-required.js.map +1 -0
  36. package/dist/commonjs/rules/lifecycle-build-must-forward-context.d.ts +18 -0
  37. package/dist/commonjs/rules/lifecycle-build-must-forward-context.d.ts.map +1 -0
  38. package/dist/commonjs/rules/lifecycle-build-must-forward-context.js +54 -0
  39. package/dist/commonjs/rules/lifecycle-build-must-forward-context.js.map +1 -0
  40. package/dist/commonjs/rules/no-cdk-api-above-floor.d.ts +15 -0
  41. package/dist/commonjs/rules/no-cdk-api-above-floor.d.ts.map +1 -0
  42. package/dist/commonjs/rules/no-cdk-api-above-floor.js +80 -0
  43. package/dist/commonjs/rules/no-cdk-api-above-floor.js.map +1 -0
  44. package/dist/commonjs/rules/no-cjs-incompatible-syntax.d.ts +14 -0
  45. package/dist/commonjs/rules/no-cjs-incompatible-syntax.d.ts.map +1 -0
  46. package/dist/commonjs/rules/no-cjs-incompatible-syntax.js +55 -0
  47. package/dist/commonjs/rules/no-cjs-incompatible-syntax.js.map +1 -0
  48. package/dist/commonjs/rules/no-realm-bound-instanceof.d.ts +25 -0
  49. package/dist/commonjs/rules/no-realm-bound-instanceof.d.ts.map +1 -0
  50. package/dist/commonjs/rules/no-realm-bound-instanceof.js +98 -0
  51. package/dist/commonjs/rules/no-realm-bound-instanceof.js.map +1 -0
  52. package/dist/commonjs/rules/no-typescript-private-modifier.d.ts +17 -0
  53. package/dist/commonjs/rules/no-typescript-private-modifier.d.ts.map +1 -0
  54. package/dist/commonjs/rules/no-typescript-private-modifier.js +91 -0
  55. package/dist/commonjs/rules/no-typescript-private-modifier.js.map +1 -0
  56. package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.d.ts +17 -0
  57. package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.d.ts.map +1 -0
  58. package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.js +152 -0
  59. package/dist/commonjs/rules/redeclared-prop-must-track-cdk-type.js.map +1 -0
  60. package/dist/esm/configs/presets.d.ts +42 -0
  61. package/dist/esm/configs/presets.d.ts.map +1 -0
  62. package/dist/esm/configs/presets.js +55 -0
  63. package/dist/esm/configs/presets.js.map +1 -0
  64. package/dist/esm/index.d.ts +84 -0
  65. package/dist/esm/index.d.ts.map +1 -0
  66. package/dist/esm/index.js +60 -0
  67. package/dist/esm/index.js.map +1 -0
  68. package/dist/esm/package.json +3 -0
  69. package/dist/esm/rules/builder-must-be-tagged.d.ts +15 -0
  70. package/dist/esm/rules/builder-must-be-tagged.d.ts.map +1 -0
  71. package/dist/esm/rules/builder-must-be-tagged.js +67 -0
  72. package/dist/esm/rules/builder-must-be-tagged.js.map +1 -0
  73. package/dist/esm/rules/builder-must-implement-copy-state.d.ts +13 -0
  74. package/dist/esm/rules/builder-must-implement-copy-state.d.ts.map +1 -0
  75. package/dist/esm/rules/builder-must-implement-copy-state.js +120 -0
  76. package/dist/esm/rules/builder-must-implement-copy-state.js.map +1 -0
  77. package/dist/esm/rules/constraint-metadata-required.d.ts +16 -0
  78. package/dist/esm/rules/constraint-metadata-required.d.ts.map +1 -0
  79. package/dist/esm/rules/constraint-metadata-required.js +76 -0
  80. package/dist/esm/rules/constraint-metadata-required.js.map +1 -0
  81. package/dist/esm/rules/index.d.ts +14 -0
  82. package/dist/esm/rules/index.d.ts.map +1 -0
  83. package/dist/esm/rules/index.js +49 -0
  84. package/dist/esm/rules/index.js.map +1 -0
  85. package/dist/esm/rules/lib/imports.d.ts +24 -0
  86. package/dist/esm/rules/lib/imports.d.ts.map +1 -0
  87. package/dist/esm/rules/lib/imports.js +70 -0
  88. package/dist/esm/rules/lib/imports.js.map +1 -0
  89. package/dist/esm/rules/lifecycle-build-context-required.d.ts +14 -0
  90. package/dist/esm/rules/lifecycle-build-context-required.d.ts.map +1 -0
  91. package/dist/esm/rules/lifecycle-build-context-required.js +43 -0
  92. package/dist/esm/rules/lifecycle-build-context-required.js.map +1 -0
  93. package/dist/esm/rules/lifecycle-build-must-forward-context.d.ts +18 -0
  94. package/dist/esm/rules/lifecycle-build-must-forward-context.d.ts.map +1 -0
  95. package/dist/esm/rules/lifecycle-build-must-forward-context.js +51 -0
  96. package/dist/esm/rules/lifecycle-build-must-forward-context.js.map +1 -0
  97. package/dist/esm/rules/no-cdk-api-above-floor.d.ts +15 -0
  98. package/dist/esm/rules/no-cdk-api-above-floor.d.ts.map +1 -0
  99. package/dist/esm/rules/no-cdk-api-above-floor.js +77 -0
  100. package/dist/esm/rules/no-cdk-api-above-floor.js.map +1 -0
  101. package/dist/esm/rules/no-cjs-incompatible-syntax.d.ts +14 -0
  102. package/dist/esm/rules/no-cjs-incompatible-syntax.d.ts.map +1 -0
  103. package/dist/esm/rules/no-cjs-incompatible-syntax.js +52 -0
  104. package/dist/esm/rules/no-cjs-incompatible-syntax.js.map +1 -0
  105. package/dist/esm/rules/no-realm-bound-instanceof.d.ts +25 -0
  106. package/dist/esm/rules/no-realm-bound-instanceof.d.ts.map +1 -0
  107. package/dist/esm/rules/no-realm-bound-instanceof.js +95 -0
  108. package/dist/esm/rules/no-realm-bound-instanceof.js.map +1 -0
  109. package/dist/esm/rules/no-typescript-private-modifier.d.ts +17 -0
  110. package/dist/esm/rules/no-typescript-private-modifier.d.ts.map +1 -0
  111. package/dist/esm/rules/no-typescript-private-modifier.js +88 -0
  112. package/dist/esm/rules/no-typescript-private-modifier.js.map +1 -0
  113. package/dist/esm/rules/redeclared-prop-must-track-cdk-type.d.ts +17 -0
  114. package/dist/esm/rules/redeclared-prop-must-track-cdk-type.d.ts.map +1 -0
  115. package/dist/esm/rules/redeclared-prop-must-track-cdk-type.js +149 -0
  116. package/dist/esm/rules/redeclared-prop-must-track-cdk-type.js.map +1 -0
  117. package/docs/rules/builder-must-be-tagged.md +46 -0
  118. package/docs/rules/builder-must-implement-copy-state.md +50 -0
  119. package/docs/rules/constraint-metadata-required.md +44 -0
  120. package/docs/rules/lifecycle-build-context-required.md +39 -0
  121. package/docs/rules/lifecycle-build-must-forward-context.md +50 -0
  122. package/docs/rules/no-cdk-api-above-floor.md +56 -0
  123. package/docs/rules/no-cjs-incompatible-syntax.md +48 -0
  124. package/docs/rules/no-realm-bound-instanceof.md +87 -0
  125. package/docs/rules/no-typescript-private-modifier.md +72 -0
  126. package/docs/rules/redeclared-prop-must-track-cdk-type.md +60 -0
  127. package/package.json +81 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const imports_js_1 = require("./lib/imports.js");
5
+ /**
6
+ * Foundational `isCfn*` guards that predate the floor (core, since v2.0) and
7
+ * are therefore allowed — `isCfnResource` is in fact the portable replacement
8
+ * for the banned per-resource guards.
9
+ */
10
+ const ALLOWED_CFN_GUARDS = new Set(["isCfnResource", "isCfnElement"]);
11
+ /**
12
+ * The ban list. Add an entry whenever an `aws-cdk-lib` API we reach for turns
13
+ * out to postdate the supported floor — this list is expected to grow as the
14
+ * floor is pinned and lowered ahead of 1.0.0.
15
+ *
16
+ * Seeded with the per-resource `isCfn<Resource>` static type guards, which
17
+ * aws-cdk-lib first shipped on every generated L1 in 2.231.0 (verified by
18
+ * installing real versions: 2.230.0 lacks them, 2.231.0 has them). Calling
19
+ * them (e.g. `CfnAlarm.isCfnAlarm(node)`) throws `TypeError` on the older
20
+ * versions in our `^2` peer range — see issue #146.
21
+ */
22
+ const FORBIDDEN = [
23
+ {
24
+ matches: (name) => /^isCfn[A-Z]/.test(name) && !ALLOWED_CFN_GUARDS.has(name),
25
+ label: "the per-resource `Cfn<Resource>.isCfn<Resource>` L1 static type guards",
26
+ since: "2.231.0",
27
+ use: "`CfnResource.isCfnResource(x) && x.cfnResourceType === Cfn<Resource>.CFN_RESOURCE_TYPE_NAME` " +
28
+ "(what the static does internally, but valid across the whole peer range), e.g. the " +
29
+ "`isCfnAlarm` helper in @composurecdk/cloudwatch",
30
+ },
31
+ ];
32
+ /**
33
+ * Flags an `aws-cdk-lib` API newer than the oldest CDK version this package
34
+ * supports.
35
+ *
36
+ * Such a call type-checks and passes tests, because both run against whichever
37
+ * CDK is installed here — the newest. It then throws at runtime for anyone whose
38
+ * own `aws-cdk-lib` is older, while still inside the range the package declares
39
+ * it supports. The fix is a form of the same check that works across the whole
40
+ * range; the rule's message names one per banned API.
41
+ *
42
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-cdk-api-above-floor.md | the rule documentation}.
43
+ */
44
+ exports.rule = {
45
+ meta: {
46
+ type: "problem",
47
+ docs: {
48
+ description: "Ban aws-cdk-lib APIs newer than the supported peer-dependency floor",
49
+ },
50
+ schema: [],
51
+ messages: {
52
+ aboveFloor: "{{label}} were added in aws-cdk-lib {{since}}, above the supported floor — they throw on " +
53
+ "older versions in the peer range. Use {{use}}.",
54
+ },
55
+ },
56
+ create(ctx) {
57
+ return {
58
+ MemberExpression(node) {
59
+ if (node.property.type !== "Identifier")
60
+ return;
61
+ const property = node.property;
62
+ const root = (0, imports_js_1.chainRoot)(node.object);
63
+ if (root === undefined)
64
+ return;
65
+ const source = (0, imports_js_1.importSourceOf)(ctx.sourceCode.getScope(node), root.name);
66
+ if (source === undefined || !(0, imports_js_1.isCdkSource)(source))
67
+ return;
68
+ const forbidden = FORBIDDEN.find((entry) => entry.matches(property.name));
69
+ if (forbidden === undefined)
70
+ return;
71
+ ctx.report({
72
+ node: property,
73
+ messageId: "aboveFloor",
74
+ data: { label: forbidden.label, since: forbidden.since, use: forbidden.use },
75
+ });
76
+ },
77
+ };
78
+ },
79
+ };
80
+ //# sourceMappingURL=no-cdk-api-above-floor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-cdk-api-above-floor.js","sourceRoot":"","sources":["../../../src/rules/no-cdk-api-above-floor.ts"],"names":[],"mappings":";;;AAEA,iDAA0E;AAqB1E;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,MAAM,SAAS,GAAsB;IACnC;QACE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;QAC5E,KAAK,EAAE,wEAAwE;QAC/E,KAAK,EAAE,SAAS;QAChB,GAAG,EACD,+FAA+F;YAC/F,qFAAqF;YACrF,iDAAiD;KACpD;CACF,CAAC;AAEF;;;;;;;;;;;GAWG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,qEAAqE;SACnF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,UAAU,EACR,2FAA2F;gBAC3F,gDAAgD;SACnD;KACF;IACD,MAAM,CAAC,GAAG;QACR,OAAO;YACL,gBAAgB,CAAC,IAAsB;gBACrC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAAE,OAAO;gBAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC/B,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACpC,IAAI,IAAI,KAAK,SAAS;oBAAE,OAAO;gBAC/B,MAAM,MAAM,GAAG,IAAA,2BAAc,EAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxE,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,IAAA,wBAAW,EAAC,MAAM,CAAC;oBAAE,OAAO;gBAEzD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC1E,IAAI,SAAS,KAAK,SAAS;oBAAE,OAAO;gBACpC,GAAG,CAAC,MAAM,CAAC;oBACT,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,YAAY;oBACvB,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE;iBAC7E,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Rule } from "eslint";
2
+ /**
3
+ * Flags syntax with no CommonJS equivalent: `import.meta`, top-level `await` and
4
+ * top-level `for await…of`.
5
+ *
6
+ * These packages are published as both ECMAScript and CommonJS modules from one
7
+ * source. All three constructs are valid ESM that the CommonJS compile cannot
8
+ * emit, so each one breaks half the build. Reporting them as you type beats
9
+ * discovering it when the second dialect compiles.
10
+ *
11
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-cjs-incompatible-syntax.md | the rule documentation}.
12
+ */
13
+ export declare const rule: Rule.RuleModule;
14
+ //# sourceMappingURL=no-cjs-incompatible-syntax.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-cjs-incompatible-syntax.d.ts","sourceRoot":"","sources":["../../../src/rules/no-cjs-incompatible-syntax.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AASnC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAuCvB,CAAC"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const FUNCTION_TYPES = new Set([
5
+ "FunctionDeclaration",
6
+ "FunctionExpression",
7
+ "ArrowFunctionExpression",
8
+ ]);
9
+ /**
10
+ * Flags syntax with no CommonJS equivalent: `import.meta`, top-level `await` and
11
+ * top-level `for await…of`.
12
+ *
13
+ * These packages are published as both ECMAScript and CommonJS modules from one
14
+ * source. All three constructs are valid ESM that the CommonJS compile cannot
15
+ * emit, so each one breaks half the build. Reporting them as you type beats
16
+ * discovering it when the second dialect compiles.
17
+ *
18
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-cjs-incompatible-syntax.md | the rule documentation}.
19
+ */
20
+ exports.rule = {
21
+ meta: {
22
+ type: "problem",
23
+ docs: {
24
+ description: "Ban ESM-only syntax (import.meta, top-level await) that cannot emit to CommonJS",
25
+ },
26
+ schema: [],
27
+ messages: {
28
+ importMeta: "`import.meta` has no CommonJS equivalent, so it breaks the CommonJS half of a " +
29
+ "dual-published build. Take the value from a parameter or a caller instead.",
30
+ topLevelAwait: "Top-level `await` has no CommonJS equivalent, so it breaks the CommonJS half of a " +
31
+ "dual-published build. Move the `await` inside an async function.",
32
+ },
33
+ },
34
+ create(ctx) {
35
+ const isTopLevel = (node) => !ctx.sourceCode.getAncestors(node).some((ancestor) => FUNCTION_TYPES.has(ancestor.type));
36
+ return {
37
+ MetaProperty(node) {
38
+ if (node.meta.name === "import" && node.property.name === "meta") {
39
+ ctx.report({ node, messageId: "importMeta" });
40
+ }
41
+ },
42
+ AwaitExpression(node) {
43
+ if (isTopLevel(node)) {
44
+ ctx.report({ node, messageId: "topLevelAwait" });
45
+ }
46
+ },
47
+ "ForOfStatement[await=true]"(node) {
48
+ if (isTopLevel(node)) {
49
+ ctx.report({ node, messageId: "topLevelAwait" });
50
+ }
51
+ },
52
+ };
53
+ },
54
+ };
55
+ //# sourceMappingURL=no-cjs-incompatible-syntax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-cjs-incompatible-syntax.js","sourceRoot":"","sources":["../../../src/rules/no-cjs-incompatible-syntax.ts"],"names":[],"mappings":";;;AAGA,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,qBAAqB;IACrB,oBAAoB;IACpB,yBAAyB;CAC1B,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,iFAAiF;SACpF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,UAAU,EACR,gFAAgF;gBAChF,4EAA4E;YAC9E,aAAa,EACX,oFAAoF;gBACpF,kEAAkE;SACrE;KACF;IACD,MAAM,CAAC,GAAG;QACR,MAAM,UAAU,GAAG,CAAC,IAAU,EAAW,EAAE,CACzC,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAE3F,OAAO;YACL,YAAY,CAAC,IAAkB;gBAC7B,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACjE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;YACD,eAAe,CAAC,IAAqB;gBACnC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrB,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YACD,4BAA4B,CAAC,IAAoB;gBAC/C,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrB,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { Rule } from "eslint";
2
+ /**
3
+ * Bans `instanceof` against a class reached through an `import`.
4
+ *
5
+ * These packages ship as both ECMAScript and CommonJS modules, and both copies
6
+ * can load in the same process — a consumer importing one while a dependency
7
+ * requires the other. Each copy evaluates its own class objects, so an instance
8
+ * created by one fails `instanceof` against the other's class: the check returns
9
+ * `false` for a value that is plainly of that type.
10
+ *
11
+ * It fails silently, which is what makes it dangerous — a deduplication quietly
12
+ * skipped, a guard quietly bypassed, and no error to trace. Use a `Symbol.for(…)`
13
+ * brand instead, which is shared across copies.
14
+ *
15
+ * A relative import is no safer by default: it resolves separately in each copy.
16
+ * A package nothing can install twice may say so with
17
+ * `assumeNeverInstalledAsADependency`, which treats its own modules as
18
+ * same-realm while still flagging dependencies. An application is the archetype;
19
+ * being private is not enough, since a private package can still be a
20
+ * dependency.
21
+ *
22
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-realm-bound-instanceof.md | the rule documentation}.
23
+ */
24
+ export declare const rule: Rule.RuleModule;
25
+ //# sourceMappingURL=no-realm-bound-instanceof.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-realm-bound-instanceof.d.ts","sourceRoot":"","sources":["../../../src/rules/no-realm-bound-instanceof.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAInC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UA8EvB,CAAC"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const imports_js_1 = require("./lib/imports.js");
5
+ /**
6
+ * Bans `instanceof` against a class reached through an `import`.
7
+ *
8
+ * These packages ship as both ECMAScript and CommonJS modules, and both copies
9
+ * can load in the same process — a consumer importing one while a dependency
10
+ * requires the other. Each copy evaluates its own class objects, so an instance
11
+ * created by one fails `instanceof` against the other's class: the check returns
12
+ * `false` for a value that is plainly of that type.
13
+ *
14
+ * It fails silently, which is what makes it dangerous — a deduplication quietly
15
+ * skipped, a guard quietly bypassed, and no error to trace. Use a `Symbol.for(…)`
16
+ * brand instead, which is shared across copies.
17
+ *
18
+ * A relative import is no safer by default: it resolves separately in each copy.
19
+ * A package nothing can install twice may say so with
20
+ * `assumeNeverInstalledAsADependency`, which treats its own modules as
21
+ * same-realm while still flagging dependencies. An application is the archetype;
22
+ * being private is not enough, since a private package can still be a
23
+ * dependency.
24
+ *
25
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-realm-bound-instanceof.md | the rule documentation}.
26
+ */
27
+ exports.rule = {
28
+ meta: {
29
+ type: "problem",
30
+ docs: {
31
+ description: "Ban realm-bound `instanceof` against imported classes",
32
+ },
33
+ schema: [
34
+ {
35
+ type: "object",
36
+ properties: {
37
+ assumeNeverInstalledAsADependency: {
38
+ type: "boolean",
39
+ description: "Exempt this package's own relative imports, on the basis that nothing can " +
40
+ "install it twice. An application's claim to make; a library must not, since a " +
41
+ "consumer can install two versions of it side by side.",
42
+ },
43
+ },
44
+ additionalProperties: false,
45
+ },
46
+ ],
47
+ messages: {
48
+ cdkClass: "`instanceof {{name}}` is realm-bound: it returns false for a value created by another " +
49
+ "copy of `aws-cdk-lib`. Identify the construct by its L1 instead — " +
50
+ "`CfnResource.isCfnResource(x) && x.cfnResourceType === Cfn{{name}}.CFN_RESOURCE_TYPE_NAME`.",
51
+ ownClass: "`instanceof {{name}}` is realm-bound: `{{source}}` resolves separately in each copy of " +
52
+ "this package, so the check returns false for a value that is plainly of that type. " +
53
+ "Brand the class with `Symbol.for(...)` and test for that brand instead.",
54
+ dependencyClass: "`instanceof {{name}}` is realm-bound: `{{source}}` can load twice in one process, so the " +
55
+ "check returns false for a value that is plainly of that type. Prefer a type guard the " +
56
+ "package provides, or test a distinguishing property rather than identity. If the class " +
57
+ "is one you own, brand it with `Symbol.for(...)`.",
58
+ },
59
+ },
60
+ create(ctx) {
61
+ const { assumeNeverInstalledAsADependency = false } = (ctx.options[0] ?? {});
62
+ return {
63
+ BinaryExpression(node) {
64
+ if (node.operator !== "instanceof")
65
+ return;
66
+ const root = (0, imports_js_1.chainRoot)(node.right);
67
+ if (root === undefined)
68
+ return;
69
+ const source = (0, imports_js_1.importSourceOf)(ctx.sourceCode.getScope(node), root.name);
70
+ if (source === undefined)
71
+ return;
72
+ // A relative specifier resolves inside this package, so it duplicates
73
+ // only if the package itself does. Deliberately not `#` subpaths: the
74
+ // `imports` field can map one to an external package.
75
+ if (assumeNeverInstalledAsADependency && source.startsWith("."))
76
+ return;
77
+ // Name the class, not the namespace it was reached through:
78
+ // `cdk.aws_s3.Bucket` is "Bucket", and the cdk message interpolates
79
+ // that into `Cfn<name>.CFN_RESOURCE_TYPE_NAME`.
80
+ const target = (0, imports_js_1.unwrapWrappers)(node.right);
81
+ const name = target.type === "MemberExpression" && target.property.type === "Identifier"
82
+ ? target.property.name
83
+ : root.name;
84
+ // Report on the class reference, not the whole expression: the fix
85
+ // replaces the right-hand side, and a narrow squiggle points at it.
86
+ // The specifier says whether the reader can brand the class: a relative
87
+ // import is their own module, anything else is someone else's package.
88
+ const messageId = (0, imports_js_1.isCdkSource)(source)
89
+ ? "cdkClass"
90
+ : source.startsWith(".")
91
+ ? "ownClass"
92
+ : "dependencyClass";
93
+ ctx.report({ node: node.right, messageId, data: { name, source } });
94
+ },
95
+ };
96
+ },
97
+ };
98
+ //# sourceMappingURL=no-realm-bound-instanceof.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-realm-bound-instanceof.js","sourceRoot":"","sources":["../../../src/rules/no-realm-bound-instanceof.ts"],"names":[],"mappings":";;;AAEA,iDAA0F;AAE1F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,uDAAuD;SACrE;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,iCAAiC,EAAE;wBACjC,IAAI,EAAE,SAAS;wBACf,WAAW,EACT,4EAA4E;4BAC5E,gFAAgF;4BAChF,uDAAuD;qBAC1D;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,QAAQ,EAAE;YACR,QAAQ,EACN,wFAAwF;gBACxF,oEAAoE;gBACpE,6FAA6F;YAC/F,QAAQ,EACN,yFAAyF;gBACzF,qFAAqF;gBACrF,yEAAyE;YAC3E,eAAe,EACb,2FAA2F;gBAC3F,wFAAwF;gBACxF,yFAAyF;gBACzF,kDAAkD;SACrD;KACF;IACD,MAAM,CAAC,GAAG;QACR,MAAM,EAAE,iCAAiC,GAAG,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAE1E,CAAC;QAEF,OAAO;YACL,gBAAgB,CAAC,IAAsB;gBACrC,IAAI,IAAI,CAAC,QAAQ,KAAK,YAAY;oBAAE,OAAO;gBAC3C,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnC,IAAI,IAAI,KAAK,SAAS;oBAAE,OAAO;gBAE/B,MAAM,MAAM,GAAG,IAAA,2BAAc,EAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxE,IAAI,MAAM,KAAK,SAAS;oBAAE,OAAO;gBACjC,sEAAsE;gBACtE,sEAAsE;gBACtE,sDAAsD;gBACtD,IAAI,iCAAiC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,OAAO;gBAExE,4DAA4D;gBAC5D,oEAAoE;gBACpE,gDAAgD;gBAChD,MAAM,MAAM,GAAG,IAAA,2BAAc,EAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1C,MAAM,IAAI,GACR,MAAM,CAAC,IAAI,KAAK,kBAAkB,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACzE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI;oBACtB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBAEhB,mEAAmE;gBACnE,oEAAoE;gBACpE,wEAAwE;gBACxE,uEAAuE;gBACvE,MAAM,SAAS,GAAG,IAAA,wBAAW,EAAC,MAAM,CAAC;oBACnC,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;wBACtB,CAAC,CAAC,UAAU;wBACZ,CAAC,CAAC,iBAAiB,CAAC;gBAExB,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;YACtE,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Rule } from "eslint";
2
+ /**
3
+ * Bans the TypeScript `private` modifier in favour of ECMAScript private fields.
4
+ *
5
+ * The two are not interchangeable once a class is generic over its own members.
6
+ * A TypeScript `private` member is still part of the type, so it appears in
7
+ * `keyof T`, survives into a mapped type, and reaches the emitted `.d.ts` — where
8
+ * a consumer's compiler cannot name it and reports TS4094. A `#field` is not
9
+ * part of the type at all, so it never gets that far.
10
+ *
11
+ * A private constructor stays allowed: `#constructor` is not valid syntax, so
12
+ * there is nothing to prefer over it.
13
+ *
14
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-typescript-private-modifier.md | the rule documentation}.
15
+ */
16
+ export declare const rule: Rule.RuleModule;
17
+ //# sourceMappingURL=no-typescript-private-modifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-typescript-private-modifier.d.ts","sourceRoot":"","sources":["../../../src/rules/no-typescript-private-modifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAkCnC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAwDvB,CAAC"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ /**
5
+ * The member's own name, for the message. A computed key has no name to give —
6
+ * `#[expr]` is not a thing — so the message falls back to a placeholder rather
7
+ * than naming whatever expression produced the key.
8
+ */
9
+ function memberName(key, computed) {
10
+ if (computed)
11
+ return "field";
12
+ if (key.type === "Identifier")
13
+ return key.name;
14
+ if (key.type === "Literal" && typeof key.value === "string")
15
+ return key.value;
16
+ return "field";
17
+ }
18
+ /** The bound name of a parameter, seeing through a default value. */
19
+ function parameterName(parameter) {
20
+ const bound = parameter.type === "AssignmentPattern" ? parameter.left : parameter;
21
+ return bound.type === "Identifier" ? bound.name : "field";
22
+ }
23
+ /**
24
+ * Bans the TypeScript `private` modifier in favour of ECMAScript private fields.
25
+ *
26
+ * The two are not interchangeable once a class is generic over its own members.
27
+ * A TypeScript `private` member is still part of the type, so it appears in
28
+ * `keyof T`, survives into a mapped type, and reaches the emitted `.d.ts` — where
29
+ * a consumer's compiler cannot name it and reports TS4094. A `#field` is not
30
+ * part of the type at all, so it never gets that far.
31
+ *
32
+ * A private constructor stays allowed: `#constructor` is not valid syntax, so
33
+ * there is nothing to prefer over it.
34
+ *
35
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/no-typescript-private-modifier.md | the rule documentation}.
36
+ */
37
+ exports.rule = {
38
+ meta: {
39
+ type: "problem",
40
+ docs: {
41
+ description: "Ban the TypeScript `private` modifier in favour of ECMAScript `#` fields",
42
+ },
43
+ schema: [],
44
+ messages: {
45
+ property: "Use an ECMAScript private field (`#{{name}}`) instead of the TypeScript `private` " +
46
+ "modifier. A `private` member still appears in `keyof T` and is carried through mapped " +
47
+ "types into the emitted .d.ts, where it produces TS4094 for consumers.",
48
+ method: "Use an ECMAScript private method (`#{{name}}()`) instead of the TypeScript `private` " +
49
+ "modifier. A private constructor is the only permitted use, since `#constructor` is not " +
50
+ "valid syntax.",
51
+ parameterProperty: "A parameter property cannot be ECMAScript private. Declare the field as " +
52
+ "`readonly #{{name}}` and assign it in the constructor body.",
53
+ },
54
+ },
55
+ create(ctx) {
56
+ // Each handler reports on the member's own name rather than the whole
57
+ // declaration: the fix replaces the modifier and renames the key, so a
58
+ // narrow squiggle points at both.
59
+ return {
60
+ "PropertyDefinition[accessibility='private']"(node) {
61
+ ctx.report({
62
+ node: node.key,
63
+ messageId: "property",
64
+ data: { name: memberName(node.key, node.computed) },
65
+ });
66
+ },
67
+ "MethodDefinition[accessibility='private'][kind!='constructor']"(node) {
68
+ ctx.report({
69
+ node: node.key,
70
+ messageId: "method",
71
+ data: { name: memberName(node.key, node.computed) },
72
+ });
73
+ },
74
+ // `accessor x` is a distinct node from a plain field, and its `private`
75
+ // reaches `keyof T` the same way.
76
+ "AccessorProperty[accessibility='private']"(node) {
77
+ const { key, computed } = node;
78
+ ctx.report({ node: key, messageId: "property", data: { name: memberName(key, computed) } });
79
+ },
80
+ "TSParameterProperty[accessibility='private']"(node) {
81
+ const { parameter } = node;
82
+ ctx.report({
83
+ node: parameter,
84
+ messageId: "parameterProperty",
85
+ data: { name: parameterName(parameter) },
86
+ });
87
+ },
88
+ };
89
+ },
90
+ };
91
+ //# sourceMappingURL=no-typescript-private-modifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-typescript-private-modifier.js","sourceRoot":"","sources":["../../../src/rules/no-typescript-private-modifier.ts"],"names":[],"mappings":";;;AAgBA;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAS,EAAE,QAAiB;IAC9C,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC;IAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAC/C,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC;IAC9E,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,qEAAqE;AACrE,SAAS,aAAa,CAAC,SAAe;IACpC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,OAAO,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;;;GAaG;AACU,QAAA,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,0EAA0E;SACxF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,QAAQ,EACN,oFAAoF;gBACpF,wFAAwF;gBACxF,uEAAuE;YACzE,MAAM,EACJ,uFAAuF;gBACvF,yFAAyF;gBACzF,eAAe;YACjB,iBAAiB,EACf,0EAA0E;gBAC1E,6DAA6D;SAChE;KACF;IACD,MAAM,CAAC,GAAG;QACR,sEAAsE;QACtE,uEAAuE;QACvE,kCAAkC;QAClC,OAAO;YACL,6CAA6C,CAAC,IAAwB;gBACpE,GAAG,CAAC,MAAM,CAAC;oBACT,IAAI,EAAE,IAAI,CAAC,GAAG;oBACd,SAAS,EAAE,UAAU;oBACrB,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;iBACpD,CAAC,CAAC;YACL,CAAC;YACD,gEAAgE,CAAC,IAAsB;gBACrF,GAAG,CAAC,MAAM,CAAC;oBACT,IAAI,EAAE,IAAI,CAAC,GAAG;oBACd,SAAS,EAAE,QAAQ;oBACnB,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;iBACpD,CAAC,CAAC;YACL,CAAC;YACD,wEAAwE;YACxE,kCAAkC;YAClC,2CAA2C,CAAC,IAAU;gBACpD,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAuC,CAAC;gBAClE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9F,CAAC;YACD,8CAA8C,CAAC,IAAU;gBACvD,MAAM,EAAE,SAAS,EAAE,GAAG,IAAwC,CAAC;gBAC/D,GAAG,CAAC,MAAM,CAAC;oBACT,IAAI,EAAE,SAAS;oBACf,SAAS,EAAE,mBAAmB;oBAC9B,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE;iBACzC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Rule } from "eslint";
2
+ /**
3
+ * Flags a re-declared CDK prop that pins a named CDK interface inside
4
+ * `Resolvable<…>` rather than reading the type from CDK's own prop.
5
+ *
6
+ * A builder's props type is CDK's props type with a few keys lifted out and
7
+ * re-declared. Everything left inside the `Omit` keeps tracking whichever
8
+ * `aws-cdk-lib` the consumer installed; a key re-spelled with a named interface
9
+ * stops tracking it, freezing at whatever that interface meant when it was
10
+ * written. When CDK later widens that prop, the builder goes on rejecting values
11
+ * the construct it wraps now accepts — and it surfaces in the consumer's own
12
+ * compile, not in this package's.
13
+ *
14
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/redeclared-prop-must-track-cdk-type.md | the rule documentation}.
15
+ */
16
+ export declare const rule: Rule.RuleModule;
17
+ //# sourceMappingURL=redeclared-prop-must-track-cdk-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redeclared-prop-must-track-cdk-type.d.ts","sourceRoot":"","sources":["../../../src/rules/redeclared-prop-must-track-cdk-type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAqFnC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAiEvB,CAAC"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = void 0;
4
+ const imports_js_1 = require("./lib/imports.js");
5
+ /** True for `@aws-cdk/aws-*-alpha` and friends, alongside `aws-cdk-lib`. */
6
+ function isCdkModule(source) {
7
+ return (0, imports_js_1.isCdkSource)(source) || source.startsWith("@aws-cdk/");
8
+ }
9
+ /** The first type argument of a type reference or interface heritage, either spelling. */
10
+ function typeArgAt(node, index) {
11
+ const args = (node.typeArguments ?? node.typeParameters);
12
+ const params = args?.params ?? [];
13
+ return params.at(index);
14
+ }
15
+ /** The leftmost identifier of `Foo` or `ns.Foo`, or `undefined` for anything else. */
16
+ function rootName(typeName) {
17
+ let current = typeName;
18
+ while (current.type === "TSQualifiedName")
19
+ current = current.left;
20
+ return current.type === "Identifier" ? current.name : undefined;
21
+ }
22
+ /** The string keys named by `Omit`'s second argument, ignoring non-literal ones. */
23
+ function literalKeys(node) {
24
+ if (node === undefined)
25
+ return [];
26
+ if (node.type === "TSUnionType") {
27
+ return node.types.flatMap((t) => literalKeys(t));
28
+ }
29
+ if (node.type !== "TSLiteralType")
30
+ return [];
31
+ const literal = node.literal;
32
+ return typeof literal.value === "string" ? [literal.value] : [];
33
+ }
34
+ /** The keys an interface's `extends` clause omits from a base CDK props type. */
35
+ function omittedKeys(heritage) {
36
+ const keys = new Set();
37
+ for (const entry of heritage) {
38
+ const expression = entry.expression;
39
+ if (expression?.type !== "Identifier" || expression.name !== "Omit")
40
+ continue;
41
+ for (const key of literalKeys(typeArgAt(entry, 1)))
42
+ keys.add(key);
43
+ }
44
+ return keys;
45
+ }
46
+ /** Every `Resolvable<…>` reference nested anywhere inside a type annotation. */
47
+ function resolvableRefs(node, found = []) {
48
+ if (node === null || typeof node !== "object" || !("type" in node))
49
+ return found;
50
+ const typed = node;
51
+ if (typed.type === "TSTypeReference" && rootName(typed.typeName) === "Resolvable") {
52
+ found.push(typed);
53
+ }
54
+ for (const [key, value] of Object.entries(typed)) {
55
+ // `parent` points back up the tree — following it never terminates.
56
+ if (key === "parent")
57
+ continue;
58
+ if (Array.isArray(value))
59
+ for (const item of value)
60
+ resolvableRefs(item, found);
61
+ else
62
+ resolvableRefs(value, found);
63
+ }
64
+ return found;
65
+ }
66
+ /** The property name of a `key: T` signature, or `undefined` for a computed one. */
67
+ function propertyName(member) {
68
+ if (member.type !== "TSPropertySignature" || member.computed === true)
69
+ return undefined;
70
+ const key = member.key;
71
+ if (key.type === "Identifier")
72
+ return key.name;
73
+ if (key.type === "Literal" && typeof key.value === "string")
74
+ return key.value;
75
+ return undefined;
76
+ }
77
+ /**
78
+ * Flags a re-declared CDK prop that pins a named CDK interface inside
79
+ * `Resolvable<…>` rather than reading the type from CDK's own prop.
80
+ *
81
+ * A builder's props type is CDK's props type with a few keys lifted out and
82
+ * re-declared. Everything left inside the `Omit` keeps tracking whichever
83
+ * `aws-cdk-lib` the consumer installed; a key re-spelled with a named interface
84
+ * stops tracking it, freezing at whatever that interface meant when it was
85
+ * written. When CDK later widens that prop, the builder goes on rejecting values
86
+ * the construct it wraps now accepts — and it surfaces in the consumer's own
87
+ * compile, not in this package's.
88
+ *
89
+ * See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/redeclared-prop-must-track-cdk-type.md | the rule documentation}.
90
+ */
91
+ exports.rule = {
92
+ meta: {
93
+ type: "problem",
94
+ docs: {
95
+ description: "A re-declared CDK prop must read its type from CDK's own prop, not pin an interface",
96
+ },
97
+ schema: [],
98
+ messages: {
99
+ pinnedType: "`{{prop}}` re-declares a prop omitted from `{{base}}`, but pins `{{pinned}}` — the " +
100
+ "builder stops accepting what CDK accepts as soon as CDK widens the prop. Read the type " +
101
+ 'from CDK\'s own prop instead: `Resolvable<NonNullable<{{base}}["{{prop}}"]>>`. ' +
102
+ "Keep the indexed access inline — extracting it to a named alias puts an unnameable " +
103
+ "type into the emitted declaration.",
104
+ },
105
+ },
106
+ create(ctx) {
107
+ const cdkTypeNames = new Set();
108
+ const listener = {
109
+ ImportDeclaration(node) {
110
+ if (typeof node.source.value !== "string" || !isCdkModule(node.source.value))
111
+ return;
112
+ for (const spec of node.specifiers) {
113
+ cdkTypeNames.add(spec.local.name);
114
+ }
115
+ },
116
+ };
117
+ listener.TSInterfaceDeclaration = (node) => {
118
+ const decl = node;
119
+ const heritage = decl.extends ?? [];
120
+ const omitted = omittedKeys(heritage);
121
+ if (omitted.size === 0)
122
+ return;
123
+ // Name the base the indexed access should read from — the first `Omit`'s
124
+ // own base, which is the CDK props type in every builder that has one.
125
+ const omit = heritage.find((entry) => entry.expression?.name === "Omit");
126
+ const omitBase = omit === undefined ? undefined : typeArgAt(omit, 0);
127
+ const base = (omitBase === undefined ? undefined : rootName(omitBase.typeName)) ??
128
+ "CdkProps";
129
+ const body = decl.body?.body ?? [];
130
+ for (const member of body) {
131
+ const prop = propertyName(member);
132
+ if (prop === undefined || !omitted.has(prop))
133
+ continue;
134
+ for (const resolvable of resolvableRefs(member.typeAnnotation)) {
135
+ const inner = typeArgAt(resolvable, 0);
136
+ if (inner?.type !== "TSTypeReference")
137
+ continue;
138
+ const pinned = rootName(inner.typeName);
139
+ if (pinned === undefined || !cdkTypeNames.has(pinned))
140
+ continue;
141
+ ctx.report({
142
+ node: inner,
143
+ messageId: "pinnedType",
144
+ data: { prop, base, pinned },
145
+ });
146
+ }
147
+ }
148
+ };
149
+ return listener;
150
+ },
151
+ };
152
+ //# sourceMappingURL=redeclared-prop-must-track-cdk-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redeclared-prop-must-track-cdk-type.js","sourceRoot":"","sources":["../../../src/rules/redeclared-prop-must-track-cdk-type.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { Linter } from "eslint";
2
+ /**
3
+ * The rule sets behind each preset, grouped by **what must be true of the
4
+ * consumer** for the rule to be correct — not by subject matter. Every rule
5
+ * belongs to exactly one, which a test enforces.
6
+ *
7
+ * The reasoning behind the tiers, and what moving a rule between them costs,
8
+ * is in ADR-0019.
9
+ */
10
+ /**
11
+ * True for anyone writing a `Lifecycle` or a builder, in any shape of project —
12
+ * an application as much as a library.
13
+ */
14
+ export declare const recommendedRules: Linter.RulesRecord;
15
+ /**
16
+ * Additionally true for a package other people compile against.
17
+ *
18
+ * Each hazard here exists only once you emit a `.d.ts` someone else consumes:
19
+ * TS4094 and TS2883 need an exported mapped type, and a narrowed prop type only
20
+ * hurts when it is your published API. An application emits none of that.
21
+ *
22
+ * `lifecycle-build-must-forward-context` sits here for a different reason — a
23
+ * root-level build has no context to forward and is correct, and in an
24
+ * application nearly every build is a root build. That is a property of where
25
+ * the call sits in the composition graph, so no amount of narrowing the rule
26
+ * fixes it.
27
+ */
28
+ export declare const libraryAuthorRules: Linter.RulesRecord;
29
+ /**
30
+ * Additionally true for a package shipping both an ESM and a CommonJS build.
31
+ * Out of `recommended` because banning `import.meta` is a false positive for an
32
+ * ESM-only library, where it is legal and idiomatic.
33
+ */
34
+ export declare const dualPublishingRules: Linter.RulesRecord;
35
+ /**
36
+ * composureCDK's own house rules. Each encodes a convention or a hardcoded
37
+ * value — this repo's CDK floor, its tagging wrapper, its constraint catalogue
38
+ * — that is wrong elsewhere. Published so the preset is reproducible, not as a
39
+ * recommendation.
40
+ */
41
+ export declare const internalRules: Linter.RulesRecord;
42
+ //# sourceMappingURL=presets.d.ts.map