@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 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/configs/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC;;;;;;;GAOG;AAEH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,WAIrC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,WAIvC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAExC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,WAIlC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rule sets behind each preset, grouped by **what must be true of the
|
|
3
|
+
* consumer** for the rule to be correct — not by subject matter. Every rule
|
|
4
|
+
* belongs to exactly one, which a test enforces.
|
|
5
|
+
*
|
|
6
|
+
* The reasoning behind the tiers, and what moving a rule between them costs,
|
|
7
|
+
* is in ADR-0019.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* True for anyone writing a `Lifecycle` or a builder, in any shape of project —
|
|
11
|
+
* an application as much as a library.
|
|
12
|
+
*/
|
|
13
|
+
export const recommendedRules = {
|
|
14
|
+
"composurecdk/builder-must-implement-copy-state": "error",
|
|
15
|
+
"composurecdk/lifecycle-build-context-required": "error",
|
|
16
|
+
"composurecdk/no-realm-bound-instanceof": "error",
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Additionally true for a package other people compile against.
|
|
20
|
+
*
|
|
21
|
+
* Each hazard here exists only once you emit a `.d.ts` someone else consumes:
|
|
22
|
+
* TS4094 and TS2883 need an exported mapped type, and a narrowed prop type only
|
|
23
|
+
* hurts when it is your published API. An application emits none of that.
|
|
24
|
+
*
|
|
25
|
+
* `lifecycle-build-must-forward-context` sits here for a different reason — a
|
|
26
|
+
* root-level build has no context to forward and is correct, and in an
|
|
27
|
+
* application nearly every build is a root build. That is a property of where
|
|
28
|
+
* the call sits in the composition graph, so no amount of narrowing the rule
|
|
29
|
+
* fixes it.
|
|
30
|
+
*/
|
|
31
|
+
export const libraryAuthorRules = {
|
|
32
|
+
"composurecdk/lifecycle-build-must-forward-context": "error",
|
|
33
|
+
"composurecdk/no-typescript-private-modifier": "error",
|
|
34
|
+
"composurecdk/redeclared-prop-must-track-cdk-type": "error",
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Additionally true for a package shipping both an ESM and a CommonJS build.
|
|
38
|
+
* Out of `recommended` because banning `import.meta` is a false positive for an
|
|
39
|
+
* ESM-only library, where it is legal and idiomatic.
|
|
40
|
+
*/
|
|
41
|
+
export const dualPublishingRules = {
|
|
42
|
+
"composurecdk/no-cjs-incompatible-syntax": "error",
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* composureCDK's own house rules. Each encodes a convention or a hardcoded
|
|
46
|
+
* value — this repo's CDK floor, its tagging wrapper, its constraint catalogue
|
|
47
|
+
* — that is wrong elsewhere. Published so the preset is reproducible, not as a
|
|
48
|
+
* recommendation.
|
|
49
|
+
*/
|
|
50
|
+
export const internalRules = {
|
|
51
|
+
"composurecdk/builder-must-be-tagged": "error",
|
|
52
|
+
"composurecdk/constraint-metadata-required": "error",
|
|
53
|
+
"composurecdk/no-cdk-api-above-floor": "error",
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../../../src/configs/presets.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD,gDAAgD,EAAE,OAAO;IACzD,+CAA+C,EAAE,OAAO;IACxD,wCAAwC,EAAE,OAAO;CAClD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAuB;IACpD,mDAAmD,EAAE,OAAO;IAC5D,6CAA6C,EAAE,OAAO;IACtD,kDAAkD,EAAE,OAAO;CAC5D,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuB;IACrD,yCAAyC,EAAE,OAAO;CACnD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,qCAAqC,EAAE,OAAO;IAC9C,2CAA2C,EAAE,OAAO;IACpD,qCAAqC,EAAE,OAAO;CAC/C,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { rules } from "./rules/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Self-contained flat config entries — each registers the plugin, so a consumer
|
|
4
|
+
* needs no `plugins` entry of their own, and they compose:
|
|
5
|
+
*
|
|
6
|
+
* ```js
|
|
7
|
+
* import composurecdk from "@composurecdk/eslint-plugin";
|
|
8
|
+
* export default [
|
|
9
|
+
* {
|
|
10
|
+
* files: ["src/**\/*.ts"],
|
|
11
|
+
* extends: [composurecdk.configs.recommended, composurecdk.configs.dualPublishing],
|
|
12
|
+
* },
|
|
13
|
+
* ];
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* None declares `files`: the rules target library source, but only the consumer
|
|
17
|
+
* knows where theirs lives. See `./configs/presets.ts` for which rules each
|
|
18
|
+
* holds and why.
|
|
19
|
+
*/
|
|
20
|
+
export declare const configs: {
|
|
21
|
+
recommended: {
|
|
22
|
+
name: string;
|
|
23
|
+
plugins: {
|
|
24
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
25
|
+
};
|
|
26
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
27
|
+
};
|
|
28
|
+
libraryAuthor: {
|
|
29
|
+
name: string;
|
|
30
|
+
plugins: {
|
|
31
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
32
|
+
};
|
|
33
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
34
|
+
};
|
|
35
|
+
dualPublishing: {
|
|
36
|
+
name: string;
|
|
37
|
+
plugins: {
|
|
38
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
39
|
+
};
|
|
40
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
41
|
+
};
|
|
42
|
+
internal: {
|
|
43
|
+
name: string;
|
|
44
|
+
plugins: {
|
|
45
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
46
|
+
};
|
|
47
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export { rules };
|
|
51
|
+
declare const _default: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin & {
|
|
52
|
+
configs: {
|
|
53
|
+
recommended: {
|
|
54
|
+
name: string;
|
|
55
|
+
plugins: {
|
|
56
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
57
|
+
};
|
|
58
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
59
|
+
};
|
|
60
|
+
libraryAuthor: {
|
|
61
|
+
name: string;
|
|
62
|
+
plugins: {
|
|
63
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
64
|
+
};
|
|
65
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
66
|
+
};
|
|
67
|
+
dualPublishing: {
|
|
68
|
+
name: string;
|
|
69
|
+
plugins: {
|
|
70
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
71
|
+
};
|
|
72
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
73
|
+
};
|
|
74
|
+
internal: {
|
|
75
|
+
name: string;
|
|
76
|
+
plugins: {
|
|
77
|
+
composurecdk: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin;
|
|
78
|
+
};
|
|
79
|
+
rules: import("@eslint/core", { with: { "resolution-mode": "require" } }).RulesConfig;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export default _default;
|
|
84
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAkBzC;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqBqB,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEjB,wBAAkD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { dualPublishingRules, internalRules, libraryAuthorRules, recommendedRules, } from "./configs/presets.js";
|
|
2
|
+
import { rules } from "./rules/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* The plugin object, built before `configs` so every preset can register *this*
|
|
5
|
+
* object under `plugins`.
|
|
6
|
+
*
|
|
7
|
+
* The identity matters. ESLint rejects a flat config whose entries register two
|
|
8
|
+
* different objects under one plugin name, so a consumer extending two presets
|
|
9
|
+
* at once — or extending one and writing `plugins: { composurecdk }` themselves
|
|
10
|
+
* — must be handing ESLint the same reference each time. `Object.assign` below
|
|
11
|
+
* attaches `configs` to this object rather than producing a second one.
|
|
12
|
+
*/
|
|
13
|
+
const plugin = {
|
|
14
|
+
// Names the plugin in `--print-config` output and the flat config inspector.
|
|
15
|
+
meta: { name: "@composurecdk/eslint-plugin" },
|
|
16
|
+
rules,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Self-contained flat config entries — each registers the plugin, so a consumer
|
|
20
|
+
* needs no `plugins` entry of their own, and they compose:
|
|
21
|
+
*
|
|
22
|
+
* ```js
|
|
23
|
+
* import composurecdk from "@composurecdk/eslint-plugin";
|
|
24
|
+
* export default [
|
|
25
|
+
* {
|
|
26
|
+
* files: ["src/**\/*.ts"],
|
|
27
|
+
* extends: [composurecdk.configs.recommended, composurecdk.configs.dualPublishing],
|
|
28
|
+
* },
|
|
29
|
+
* ];
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* None declares `files`: the rules target library source, but only the consumer
|
|
33
|
+
* knows where theirs lives. See `./configs/presets.ts` for which rules each
|
|
34
|
+
* holds and why.
|
|
35
|
+
*/
|
|
36
|
+
export const configs = {
|
|
37
|
+
recommended: {
|
|
38
|
+
name: "composurecdk/recommended",
|
|
39
|
+
plugins: { composurecdk: plugin },
|
|
40
|
+
rules: recommendedRules,
|
|
41
|
+
},
|
|
42
|
+
libraryAuthor: {
|
|
43
|
+
name: "composurecdk/library-author",
|
|
44
|
+
plugins: { composurecdk: plugin },
|
|
45
|
+
rules: libraryAuthorRules,
|
|
46
|
+
},
|
|
47
|
+
dualPublishing: {
|
|
48
|
+
name: "composurecdk/dual-publishing",
|
|
49
|
+
plugins: { composurecdk: plugin },
|
|
50
|
+
rules: dualPublishingRules,
|
|
51
|
+
},
|
|
52
|
+
internal: {
|
|
53
|
+
name: "composurecdk/internal",
|
|
54
|
+
plugins: { composurecdk: plugin },
|
|
55
|
+
rules: internalRules,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
export { rules };
|
|
59
|
+
export default Object.assign(plugin, { configs });
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC;;;;;;;;;GASG;AACH,MAAM,MAAM,GAAkB;IAC5B,6EAA6E;IAC7E,IAAI,EAAE,EAAE,IAAI,EAAE,6BAA6B,EAAE;IAC7C,KAAK;CACN,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,WAAW,EAAE;QACX,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;QACjC,KAAK,EAAE,gBAAgB;KACxB;IACD,aAAa,EAAE;QACb,IAAI,EAAE,6BAA6B;QACnC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;QACjC,KAAK,EAAE,kBAAkB;KAC1B;IACD,cAAc,EAAE;QACd,IAAI,EAAE,8BAA8B;QACpC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;QACjC,KAAK,EAAE,mBAAmB;KAC3B;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,uBAAuB;QAC7B,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;QACjC,KAAK,EAAE,aAAa;KACrB;CACsC,CAAC;AAE1C,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,eAAe,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Flags `Builder()` or `IBuilder<…>` from `@composurecdk/core` in a builder that
|
|
4
|
+
* wraps a taggable resource.
|
|
5
|
+
*
|
|
6
|
+
* Tagging is cross-cutting: every deployable resource needs it, and a consumer
|
|
7
|
+
* expects the same tagging surface on every builder rather than on whichever
|
|
8
|
+
* ones remembered to add it. `taggedBuilder` / `ITaggedBuilder` from
|
|
9
|
+
* `@composurecdk/cloudformation` supply that surface; the core builder does not,
|
|
10
|
+
* because core stays independent of CloudFormation.
|
|
11
|
+
*
|
|
12
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/builder-must-be-tagged.md | the rule documentation}.
|
|
13
|
+
*/
|
|
14
|
+
export declare const rule: Rule.RuleModule;
|
|
15
|
+
//# sourceMappingURL=builder-must-be-tagged.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-must-be-tagged.d.ts","sourceRoot":"","sources":["../../../src/rules/builder-must-be-tagged.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAanC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAkDvB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const taggedSuffix = "If the wrapped CFN resource has no Tags property (Route53 records, IAM ManagedPolicy, " +
|
|
2
|
+
"SNS Subscription, AWS Budgets), disable this rule on the offending line with a directive " +
|
|
3
|
+
"naming the resource: `// eslint-disable-next-line composurecdk/builder-must-be-tagged -- AWS::… has no Tags property`.";
|
|
4
|
+
/**
|
|
5
|
+
* Flags `Builder()` or `IBuilder<…>` from `@composurecdk/core` in a builder that
|
|
6
|
+
* wraps a taggable resource.
|
|
7
|
+
*
|
|
8
|
+
* Tagging is cross-cutting: every deployable resource needs it, and a consumer
|
|
9
|
+
* expects the same tagging surface on every builder rather than on whichever
|
|
10
|
+
* ones remembered to add it. `taggedBuilder` / `ITaggedBuilder` from
|
|
11
|
+
* `@composurecdk/cloudformation` supply that surface; the core builder does not,
|
|
12
|
+
* because core stays independent of CloudFormation.
|
|
13
|
+
*
|
|
14
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/builder-must-be-tagged.md | the rule documentation}.
|
|
15
|
+
*/
|
|
16
|
+
export const rule = {
|
|
17
|
+
meta: {
|
|
18
|
+
type: "problem",
|
|
19
|
+
docs: {
|
|
20
|
+
description: "Library builders must use `taggedBuilder` / `ITaggedBuilder` from `@composurecdk/cloudformation` " +
|
|
21
|
+
"unless the wrapped CFN resource has no Tags property.",
|
|
22
|
+
},
|
|
23
|
+
schema: [],
|
|
24
|
+
messages: {
|
|
25
|
+
restrictedCall: "Use `taggedBuilder` from `@composurecdk/cloudformation` instead of `Builder` from `@composurecdk/core`. " +
|
|
26
|
+
taggedSuffix,
|
|
27
|
+
restrictedType: "Use `ITaggedBuilder` from `@composurecdk/cloudformation` instead of `IBuilder` from `@composurecdk/core`. " +
|
|
28
|
+
taggedSuffix,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
create(ctx) {
|
|
32
|
+
const localBuilderNames = new Set();
|
|
33
|
+
const localIBuilderNames = new Set();
|
|
34
|
+
const listener = {
|
|
35
|
+
ImportDeclaration(node) {
|
|
36
|
+
if (node.source.value !== "@composurecdk/core")
|
|
37
|
+
return;
|
|
38
|
+
for (const spec of node.specifiers) {
|
|
39
|
+
if (spec.type !== "ImportSpecifier")
|
|
40
|
+
continue;
|
|
41
|
+
if (spec.imported.type !== "Identifier")
|
|
42
|
+
continue;
|
|
43
|
+
if (spec.imported.name === "Builder")
|
|
44
|
+
localBuilderNames.add(spec.local.name);
|
|
45
|
+
if (spec.imported.name === "IBuilder")
|
|
46
|
+
localIBuilderNames.add(spec.local.name);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
CallExpression(node) {
|
|
50
|
+
if (node.callee.type === "Identifier" && localBuilderNames.has(node.callee.name)) {
|
|
51
|
+
ctx.report({ node: node.callee, messageId: "restrictedCall" });
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
listener.TSTypeReference = (node) => {
|
|
56
|
+
const ref = node;
|
|
57
|
+
const name = ref.typeName.name;
|
|
58
|
+
if (ref.typeName.type === "Identifier" &&
|
|
59
|
+
name !== undefined &&
|
|
60
|
+
localIBuilderNames.has(name)) {
|
|
61
|
+
ctx.report({ node: ref.typeName, messageId: "restrictedType" });
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return listener;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=builder-must-be-tagged.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-must-be-tagged.js","sourceRoot":"","sources":["../../../src/rules/builder-must-be-tagged.ts"],"names":[],"mappings":"AAGA,MAAM,YAAY,GAChB,wFAAwF;IACxF,2FAA2F;IAC3F,wHAAwH,CAAC;AAO3H;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,IAAI,GAAoB;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,mGAAmG;gBACnG,uDAAuD;SAC1D;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,cAAc,EACZ,0GAA0G;gBAC1G,YAAY;YACd,cAAc,EACZ,4GAA4G;gBAC5G,YAAY;SACf;KACF;IACD,MAAM,CAAC,GAAG;QACR,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC5C,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC7C,MAAM,QAAQ,GAAsB;YAClC,iBAAiB,CAAC,IAAI;gBACpB,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAoB;oBAAE,OAAO;gBACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACnC,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;wBAAE,SAAS;oBAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBAAE,SAAS;oBAClD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS;wBAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC7E,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,UAAU;wBAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACjF,CAAC;YACH,CAAC;YACD,cAAc,CAAC,IAAI;gBACjB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBACjF,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC;SACF,CAAC;QACF,QAAQ,CAAC,eAAe,GAAG,CAAC,IAAU,EAAE,EAAE;YACxC,MAAM,GAAG,GAAG,IAAsC,CAAC;YACnD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC/B,IACE,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;gBAClC,IAAI,KAAK,SAAS;gBAClB,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,EAC5B,CAAC;gBACD,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
/**
|
|
3
|
+
* Flags a builder class holding private state with no `[COPY_STATE]` hook.
|
|
4
|
+
*
|
|
5
|
+
* `.copy()` shallow-clones the builder's props. State held in private fields sits
|
|
6
|
+
* outside that copy, so without the hook it is silently dropped: the clone looks
|
|
7
|
+
* correct and behaves differently. Implement `[COPY_STATE]` to carry such state
|
|
8
|
+
* onto the clone.
|
|
9
|
+
*
|
|
10
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/builder-must-implement-copy-state.md | the rule documentation}.
|
|
11
|
+
*/
|
|
12
|
+
export declare const rule: Rule.RuleModule;
|
|
13
|
+
//# sourceMappingURL=builder-must-implement-copy-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-must-implement-copy-state.d.ts","sourceRoot":"","sources":["../../../src/rules/builder-must-implement-copy-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,QAAQ,CAAC;AAkB/C;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,EAAE,IAAI,CAAC,UAkGvB,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
function readIgnoreMarker(fieldNode, sourceCode) {
|
|
2
|
+
const comments = sourceCode.getCommentsBefore(fieldNode);
|
|
3
|
+
for (const comment of comments) {
|
|
4
|
+
const match = /@copy-state:\s*ignore(.*)$/i.exec(comment.value);
|
|
5
|
+
if (!match)
|
|
6
|
+
continue;
|
|
7
|
+
const tail = match[1];
|
|
8
|
+
return /--\s*\S/.test(tail) ? "valid" : "missing-justification";
|
|
9
|
+
}
|
|
10
|
+
return "absent";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Flags a builder class holding private state with no `[COPY_STATE]` hook.
|
|
14
|
+
*
|
|
15
|
+
* `.copy()` shallow-clones the builder's props. State held in private fields sits
|
|
16
|
+
* outside that copy, so without the hook it is silently dropped: the clone looks
|
|
17
|
+
* correct and behaves differently. Implement `[COPY_STATE]` to carry such state
|
|
18
|
+
* onto the clone.
|
|
19
|
+
*
|
|
20
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/builder-must-implement-copy-state.md | the rule documentation}.
|
|
21
|
+
*/
|
|
22
|
+
export const rule = {
|
|
23
|
+
meta: {
|
|
24
|
+
type: "problem",
|
|
25
|
+
docs: {
|
|
26
|
+
description: "Builder classes with private fields must implement `[COPY_STATE]` " +
|
|
27
|
+
"(or annotate fields with `// @copy-state: ignore -- reason`). See ADR-0005.",
|
|
28
|
+
},
|
|
29
|
+
schema: [],
|
|
30
|
+
messages: {
|
|
31
|
+
missingHook: "Builder class `{{className}}` has private field(s) {{fields}} but no `[COPY_STATE]` hook. " +
|
|
32
|
+
"`.copy()` shallow-clones props only, so these fields are silently dropped from the " +
|
|
33
|
+
"clone. Implement `[COPY_STATE](target) { … }` to carry them across, or annotate each " +
|
|
34
|
+
"field with `// @copy-state: ignore -- reason`.",
|
|
35
|
+
ignoreMarkerNeedsJustification: "`@copy-state: ignore` on field `{{field}}` must include a justification after `--` " +
|
|
36
|
+
"(e.g. `// @copy-state: ignore -- regenerated per build`). The reason survives refactors " +
|
|
37
|
+
"and shows up in code review.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
create(ctx) {
|
|
41
|
+
const sourceCode = ctx.sourceCode;
|
|
42
|
+
const builderFactoryNames = new Set();
|
|
43
|
+
const classNodes = new Map();
|
|
44
|
+
const builderClassNames = new Set();
|
|
45
|
+
return {
|
|
46
|
+
ImportDeclaration(node) {
|
|
47
|
+
if (node.source.value !== "@composurecdk/core" &&
|
|
48
|
+
node.source.value !== "@composurecdk/cloudformation") {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
for (const spec of node.specifiers) {
|
|
52
|
+
if (spec.type !== "ImportSpecifier")
|
|
53
|
+
continue;
|
|
54
|
+
if (spec.imported.type !== "Identifier")
|
|
55
|
+
continue;
|
|
56
|
+
if (spec.imported.name === "Builder" || spec.imported.name === "taggedBuilder") {
|
|
57
|
+
builderFactoryNames.add(spec.local.name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
ClassDeclaration(node) {
|
|
62
|
+
classNodes.set(node.id.name, node);
|
|
63
|
+
},
|
|
64
|
+
CallExpression(node) {
|
|
65
|
+
if (node.callee.type !== "Identifier")
|
|
66
|
+
return;
|
|
67
|
+
if (!builderFactoryNames.has(node.callee.name))
|
|
68
|
+
return;
|
|
69
|
+
if (node.arguments.length === 0)
|
|
70
|
+
return;
|
|
71
|
+
const arg = node.arguments[0];
|
|
72
|
+
if (arg.type === "Identifier")
|
|
73
|
+
builderClassNames.add(arg.name);
|
|
74
|
+
},
|
|
75
|
+
"Program:exit"() {
|
|
76
|
+
for (const className of builderClassNames) {
|
|
77
|
+
const classNode = classNodes.get(className);
|
|
78
|
+
if (!classNode)
|
|
79
|
+
continue;
|
|
80
|
+
const privateFields = [];
|
|
81
|
+
let hasCopyStateHook = false;
|
|
82
|
+
for (const member of classNode.body.body) {
|
|
83
|
+
if (member.type === "PropertyDefinition" && member.key.type === "PrivateIdentifier") {
|
|
84
|
+
privateFields.push(member);
|
|
85
|
+
}
|
|
86
|
+
else if (member.type === "MethodDefinition" &&
|
|
87
|
+
member.computed &&
|
|
88
|
+
member.key.type === "Identifier" &&
|
|
89
|
+
member.key.name === "COPY_STATE") {
|
|
90
|
+
hasCopyStateHook = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const fieldsNeedingHook = [];
|
|
94
|
+
for (const field of privateFields) {
|
|
95
|
+
const ignoreState = readIgnoreMarker(field, sourceCode);
|
|
96
|
+
if (ignoreState === "valid")
|
|
97
|
+
continue;
|
|
98
|
+
if (ignoreState === "missing-justification") {
|
|
99
|
+
ctx.report({
|
|
100
|
+
node: field,
|
|
101
|
+
messageId: "ignoreMarkerNeedsJustification",
|
|
102
|
+
data: { field: `#${field.key.name}` },
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
fieldsNeedingHook.push(`#${field.key.name}`);
|
|
107
|
+
}
|
|
108
|
+
if (!hasCopyStateHook && fieldsNeedingHook.length > 0) {
|
|
109
|
+
ctx.report({
|
|
110
|
+
node: classNode.id,
|
|
111
|
+
messageId: "missingHook",
|
|
112
|
+
data: { className, fields: fieldsNeedingHook.join(", ") },
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
//# 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,76 @@
|
|
|
1
|
+
const REQUIRED_FIELDS = ["name", "allowed", "source"];
|
|
2
|
+
function propertyKey(property) {
|
|
3
|
+
if (property.computed)
|
|
4
|
+
return undefined;
|
|
5
|
+
if (property.key.type === "Identifier")
|
|
6
|
+
return property.key.name;
|
|
7
|
+
if (property.key.type === "Literal")
|
|
8
|
+
return String(property.key.value);
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
function isEmptyStringLiteral(value) {
|
|
12
|
+
return value.type === "Literal" && typeof value.value === "string" && value.value.trim() === "";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Requires every `stringConstraint({ … })` call to set a non-empty `name`,
|
|
16
|
+
* `allowed` and `source`.
|
|
17
|
+
*
|
|
18
|
+
* Those three fields are what turn a synth-time validation failure into
|
|
19
|
+
* something actionable — they name the offending property, list the characters
|
|
20
|
+
* it accepts, and link the AWS documentation. The factory's type already makes
|
|
21
|
+
* the keys required, so the gap this closes is the one the type checker cannot
|
|
22
|
+
* see: a present-but-empty string compiles happily while degrading every message
|
|
23
|
+
* the constraint will ever produce.
|
|
24
|
+
*
|
|
25
|
+
* See {@link https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules/constraint-metadata-required.md | the rule documentation}.
|
|
26
|
+
*/
|
|
27
|
+
export const rule = {
|
|
28
|
+
meta: {
|
|
29
|
+
type: "problem",
|
|
30
|
+
docs: {
|
|
31
|
+
description: "stringConstraint() must set a non-empty name, allowed, and source so every validation error names the allowed set and links the AWS doc",
|
|
32
|
+
},
|
|
33
|
+
schema: [],
|
|
34
|
+
messages: {
|
|
35
|
+
missingField: "stringConstraint() is missing required `{{field}}`. Every catalogue entry must set " +
|
|
36
|
+
"name, allowed and source, so a synth-time error can name the allowed set and link the AWS doc.",
|
|
37
|
+
emptyField: "stringConstraint() `{{field}}` is empty. It is surfaced verbatim in the validation " +
|
|
38
|
+
"error message — give it a meaningful value.",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
create(ctx) {
|
|
42
|
+
return {
|
|
43
|
+
CallExpression(node) {
|
|
44
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "stringConstraint") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (node.arguments.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const arg = node.arguments[0];
|
|
50
|
+
if (arg.type !== "ObjectExpression")
|
|
51
|
+
return;
|
|
52
|
+
// A spread could supply any of the required fields — can't verify statically.
|
|
53
|
+
if (arg.properties.some((p) => p.type === "SpreadElement"))
|
|
54
|
+
return;
|
|
55
|
+
const values = new Map();
|
|
56
|
+
for (const property of arg.properties) {
|
|
57
|
+
if (property.type !== "Property")
|
|
58
|
+
continue;
|
|
59
|
+
const key = propertyKey(property);
|
|
60
|
+
if (key !== undefined)
|
|
61
|
+
values.set(key, property.value);
|
|
62
|
+
}
|
|
63
|
+
for (const field of REQUIRED_FIELDS) {
|
|
64
|
+
const value = values.get(field);
|
|
65
|
+
if (value === undefined) {
|
|
66
|
+
ctx.report({ node, messageId: "missingField", data: { field } });
|
|
67
|
+
}
|
|
68
|
+
else if (isEmptyStringLiteral(value)) {
|
|
69
|
+
ctx.report({ node: value, messageId: "emptyField", data: { field } });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
//# 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;AACH,MAAM,CAAC,MAAM,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,49 @@
|
|
|
1
|
+
import { rule as builderMustBeTagged } from "./builder-must-be-tagged.js";
|
|
2
|
+
import { rule as builderMustImplementCopyState } from "./builder-must-implement-copy-state.js";
|
|
3
|
+
import { rule as constraintMetadataRequired } from "./constraint-metadata-required.js";
|
|
4
|
+
import { rule as lifecycleBuildContextRequired } from "./lifecycle-build-context-required.js";
|
|
5
|
+
import { rule as lifecycleBuildMustForwardContext } from "./lifecycle-build-must-forward-context.js";
|
|
6
|
+
import { rule as noCdkApiAboveFloor } from "./no-cdk-api-above-floor.js";
|
|
7
|
+
import { rule as noCjsIncompatibleSyntax } from "./no-cjs-incompatible-syntax.js";
|
|
8
|
+
import { rule as noRealmBoundInstanceof } from "./no-realm-bound-instanceof.js";
|
|
9
|
+
import { rule as noTypescriptPrivateModifier } from "./no-typescript-private-modifier.js";
|
|
10
|
+
import { rule as redeclaredPropMustTrackCdkType } from "./redeclared-prop-must-track-cdk-type.js";
|
|
11
|
+
/**
|
|
12
|
+
* Where each rule's documentation lives — the page an editor opens from a
|
|
13
|
+
* reported violation.
|
|
14
|
+
*
|
|
15
|
+
* Pinned to `main` rather than the release tag: reading the package's own
|
|
16
|
+
* version needs a JSON import, which does not emit cleanly to CommonJS
|
|
17
|
+
* (ADR-0007). The cost is that a consumer on an older version is shown current
|
|
18
|
+
* docs, which is the same trade most published plugins make.
|
|
19
|
+
*/
|
|
20
|
+
const DOCS_BASE = "https://github.com/laazyj/composureCDK/blob/main/packages/eslint-plugin/docs/rules";
|
|
21
|
+
/**
|
|
22
|
+
* Attaches `meta.docs.url` to every rule, derived from the name it is
|
|
23
|
+
* registered under.
|
|
24
|
+
*
|
|
25
|
+
* Deriving beats writing it per rule: the link an editor offers cannot disagree
|
|
26
|
+
* with the rule id ESLint reports, and adding a rule cannot forget it.
|
|
27
|
+
*/
|
|
28
|
+
function withDocsUrl(entries) {
|
|
29
|
+
return Object.fromEntries(Object.entries(entries).map(([name, rule]) => [
|
|
30
|
+
name,
|
|
31
|
+
{
|
|
32
|
+
...rule,
|
|
33
|
+
meta: { ...rule.meta, docs: { ...rule.meta?.docs, url: `${DOCS_BASE}/${name}.md` } },
|
|
34
|
+
},
|
|
35
|
+
]));
|
|
36
|
+
}
|
|
37
|
+
export const rules = withDocsUrl({
|
|
38
|
+
"builder-must-be-tagged": builderMustBeTagged,
|
|
39
|
+
"builder-must-implement-copy-state": builderMustImplementCopyState,
|
|
40
|
+
"constraint-metadata-required": constraintMetadataRequired,
|
|
41
|
+
"lifecycle-build-context-required": lifecycleBuildContextRequired,
|
|
42
|
+
"lifecycle-build-must-forward-context": lifecycleBuildMustForwardContext,
|
|
43
|
+
"no-cdk-api-above-floor": noCdkApiAboveFloor,
|
|
44
|
+
"no-cjs-incompatible-syntax": noCjsIncompatibleSyntax,
|
|
45
|
+
"no-realm-bound-instanceof": noRealmBoundInstanceof,
|
|
46
|
+
"no-typescript-private-modifier": noTypescriptPrivateModifier,
|
|
47
|
+
"redeclared-prop-must-track-cdk-type": redeclaredPropMustTrackCdkType,
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,IAAI,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,IAAI,IAAI,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAC/F,OAAO,EAAE,IAAI,IAAI,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAE,IAAI,IAAI,6BAA6B,EAAE,MAAM,uCAAuC,CAAC;AAC9F,OAAO,EAAE,IAAI,IAAI,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AACrG,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAClF,OAAO,EAAE,IAAI,IAAI,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EAAE,IAAI,IAAI,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAC1F,OAAO,EAAE,IAAI,IAAI,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;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;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC;IAC/B,wBAAwB,EAAE,mBAAmB;IAC7C,mCAAmC,EAAE,6BAA6B;IAClE,8BAA8B,EAAE,0BAA0B;IAC1D,kCAAkC,EAAE,6BAA6B;IACjE,sCAAsC,EAAE,gCAAgC;IACxE,wBAAwB,EAAE,kBAAkB;IAC5C,4BAA4B,EAAE,uBAAuB;IACrD,2BAA2B,EAAE,sBAAsB;IACnD,gCAAgC,EAAE,2BAA2B;IAC7D,qCAAqC,EAAE,8BAA8B;CACtE,CAAC,CAAC"}
|