@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,87 @@
1
+ # composurecdk/no-realm-bound-instanceof
2
+
3
+ Bans `instanceof` against a class reached through an `import`, in library `src/`.
4
+
5
+ - **Preset:** `recommended` (`error`)
6
+ - **Decision:** [ADR-0007](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0007-dual-esm-cjs-publishing.md), [ADR-0011](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0011-cross-component-relationship-guards.md), [ADR-0019](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0019-lint-rules-as-public-contract.md)
7
+
8
+ ## Why
9
+
10
+ `instanceof` is realm-bound, and library source is published dual ESM/CJS. When both copies of a package load in one process — the dual-package hazard — each copy has its own class objects. An instance minted by one copy fails `instanceof` against the other copy's class, so the check returns `false` for a value that is plainly of that type.
11
+
12
+ That has already shipped as two bugs: **#384**, where a stack-singleton dedup was silently skipped and collided on a construct id, and **#385**, where a `StatementBuilder` went unrecognised and skipped the wildcard-resource security guard. Both failed silently, which is the characteristic danger here.
13
+
14
+ ## ❌ Incorrect
15
+
16
+ ```ts
17
+ import { StatementBuilder } from "./statement-builder.js";
18
+
19
+ if (value instanceof StatementBuilder) {
20
+ // false across the dual-package boundary
21
+ }
22
+ ```
23
+
24
+ ## ✅ Correct
25
+
26
+ ```ts
27
+ const STATEMENT_BUILDER = Symbol.for("composurecdk.statement-builder");
28
+
29
+ if (typeof value === "object" && value !== null && STATEMENT_BUILDER in value) {
30
+ // a Symbol.for brand is realm-agnostic
31
+ }
32
+ ```
33
+
34
+ That is the fix when the class is **yours**. The report tells you which case you are in, because the import says so:
35
+
36
+ | Import | Message | Fix |
37
+ | -------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38
+ | Relative — your own module | `ownClass` | Brand it with `Symbol.for(…)`. |
39
+ | `aws-cdk-lib` | `cdkClass` | Read the L1 — `CfnResource.isCfnResource(x) && x.cfnResourceType === …`, per [ADR-0011](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0011-cross-component-relationship-guards.md). |
40
+ | Any other package | `dependencyClass` | You cannot brand a class you do not own. Prefer a type guard the package exports, or test a distinguishing property rather than identity. |
41
+
42
+ ## Every import is in scope by default, relative ones included
43
+
44
+ A relative import is **not** a same-realm guarantee by default. `./statement-builder.js` resolves separately in each copy of the package, which is exactly how #385 happened.
45
+
46
+ ## Options
47
+
48
+ ### `assumeNeverInstalledAsADependency`
49
+
50
+ ```js
51
+ "composurecdk/no-realm-bound-instanceof": ["error", { assumeNeverInstalledAsADependency: true }]
52
+ ```
53
+
54
+ Asserts that **this package cannot load twice in one process**, so its own modules resolve to one set of class objects. Relative imports are then treated as same-realm; everything else is still flagged, because whether a _dependency_ loads twice is a property of the consumer's install, not of your source.
55
+
56
+ **An application is the archetype** — nothing installs one as a dependency, so it genuinely loads once. Being `private` is not the test: a private package can still be a dependency, and one in this repo is depended on by seventeen others.
57
+
58
+ **A library must not set it**, even a single-format one. A consumer can install two versions of your library side by side, and then your relative imports duplicate exactly as a dual-published package's do — the hazard returns with the option silencing it. Shipping one module format is not sufficient; the condition is that nothing can install you twice.
59
+
60
+ Default `false`, which flags every import.
61
+
62
+ Only relative specifiers are exempted. A `#` subpath is **not**: Node's `imports` field can map one to an external package, so `#dep` may resolve into `node_modules` like any dependency.
63
+
64
+ ### Why this is an option rather than a preset
65
+
66
+ Only one of the rule's two halves is a property of your own package, so a tier cannot express it — moving the whole rule into `dualPublishing` would silence the bare-specifier half, which is the half that caused both shipped bugs. See [ADR-0019](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0019-lint-rules-as-public-contract.md) and [#450](https://github.com/laazyj/composureCDK/issues/450).
67
+
68
+ ## Not flagged
69
+
70
+ Neither can be duplicated by the hazard:
71
+
72
+ - **Globals and intrinsics** — `x instanceof RegExp`, `x instanceof Error`. They resolve to no import binding, so the scope walk skips them.
73
+ - **Classes declared in the same module** — the class and every `new` of it come from one evaluation of that module.
74
+
75
+ ## Known gaps
76
+
77
+ Both uncommon in this ESM source:
78
+
79
+ - `import = require()` bindings.
80
+ - An intermediate call that breaks the chain — `getClasses().Bucket` reads a runtime value rather than the import.
81
+ - A **relative path that leaves the package** (`../../other/src/x.js`, possible in a workspace) is exempted by the option although it reaches a different package. This repo bans that import shape outright; a consumer's may not.
82
+ - A **tsconfig path alias** (`@app/thing`, `~/thing`) resolves in-package but looks bare, so it is still flagged under the option — an over-report, not a miss.
83
+ - A package importing **itself by name** (`@scope/pkg` from inside `@scope/pkg`) is treated as a dependency, so `assumeNeverInstalledAsADependency` does not exempt it. Conservative rather than wrong — it over-reports, never under-reports — and self-reference needs an `exports` field, which an application, the only legitimate setter of that option, does not have.
84
+
85
+ ## How it works
86
+
87
+ Resolution is scope-aware, so a local shadowing an import name is correctly treated as a non-import binding. TS-only wrappers (`as`, `!`, `satisfies`, angle-bracket assertion) are unwrapped rather than trusted.
@@ -0,0 +1,72 @@
1
+ # composurecdk/no-typescript-private-modifier
2
+
3
+ Flags the TypeScript `private` modifier on a class member, in favour of an ECMAScript `#` private field.
4
+
5
+ - **Preset:** `libraryAuthor` (`error`)
6
+ - **Decision:** [ADR-0001](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0001-builder-type-emission.md)
7
+
8
+ ## Why
9
+
10
+ The two kinds of privacy look interchangeable and are not, once a class is generic over its own members.
11
+
12
+ A TypeScript `private` member is still **part of the type**. It appears in `keyof T`, so it survives into any mapped type built from the class — and from there into the emitted `.d.ts`, where a consumer's compiler meets a name it cannot refer to and reports **TS4094**. The error surfaces in the consumer's build, not in the one that produced the declaration.
13
+
14
+ An ECMAScript `#field` is not part of the type at all, so nothing downstream can trip over it.
15
+
16
+ Builders are the case that forces this, since a builder's public type is derived from its class by a mapped type — but the hazard belongs to any class whose type is transformed rather than written out by hand.
17
+
18
+ ## ❌ Incorrect
19
+
20
+ ```ts
21
+ class BucketBuilderImpl {
22
+ private props: BucketProps = {};
23
+
24
+ private clone(): this {
25
+ return this;
26
+ }
27
+ }
28
+
29
+ class Component {
30
+ constructor(private readonly scope: IConstruct) {}
31
+ }
32
+ ```
33
+
34
+ ## ✅ Correct
35
+
36
+ ```ts
37
+ class BucketBuilderImpl {
38
+ #props: BucketProps = {};
39
+
40
+ #clone(): this {
41
+ return this;
42
+ }
43
+ }
44
+
45
+ class Component {
46
+ readonly #scope: IConstruct;
47
+
48
+ constructor(scope: IConstruct) {
49
+ this.#scope = scope;
50
+ }
51
+ }
52
+ ```
53
+
54
+ A parameter property cannot be `#private` — there is no syntax for it — so the field is declared on the class and assigned in the constructor body.
55
+
56
+ ## Not flagged
57
+
58
+ | Shape | Why it is allowed |
59
+ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
60
+ | `private constructor() {}` | `#constructor` is not valid syntax, so there is nothing to prefer. Private constructors stay available for factory-only classes. |
61
+ | `protected` and `public` members | Deliberately part of the type; this rule is only about privacy that leaks. |
62
+ | `constructor(readonly scope: T)` | A parameter property with no accessibility modifier. It is public by design. |
63
+
64
+ ## How it works
65
+
66
+ Three syntactic selectors — a `private` property, a `private` method that is not a constructor, and a `private` parameter property. No type information, so it runs in a flat config and reports as you type.
67
+
68
+ ## History
69
+
70
+ `private accessor x` was not caught while this was a config: `accessor` fields parse as a distinct node that none of the three selectors matched, though the `private` on one reaches `keyof T` exactly as a plain field's does. The rule closes that hole, so it flags slightly more than the selectors did.
71
+
72
+ This shipped as three `no-restricted-syntax` selectors before becoming a rule. That was fine while the preset was private to one repo and fatal once published: flat config **replaces** rule options rather than merging them, so a consumer configuring `no-restricted-syntax` for their own purposes would silently drop all three selectors — no error, no warning. A named rule composes instead of colliding.
@@ -0,0 +1,60 @@
1
+ # composurecdk/redeclared-prop-must-track-cdk-type
2
+
3
+ Flags a re-declared CDK prop that pins a named CDK interface inside `Resolvable<…>` instead of reading the type from CDK's own prop.
4
+
5
+ - **Preset:** `libraryAuthor` (`error`)
6
+ - **Decision:** [ADR-0018](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0018-re-declared-props-track-cdk-prop-types.md)
7
+
8
+ ## Why
9
+
10
+ A builder's props interface is `Omit<CdkProps, K>` plus a re-declaration of each lifted key. Everything inside the `Omit` tracks the consumer's installed `aws-cdk-lib` — that is the point of extending CDK's own type. A re-declared key spelled `Resolvable<IKey>` does not: it freezes at whatever interface was current when it was written, so when CDK widens that prop the builder silently starts **rejecting values the wrapped construct accepts**.
11
+
12
+ Nothing else catches it. The suites do not typecheck, and `build` runs against the latest CDK, where a narrowed prop still compiles — it is narrower, not wrong. The failure surfaces in a consumer's own `tsc`.
13
+
14
+ [ADR-0018](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0018-re-declared-props-track-cdk-prop-types.md) has the full case, including the two instances that shipped unnoticed for seven months and why raising the version floors was rejected instead.
15
+
16
+ ## ❌ Incorrect
17
+
18
+ ```ts
19
+ import { type IKey } from "aws-cdk-lib/aws-kms";
20
+ import { type TopicProps } from "aws-cdk-lib/aws-sns";
21
+
22
+ export interface TopicBuilderProps extends Omit<TopicProps, "masterKey"> {
23
+ masterKey?: Resolvable<IKey>;
24
+ }
25
+ ```
26
+
27
+ ## ✅ Correct
28
+
29
+ ```ts
30
+ import { type TopicProps } from "aws-cdk-lib/aws-sns";
31
+
32
+ export interface TopicBuilderProps extends Omit<TopicProps, "masterKey"> {
33
+ masterKey?: Resolvable<NonNullable<TopicProps["masterKey"]>>;
34
+ }
35
+ ```
36
+
37
+ The prop now accepts exactly what the consumer's `aws-cdk-lib` accepts, at every floor, because it _is_ that type.
38
+
39
+ **Keep the indexed access inline.** Extracting it to a named alias puts an unnameable type into the emitted builder type and reintroduces [ADR-0001](https://github.com/laazyj/composureCDK/blob/main/docs/adr/0001-builder-type-emission.md)'s TS2883.
40
+
41
+ ## Not flagged
42
+
43
+ Each is a deliberate exclusion in ADR-0018:
44
+
45
+ | Shape | Why it is allowed |
46
+ | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
47
+ | `Resolvable<string[]>`, `Resolvable<Record<string, unknown>>` | Primitives and `any`-shaped types resolve to no CDK import. |
48
+ | `Resolvable<string \| Foo["bar"]>` | A widened union — the arm the builder adds has no CDK prop to read from. Only a bare type reference is flagged. |
49
+ | A shape-replacing re-declaration | The builder's own type is the point; it is not a `Resolvable` of a CDK interface. |
50
+
51
+ ## Known gaps
52
+
53
+ Both are covered by ADR-0018 and by review rather than by this rule:
54
+
55
+ - A prop re-declared in a **separate interface** that the props interface mixes in (`@composurecdk/sqs`'s `QueueBuilderExtensionProps`) has no `Omit` of its own to key on.
56
+ - A **hand-written setter** standing in for a lifted prop is a class method, not a property signature.
57
+
58
+ ## How it works
59
+
60
+ Purely syntactic — no type resolution, so it runs in the flat config and fires at authoring time. The rule looks for a property whose name appears in the `Omit<…>` of its own interface's `extends` clause, and whose `Resolvable<…>` argument is a bare type reference imported from `aws-cdk-lib` or `@aws-cdk/*`.
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@composurecdk/eslint-plugin",
3
+ "version": "0.10.0",
4
+ "description": "Internal ESLint plugin encoding ComposureCDK architectural invariants (tagged builders, lifecycle context, builder copy state).",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/laazyj/composureCDK.git",
8
+ "directory": "packages/eslint-plugin"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "docs",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "lint": "eslint .",
18
+ "clean": "rm -rf dist .tshy .tshy-build",
19
+ "build": "tshy",
20
+ "typecheck": "tsc --noEmit",
21
+ "check:exports": "attw --pack . --profile node16 && publint",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest"
24
+ },
25
+ "keywords": [
26
+ "eslint",
27
+ "eslintplugin",
28
+ "eslint-plugin",
29
+ "aws-cdk",
30
+ "composurecdk",
31
+ "static-analysis",
32
+ "architecture"
33
+ ],
34
+ "author": "Jason Duffett (https://github.com/laazyj)",
35
+ "license": "MIT",
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "type": "module",
40
+ "engines": {
41
+ "node": ">=20"
42
+ },
43
+ "tshy": {
44
+ "exports": {
45
+ "./package.json": "./package.json",
46
+ ".": "./src/index.ts"
47
+ }
48
+ },
49
+ "peerDependencies": {
50
+ "eslint": "^10.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/estree": "^1.0.9",
54
+ "@types/node": "^26.5.1",
55
+ "@typescript-eslint/parser": "^8.70.0",
56
+ "eslint": "^10.10.0",
57
+ "typescript": "^6.0.3",
58
+ "vitest": "^5.0.0"
59
+ },
60
+ "nx": {
61
+ "tags": [
62
+ "scope:tooling"
63
+ ]
64
+ },
65
+ "exports": {
66
+ "./package.json": "./package.json",
67
+ ".": {
68
+ "import": {
69
+ "types": "./dist/esm/index.d.ts",
70
+ "default": "./dist/esm/index.js"
71
+ },
72
+ "require": {
73
+ "types": "./dist/commonjs/index.d.ts",
74
+ "default": "./dist/commonjs/index.js"
75
+ }
76
+ }
77
+ },
78
+ "main": "./dist/commonjs/index.js",
79
+ "types": "./dist/commonjs/index.d.ts",
80
+ "module": "./dist/esm/index.js"
81
+ }