@am_shork/attest 0.1.7 → 0.2.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.
@@ -0,0 +1,255 @@
1
+ // Static registry extraction: `*.reqs.ts` source -> Registry, without running
2
+ // the module (design §5.1, §5.2).
3
+ //
4
+ // Reading a registry used to mean evaluating it, which gave `attest check` the
5
+ // threat model of a test run while advertising itself as static analysis. This
6
+ // reader walks the AST with the compiler API — already the parser layer's tool —
7
+ // pulls the object literal out of `defineRequirements(...)`, and hands *that* to
8
+ // RegistrySchema. The schema is the same one defineRequirements calls, so a
9
+ // literal registry keeps its behaviour, its codes and its wording exactly.
10
+ //
11
+ // A registry that cannot be read this way is an ERROR (`registry-not-static`).
12
+ // There is deliberately no fallback to evaluation: a reader that quietly runs
13
+ // the file when extraction fails guarantees nothing at all. `--eval` is the
14
+ // named way back.
15
+ import ts from 'typescript';
16
+ import { RegistryValidationError } from './registry.js';
17
+ import { RegistrySchema } from './schema.js';
18
+ /** The authoring function a registry file must default-export the result of. */
19
+ const DEFINE = 'defineRequirements';
20
+ /** A value could not be read from the source, and must never be guessed. */
21
+ class NotStatic extends Error {
22
+ node;
23
+ reason;
24
+ constructor(node, reason) {
25
+ super(reason);
26
+ this.node = node;
27
+ this.reason = reason;
28
+ }
29
+ }
30
+ export function readRegistrySource(file, source) {
31
+ const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, /* setParentNodes */ true);
32
+ const lineOf = (node) => sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
33
+ const exported = defaultExportExpression(sf);
34
+ if (!exported) {
35
+ // Same code and wording as the evaluating path: to an author who forgot the
36
+ // export, nothing about the diagnosis has changed.
37
+ return {
38
+ ok: false,
39
+ code: 'registry-no-default',
40
+ message: 'A registry file must default-export the result of defineRequirements(...).',
41
+ };
42
+ }
43
+ const call = defineRequirementsCall(exported, sf);
44
+ if (!call) {
45
+ return {
46
+ ok: false,
47
+ code: 'registry-not-static',
48
+ message: `A registry must be a literal: this file default-exports something other than a direct ${DEFINE}({ … }) call, ` +
49
+ 'so it cannot be read without running it. Inline the registry, or pass --eval to read it by executing the file.',
50
+ line: lineOf(exported),
51
+ };
52
+ }
53
+ let value;
54
+ try {
55
+ value = literalValue(call);
56
+ }
57
+ catch (err) {
58
+ if (!(err instanceof NotStatic))
59
+ throw err;
60
+ return {
61
+ ok: false,
62
+ code: 'registry-not-static',
63
+ message: `A registry must be a literal: ${err.reason} cannot be read without running the file. ` +
64
+ 'Write the value inline, or pass --eval to read the registry by executing the file.',
65
+ line: lineOf(err.node),
66
+ };
67
+ }
68
+ const result = RegistrySchema.safeParse(value);
69
+ if (!result.success) {
70
+ // defineRequirements throws RegistryValidationError and loadRegistry wraps
71
+ // it; going through the same error keeps the message identical rather than
72
+ // merely similar.
73
+ return {
74
+ ok: false,
75
+ code: 'registry-invalid',
76
+ message: `Failed to load registry: ${new RegistryValidationError(result.error.issues).message}`,
77
+ };
78
+ }
79
+ return { ok: true, registry: result.data };
80
+ }
81
+ /**
82
+ * The expression a file default-exports, following one level of local binding.
83
+ *
84
+ * `const reqs = defineRequirements({…}); export default reqs;` is an ordinary
85
+ * way to write a registry file — the binding is const and top-level, so what it
86
+ * names is not in question.
87
+ */
88
+ function defaultExportExpression(sf) {
89
+ for (const statement of sf.statements) {
90
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals)
91
+ continue;
92
+ const expr = unwrap(statement.expression);
93
+ if (!ts.isIdentifier(expr))
94
+ return expr;
95
+ return constInitializer(sf, expr.text) ?? expr;
96
+ }
97
+ return undefined;
98
+ }
99
+ /** The initializer of a top-level `const name = …`, if there is exactly one. */
100
+ function constInitializer(sf, name) {
101
+ for (const statement of sf.statements) {
102
+ if (!ts.isVariableStatement(statement))
103
+ continue;
104
+ if (!(statement.declarationList.flags & ts.NodeFlags.Const))
105
+ continue;
106
+ for (const decl of statement.declarationList.declarations) {
107
+ if (ts.isIdentifier(decl.name) && decl.name.text === name && decl.initializer) {
108
+ return unwrap(decl.initializer);
109
+ }
110
+ }
111
+ }
112
+ return undefined;
113
+ }
114
+ /**
115
+ * The argument of the `defineRequirements(...)` call, if that is what this is.
116
+ *
117
+ * The callee is matched against the local name the import bound — an alias or a
118
+ * namespace import is the same call — rather than against any single-argument
119
+ * call, so `buildRegistry({…})` is not mistaken for a registry.
120
+ */
121
+ function defineRequirementsCall(expr, sf) {
122
+ if (!ts.isCallExpression(expr) || expr.arguments.length !== 1)
123
+ return undefined;
124
+ const callee = expr.expression;
125
+ const named = (ts.isIdentifier(callee) && localDefineNames(sf).has(callee.text)) ||
126
+ (ts.isPropertyAccessExpression(callee) && callee.name.text === DEFINE);
127
+ return named ? expr.arguments[0] : undefined;
128
+ }
129
+ /** Local names bound to the imported `defineRequirements`, including aliases. */
130
+ function localDefineNames(sf) {
131
+ const names = new Set();
132
+ for (const statement of sf.statements) {
133
+ if (!ts.isImportDeclaration(statement))
134
+ continue;
135
+ const bindings = statement.importClause?.namedBindings;
136
+ if (!bindings || !ts.isNamedImports(bindings))
137
+ continue;
138
+ for (const el of bindings.elements) {
139
+ if ((el.propertyName ?? el.name).text === DEFINE)
140
+ names.add(el.name.text);
141
+ }
142
+ }
143
+ // A file that never imported it can still be read: the import may come from a
144
+ // global or a test harness, and the callee name is the only signal we need.
145
+ names.add(DEFINE);
146
+ return names;
147
+ }
148
+ /** Strip the type-level wrappers that do not change the value (`as const`, `satisfies`, parens). */
149
+ function unwrap(node) {
150
+ let current = node;
151
+ for (;;) {
152
+ if (ts.isParenthesizedExpression(current) ||
153
+ ts.isAsExpression(current) ||
154
+ ts.isSatisfiesExpression(current) ||
155
+ ts.isNonNullExpression(current) ||
156
+ ts.isTypeAssertionExpression(current) ||
157
+ ts.isExpressionWithTypeArguments(current)) {
158
+ current = current.expression;
159
+ continue;
160
+ }
161
+ return current;
162
+ }
163
+ }
164
+ /**
165
+ * The value of a literal expression, or a NotStatic naming what stopped it.
166
+ *
167
+ * Every branch is a form whose value is fixed by the source text alone. The
168
+ * traps are the ones that look literal and are not: `-1` is a unary expression,
169
+ * `1_000` and `0x10` are not `Number(node.text)` on the spelling, and a template
170
+ * literal is only a string while it has no substitution.
171
+ */
172
+ function literalValue(node) {
173
+ const expr = unwrap(node);
174
+ if (ts.isStringLiteral(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
175
+ // `.text` is the cooked value: escapes are already resolved.
176
+ return expr.text;
177
+ }
178
+ if (ts.isNumericLiteral(expr))
179
+ return numericValue(expr);
180
+ if (expr.kind === ts.SyntaxKind.TrueKeyword)
181
+ return true;
182
+ if (expr.kind === ts.SyntaxKind.FalseKeyword)
183
+ return false;
184
+ if (ts.isPrefixUnaryExpression(expr)) {
185
+ const operand = unwrap(expr.operand);
186
+ if (ts.isNumericLiteral(operand)) {
187
+ const n = numericValue(operand);
188
+ if (expr.operator === ts.SyntaxKind.MinusToken)
189
+ return -n;
190
+ if (expr.operator === ts.SyntaxKind.PlusToken)
191
+ return n;
192
+ }
193
+ throw new NotStatic(expr, 'a unary expression over something other than a number');
194
+ }
195
+ if (ts.isArrayLiteralExpression(expr)) {
196
+ return expr.elements.map((el) => {
197
+ if (ts.isSpreadElement(el))
198
+ throw new NotStatic(el, 'a spread element');
199
+ if (ts.isOmittedExpression(el))
200
+ throw new NotStatic(el, 'an array hole');
201
+ return literalValue(el);
202
+ });
203
+ }
204
+ if (ts.isObjectLiteralExpression(expr))
205
+ return objectValue(expr);
206
+ throw new NotStatic(expr, `a ${ts.SyntaxKind[expr.kind]}`);
207
+ }
208
+ function objectValue(expr) {
209
+ // Built without a prototype so a key from the source can never reach one:
210
+ // extraction assigns whatever the file wrote, and `Object.prototype` is not
211
+ // a place for it to land.
212
+ const out = Object.create(null);
213
+ for (const prop of expr.properties) {
214
+ if (!ts.isPropertyAssignment(prop)) {
215
+ throw new NotStatic(prop, ts.isShorthandPropertyAssignment(prop)
216
+ ? 'a shorthand property'
217
+ : ts.isSpreadAssignment(prop)
218
+ ? 'a spread'
219
+ : 'a method or accessor');
220
+ }
221
+ const key = propertyName(prop.name);
222
+ // `{'__proto__': …}` does not create a key, it swaps the prototype — and
223
+ // what the evaluator then makes of the registry is a matter of how the
224
+ // schema happens to enumerate. There is no literal value here to read, and
225
+ // imitating the prototype game is not this reader's business: refuse, so a
226
+ // file the evaluator also rejects stays rejected.
227
+ if (key === '__proto__')
228
+ throw new NotStatic(prop, 'a __proto__ key');
229
+ out[key] = literalValue(prop.initializer);
230
+ }
231
+ return out;
232
+ }
233
+ function propertyName(name) {
234
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNoSubstitutionTemplateLiteral(name)) {
235
+ return name.text;
236
+ }
237
+ if (ts.isNumericLiteral(name))
238
+ return String(numericValue(name));
239
+ throw new NotStatic(name, 'a computed key');
240
+ }
241
+ /**
242
+ * The value of a numeric literal, read from its source spelling.
243
+ *
244
+ * The spelling is used rather than the scanner's `.text` because `Number` is
245
+ * the one thing that already agrees with the evaluator on every base, on
246
+ * exponents and on `30.0`; only the numeric separators have to be removed
247
+ * first, since `Number('1_000')` is NaN.
248
+ */
249
+ function numericValue(node) {
250
+ const value = Number(node.getText().replace(/_/g, ''));
251
+ if (Number.isNaN(value))
252
+ throw new NotStatic(node, 'a number this reader cannot spell out');
253
+ return value;
254
+ }
255
+ //# sourceMappingURL=static-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-registry.js","sourceRoot":"","sources":["../../src/core/static-registry.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,9 @@ import type { AttestPlan, Issue, ParamRef, Registry } from './types.js';
4
4
  * - orphan-test: a scenario covers an unknown requirement id
