candor-ts 0.14.0 → 0.14.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/scan.mjs +25 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "candor-ts",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "candor for TypeScript — per-function side effects, transitively, with a policy gate (candor-spec 0.14)",
5
5
  "type": "module",
6
6
  "dependencies": {
package/scan.mjs CHANGED
@@ -1114,9 +1114,34 @@ function moduleUnit(sf) {
1114
1114
  }
1115
1115
  return qual;
1116
1116
  }
1117
+ // The synthesized static-initializer unit for a `class C { static { … } }` block (spec §2 unitKind
1118
+ // "initializer"). A static block runs at class-DEFINITION time, not instance construction — but its
1119
+ // body's effects otherwise walked up in `enclosing` to the ClassDeclaration, which maps to the
1120
+ // `C.constructor` unit, so a static-init effect was MISLABELED as the instance ctor (and carried no
1121
+ // unitKind). Mint it as its own unit, lazily, mirroring `moduleUnit`. (An anonymous class expression's
1122
+ // static block keys under `<anonymous>`; there is at most one static-init unit per class name.)
1123
+ function staticBlockUnit(node) {
1124
+ const cls = node.parent;
1125
+ const sf = node.getSourceFile();
1126
+ const mod = moduleOf(sf);
1127
+ const cname = (ts.isClassDeclaration(cls) || ts.isClassExpression(cls)) && cls.name ? cls.name.text : "<anonymous>";
1128
+ const qual = `${mod}.${cname}.<static-init>`;
1129
+ let rec = fns.get(qual);
1130
+ if (!rec) {
1131
+ rec = { local: "<static-init>", direct: new Set(), edges: new Set(), hosts: new Set(), tables: new Set(),
1132
+ cmds: new Set(), paths: new Set(), blind: new Set(), incomplete: new Set(), why: new Set(),
1133
+ entry: false, unitKind: "initializer",
1134
+ loc: `${path.relative(rootDir, sf.fileName)}:${sf.getLineAndCharacterOfPosition(node.getStart()).line + 1}:1` };
1135
+ fns.set(qual, rec);
1136
+ }
1137
+ return qual;
1138
+ }
1117
1139
  // nearest enclosing analyzed function (closures attribute to it — SEMANTICS §2)
1118
1140
  function enclosing(node) {
1119
1141
  for (let p = node; p; p = p.parent) {
1142
+ // A `static { … }` block is its own initializer unit (class-definition time), NOT the instance ctor
1143
+ // the ClassDeclaration maps to — intercept before the nodeName lookup would fold it into .constructor.
1144
+ if (ts.isClassStaticBlockDeclaration(p)) return staticBlockUnit(p);
1120
1145
  // A call/effect lexically inside a DECORATOR (`@factory(arg)`) runs at class-DEFINITION time, NOT in
1121
1146
  // the decorated declaration's body. The parent chain of a decorator's expression is
1122
1147
  // CallExpression → Decorator → MethodDeclaration/ClassDeclaration/Parameter, so `enclosing` otherwise