@fjall/eslint-plugin 31.0.0 → 33.0.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/no-clickhouse-internal-reexport.js +1 -1
- package/no-l2-asg-lifecycle-hook.js +2 -2
- package/no-raw-block-device-volume.js +1 -1
- package/no-raw-cdk-properties-on-public-constructs.js +1 -1
- package/no-undefined-prop-in-construct-id.js +1 -1
- package/no-zod-enum-redeclaring-named-constant.js +29 -13
- package/package.json +1 -1
|
@@ -45,7 +45,7 @@ export default {
|
|
|
45
45
|
},
|
|
46
46
|
messages: {
|
|
47
47
|
forbiddenReexport:
|
|
48
|
-
"Symbol `{{name}}` is ClickHouse-internal plumbing and must not appear on the public surface. Consume via the DatabaseFactory or a typed connector instead.
|
|
48
|
+
"Symbol `{{name}}` is ClickHouse-internal plumbing and must not appear on the public surface. Consume via the DatabaseFactory or a typed connector instead."
|
|
49
49
|
},
|
|
50
50
|
schema: []
|
|
51
51
|
},
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* first instance launches BEFORE the hook is attached, and the hook fires
|
|
8
8
|
* zero notifications for that instance.
|
|
9
9
|
*
|
|
10
|
-
* Production-confirmed
|
|
10
|
+
* Production-confirmed on 2026-05-19: the ClickHouse
|
|
11
11
|
* PDV LAUNCHING hook never fired for the first instance — the Lambda log
|
|
12
12
|
* group only saw a TEST_NOTIFICATION ~30s after instance launch. The volume
|
|
13
13
|
* was never attached, cloud-init timed out, ECS agent never started.
|
|
@@ -38,7 +38,7 @@ export default {
|
|
|
38
38
|
},
|
|
39
39
|
messages: {
|
|
40
40
|
l2AsgHook:
|
|
41
|
-
"ASG L2 `addLifecycleHook(id, props)` emits a standalone AWS::AutoScaling::LifecycleHook resource that creates AFTER the ASG — the first instance launches before the hook is attached (production-confirmed regression,
|
|
41
|
+
"ASG L2 `addLifecycleHook(id, props)` emits a standalone AWS::AutoScaling::LifecycleHook resource that creates AFTER the ASG — the first instance launches before the hook is attached (production-confirmed regression, 2026-05-19). Use `attachInlineAsgLifecycleHook` from `lib/resources/aws/compute/asgInlineLifecycleHook.ts`, which appends to `CfnAutoScalingGroup.lifecycleHookSpecificationList` atomically with the ASG."
|
|
42
42
|
},
|
|
43
43
|
schema: []
|
|
44
44
|
},
|
|
@@ -38,7 +38,7 @@ export default {
|
|
|
38
38
|
},
|
|
39
39
|
messages: {
|
|
40
40
|
rawBlockDeviceVolume:
|
|
41
|
-
"Raw `{{name}}` import from `{{source}}` is forbidden. Use `safeEbs` from `lib/resources/aws/compute/blockDeviceVolume` for ephemeral / root volumes, or `PersistentDataVolume` (Phase 1.75) for data that must survive instance refresh.
|
|
41
|
+
"Raw `{{name}}` import from `{{source}}` is forbidden. Use `safeEbs` from `lib/resources/aws/compute/blockDeviceVolume` for ephemeral / root volumes, or `PersistentDataVolume` (Phase 1.75) for data that must survive instance refresh."
|
|
42
42
|
},
|
|
43
43
|
schema: []
|
|
44
44
|
},
|
|
@@ -53,7 +53,7 @@ export default {
|
|
|
53
53
|
},
|
|
54
54
|
messages: {
|
|
55
55
|
rawCdkProperty:
|
|
56
|
-
"Public property `{{name}}` exposes raw CDK plumbing. Mark it `private readonly` and surface a typed accessor (ARN, endpoint, connector) instead.
|
|
56
|
+
"Public property `{{name}}` exposes raw CDK plumbing. Mark it `private readonly` and surface a typed accessor (ARN, endpoint, connector) instead."
|
|
57
57
|
},
|
|
58
58
|
schema: []
|
|
59
59
|
},
|
|
@@ -63,7 +63,7 @@ export default {
|
|
|
63
63
|
},
|
|
64
64
|
messages: {
|
|
65
65
|
optionalInConstructId:
|
|
66
|
-
"Construct ID interpolates `props.{{field}}` which is optionally typed; when the caller omits this field the literal string 'undefined' is baked into the CloudFormation logical ID. Resolve in the constructor (`this.{{field}}Value = props.{{field}} ?? <fallback>`) and use `this.{{field}}Value` here.
|
|
66
|
+
"Construct ID interpolates `props.{{field}}` which is optionally typed; when the caller omits this field the literal string 'undefined' is baked into the CloudFormation logical ID. Resolve in the constructor (`this.{{field}}Value = props.{{field}} ?? <fallback>`) and use `this.{{field}}Value` here."
|
|
67
67
|
},
|
|
68
68
|
schema: []
|
|
69
69
|
},
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Catches `z.enum([<string-literal>, ...])` declarations whose literal set
|
|
5
5
|
* matches any named SCREAMING_SNAKE_CASE `as const` tuple in
|
|
6
|
-
* `generator/src/schemas/constants.ts
|
|
6
|
+
* `generator/src/schemas/constants.ts`, `sharedTypes.ts` or
|
|
7
|
+
* `util/src/backupTiers.ts` (the backup tier vocabulary's home) — covers the
|
|
7
8
|
* `_TYPES`, `_TIERS`, `_PRESETS`, `_PROVIDERS`, `_ENGINES`, `_METHODS`,
|
|
8
9
|
* `_NAMES`, `_INTERVALS`, `_ARCHITECTURES`, `_VALUES` suffix families. Any
|
|
9
10
|
* exported tuple matching `/^[A-Z][A-Z0-9_]*$/` participates; suffix is not
|
|
@@ -20,12 +21,15 @@
|
|
|
20
21
|
* arm and `z.enum(["AWS_IAM","NONE"])` at another) are themselves a
|
|
21
22
|
* silent-drift hazard — both should route through the named tuple.
|
|
22
23
|
*
|
|
23
|
-
* The registry is built dynamically at rule-init time by reading
|
|
24
|
-
*
|
|
24
|
+
* The registry is built dynamically at rule-init time by reading the
|
|
25
|
+
* source files in `REGISTRY_SOURCES` relative to this rule file. Adding a
|
|
25
26
|
* new `<NAME> = [...] as const` tuple (any SCREAMING_SNAKE_CASE name) to
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* any of them automatically extends the rule's catch surface — no rule
|
|
28
|
+
* edits needed. A tuple that moves home (an alias such as
|
|
29
|
+
* `BACKUP_VAULT_TIERS = BACKUP_TIERS` is not a literal tuple) needs its new
|
|
30
|
+
* home added to the list, or the vocabulary silently drops out of the
|
|
31
|
+
* registry. Spread/concat forms (`APP_TYPES = [...TIER_NAMES, X]`) are
|
|
32
|
+
* intentionally not extracted — they would yield partial literal sets.
|
|
29
33
|
*
|
|
30
34
|
* Codifies typescript-standards.md § "Zod-Derived Type Guards (MANDATORY)".
|
|
31
35
|
*/
|
|
@@ -45,19 +49,31 @@ function getRegistry() {
|
|
|
45
49
|
return registryCache;
|
|
46
50
|
}
|
|
47
51
|
|
|
52
|
+
// Earlier entries win the name reported for a literal set, so the canonical
|
|
53
|
+
// home of a vocabulary comes first: `@fjall/util` owns the backup tier tuple
|
|
54
|
+
// and the generator re-exports it.
|
|
55
|
+
const REGISTRY_SOURCES = [
|
|
56
|
+
["util", "src", "backupTiers.ts"],
|
|
57
|
+
["generator", "src", "schemas", "constants.ts"],
|
|
58
|
+
["generator", "src", "schemas", "sharedTypes.ts"]
|
|
59
|
+
];
|
|
60
|
+
|
|
48
61
|
function buildRegistry() {
|
|
49
|
-
const
|
|
62
|
+
const monorepoRoot = join(__dirname, "..", "..");
|
|
50
63
|
const registry = new Map();
|
|
64
|
+
const sources = REGISTRY_SOURCES.map((segments) =>
|
|
65
|
+
join(monorepoRoot, ...segments)
|
|
66
|
+
);
|
|
51
67
|
// Source tree absent → published-package context, no-op silently; the warning
|
|
52
|
-
// below is reserved for
|
|
53
|
-
if (!existsSync(
|
|
68
|
+
// below is reserved for a source present but unreadable.
|
|
69
|
+
if (!sources.some((path) => existsSync(path))) return registry;
|
|
54
70
|
|
|
55
|
-
const sources = [
|
|
56
|
-
join(schemasDir, "constants.ts"),
|
|
57
|
-
join(schemasDir, "sharedTypes.ts")
|
|
58
|
-
];
|
|
59
71
|
const failures = [];
|
|
60
72
|
for (const path of sources) {
|
|
73
|
+
if (!existsSync(path)) {
|
|
74
|
+
failures.push({ path, error: "missing" });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
61
77
|
let text;
|
|
62
78
|
try {
|
|
63
79
|
text = readFileSync(path, "utf8");
|