5
5
  * - uncovered-requirement: a requirement has no scenario
6
6
  * - unbound-param: a statement placeholder has no matching param
7
+ *
8
+ * and one WARNING:
9
+ * - rationale-placeholder: a `{name}` in a rationale, which is never interpolated
7
10
  */
8
11
  export declare function validateStructure(registry: Registry, plan: AttestPlan): Issue[];
9
12
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAkB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,CAkD/E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,QAAQ,EAAE,GACf,KAAK,EAAE,CA+BT"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAkB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,CA0E/E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,QAAQ,EAAE,GACf,KAAK,EAAE,CA+BT"}
@@ -5,6 +5,9 @@
5
5
  * - orphan-test: a scenario covers an unknown requirement id
6
6
  * - uncovered-requirement: a requirement has no scenario
7
7
  * - unbound-param: a statement placeholder has no matching param
8
+ *
9
+ * and one WARNING:
10
+ * - rationale-placeholder: a `{name}` in a rationale, which is never interpolated
8
11
  */
9
12
  export function validateStructure(registry, plan) {
10
13
  const issues = [];
@@ -51,6 +54,29 @@ export function validateStructure(registry, plan) {
51
54
  }
52
55
  }
53
56
  }
57
+ // rationale-placeholder: `{name}` written in a rationale, which render does
58
+ // not interpolate (it substitutes into the statement and nothing else). Both
59
+ // spellings are reported, and the declared one is the reason this is not an
60
+ // extension of unbound-param: an author who declares `maxAttempts` and then
61
+ // writes it into the rationale has made no binding mistake at all, yet the
62
+ // braces still reach the document reviewers and audit read. Fixing render to
63
+ // interpolate here would change the bytes of every existing rendering, so
64
+ // this reports instead. WARNING, deliberately below `hasError`: an existing
65
+ // green registry gains a line of output and keeps its exit code.
66
+ for (const [id, req] of Object.entries(registry)) {
67
+ // Code spans are dropped first: a rationale is rendered as Markdown, so a
68
+ // backticked `{toString}` is a quoted token, not a placeholder its author
69
+ // misfiled — and render leaves a code span exactly as written. Attest's own
70
+ // ATX-14 is that case, which is how this exclusion was found.
71
+ for (const m of req.rationale.replace(/`[^`]*`/g, ' ').matchAll(/\{(\w+)\}/g)) {
72
+ issues.push({
73
+ level: 'WARNING',
74
+ code: 'rationale-placeholder',
75
+ reqId: id,
76
+ message: `Requirement "${id}" writes {${m[1]}} in its rationale, but only the statement is interpolated — the braces reach the rendering verbatim. Move the placeholder into the statement, or write the value out as prose.`,
77
+ });
78
+ }
79
+ }
54
80
  return issues;
55
81
  }
56
82
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { requirement, scenario } from './runtime.js';
2
2
  export { defineRequirements, delta } from './core/registry.js';
3
- export type { RegistryDelta } from './core/registry.js';
3
+ export type { RegistryDelta, DefinedRegistry } from './core/registry.js';
4
4
  export type { Requirement, Registry, ParsedScenario, AttestPlan, Level, Issue, } from './core/types.js';
5
5
  export type { JsonReport, JsonSummary, JsonCommand } from './cli/json.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EACd,UAAU,EACV,KAAK,EACL,KAAK,GACN,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EACd,UAAU,EACV,KAAK,EACL,KAAK,GACN,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@am_shork/attest",
3
- "version": "0.1.7",
3
+ "version": "0.2.1",
4
4
  "description": "TDD-native spec framework: tests are the source of truth for verification, ID-bound requirements the source of truth for intent.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -64,6 +64,7 @@
64
64
  "scripts": {
65
65
  "build": "tsc -p tsconfig.json",
66
66
  "typecheck": "tsc -p tsconfig.json --noEmit",
67
+ "typecheck:all": "tsc -p tsconfig.typecheck.json",
67
68
  "test": "vitest run",
68
69
  "test:watch": "vitest",
69
70
  "test:consumer": "pnpm run build && vitest run --config vitest.consumer.config.ts",