@aid-framework/generator-sdk 0.0.0 → 0.1.48
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 +201 -0
- package/README.md +221 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/aid-manifest.d.ts +71 -0
- package/dist/aid-manifest.d.ts.map +1 -0
- package/dist/aid-manifest.js +233 -0
- package/dist/aid-manifest.js.map +1 -0
- package/dist/determinism.d.ts +76 -0
- package/dist/determinism.d.ts.map +1 -0
- package/dist/determinism.js +142 -0
- package/dist/determinism.js.map +1 -0
- package/dist/diagnostics.d.ts +49 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +59 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/drift.d.ts +114 -0
- package/dist/drift.d.ts.map +1 -0
- package/dist/drift.js +259 -0
- package/dist/drift.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +100 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +357 -0
- package/dist/manifest.js.map +1 -0
- package/dist/node-sink.d.ts +17 -0
- package/dist/node-sink.d.ts.map +1 -0
- package/dist/node-sink.js +62 -0
- package/dist/node-sink.js.map +1 -0
- package/dist/ownership.d.ts +50 -0
- package/dist/ownership.d.ts.map +1 -0
- package/dist/ownership.js +90 -0
- package/dist/ownership.js.map +1 -0
- package/dist/plan.d.ts +51 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +132 -0
- package/dist/plan.js.map +1 -0
- package/dist/semver.d.ts +46 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +264 -0
- package/dist/semver.js.map +1 -0
- package/dist/targets.d.ts +44 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +88 -0
- package/dist/targets.js.map +1 -0
- package/package.json +43 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aid-manifest.js","sourceRoot":"","sources":["../src/aid-manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The determinism contract (§8.2): the primitives a generator uses to emit
|
|
3
|
+
* byte-identical output, plus the checker that proves it did.
|
|
4
|
+
*
|
|
5
|
+
* The contract is narrow and absolute — no timestamps, no host names, no absolute
|
|
6
|
+
* paths, no randomness — because the golden-file tests (§12 regime A) compare bytes
|
|
7
|
+
* and a single timestamp turns every regeneration into a diff. `scanForNonDeterminism`
|
|
8
|
+
* is what makes the contract testable instead of aspirational: a generator's own
|
|
9
|
+
* tests run the emitted set through it, and a violation fails the build.
|
|
10
|
+
*
|
|
11
|
+
* The contract applies to *generated code*, never to model output (§8.2).
|
|
12
|
+
*/
|
|
13
|
+
import type { GeneratedFile } from './plan.js';
|
|
14
|
+
export declare const GENERATED_BANNER_MARKER = "Code generated by AID Framework";
|
|
15
|
+
export interface BannerOptions {
|
|
16
|
+
generator: string;
|
|
17
|
+
version: string;
|
|
18
|
+
/** Line-comment prefix for the target language. */
|
|
19
|
+
comment?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The banner every generated file carries. It deliberately names the generator and
|
|
23
|
+
* version but never a time: `aid doctor` compares the version, and a timestamp would
|
|
24
|
+
* make every regeneration a spurious diff.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generatedBanner(options: BannerOptions): string;
|
|
27
|
+
export declare function normalizeNewlines(text: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Exactly one trailing newline, and no trailing blank lines.
|
|
30
|
+
*
|
|
31
|
+
* The run is stripped with a loop rather than `/\n+$/`, which backtracks from every
|
|
32
|
+
* start position when the run is not at the end of the string and is quadratic there.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureTrailingNewline(text: string): string;
|
|
35
|
+
/** Canonical text: LF endings, no trailing blank lines, exactly one trailing newline. */
|
|
36
|
+
export declare function normalizeText(text: string): string;
|
|
37
|
+
export declare function sha256Hex(text: string): string;
|
|
38
|
+
export declare function compareIds(left: string, right: string): number;
|
|
39
|
+
/** Stable ordering by a string key. Ties keep their input order. */
|
|
40
|
+
export declare function stableSortBy<T>(items: readonly T[], key: (item: T) => string): T[];
|
|
41
|
+
/** Orders IR-named nodes by their stable `id`, so output never depends on input order. */
|
|
42
|
+
export declare function sortById<T extends {
|
|
43
|
+
id: string;
|
|
44
|
+
}>(items: readonly T[]): T[];
|
|
45
|
+
export declare function sortByPath<T extends {
|
|
46
|
+
path: string;
|
|
47
|
+
}>(items: readonly T[]): T[];
|
|
48
|
+
/**
|
|
49
|
+
* A derived identifier for content that needs a stable suffix. Hashing keeps it
|
|
50
|
+
* deterministic, which `Math.random()`/UUID would not.
|
|
51
|
+
*/
|
|
52
|
+
export declare function stableId(namespace: string, value: string): string;
|
|
53
|
+
export interface DeterminismPattern {
|
|
54
|
+
id: string;
|
|
55
|
+
reason: string;
|
|
56
|
+
pattern: RegExp;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The forbidden shapes, as text patterns. This is a text-level lint, so it can only
|
|
60
|
+
* catch what is visible in the emitted bytes; it is deliberately blunt because a
|
|
61
|
+
* false positive is cheap (the generator drops the value) and a false negative is a
|
|
62
|
+
* permanently churning golden file.
|
|
63
|
+
*/
|
|
64
|
+
export declare const DETERMINISM_PATTERNS: readonly DeterminismPattern[];
|
|
65
|
+
export interface DeterminismViolation {
|
|
66
|
+
path: string;
|
|
67
|
+
pattern: string;
|
|
68
|
+
reason: string;
|
|
69
|
+
line: number;
|
|
70
|
+
text: string;
|
|
71
|
+
}
|
|
72
|
+
/** Reports every non-deterministic shape in one emitted file, in line order. */
|
|
73
|
+
export declare function scanForNonDeterminism(path: string, content: string): DeterminismViolation[];
|
|
74
|
+
/** Reports every non-deterministic shape across a whole emitted set, ordered by path. */
|
|
75
|
+
export declare function checkDeterminism(files: readonly GeneratedFile[]): DeterminismViolation[];
|
|
76
|
+
//# sourceMappingURL=determinism.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinism.d.ts","sourceRoot":"","sources":["../src/determinism.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAM9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAQlF;AAED,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAE3E;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAE/E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,kBAAkB,EAoC7D,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAiB3F;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,oBAAoB,EAAE,CAExF"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The determinism contract (§8.2): the primitives a generator uses to emit
|
|
3
|
+
* byte-identical output, plus the checker that proves it did.
|
|
4
|
+
*
|
|
5
|
+
* The contract is narrow and absolute — no timestamps, no host names, no absolute
|
|
6
|
+
* paths, no randomness — because the golden-file tests (§12 regime A) compare bytes
|
|
7
|
+
* and a single timestamp turns every regeneration into a diff. `scanForNonDeterminism`
|
|
8
|
+
* is what makes the contract testable instead of aspirational: a generator's own
|
|
9
|
+
* tests run the emitted set through it, and a violation fails the build.
|
|
10
|
+
*
|
|
11
|
+
* The contract applies to *generated code*, never to model output (§8.2).
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
export const GENERATED_BANNER_MARKER = 'Code generated by AID Framework';
|
|
15
|
+
/**
|
|
16
|
+
* The banner every generated file carries. It deliberately names the generator and
|
|
17
|
+
* version but never a time: `aid doctor` compares the version, and a timestamp would
|
|
18
|
+
* make every regeneration a spurious diff.
|
|
19
|
+
*/
|
|
20
|
+
export function generatedBanner(options) {
|
|
21
|
+
const comment = options.comment ?? '//';
|
|
22
|
+
return [
|
|
23
|
+
`${comment} ${GENERATED_BANNER_MARKER} "${options.generator}" v${options.version}. DO NOT EDIT.`,
|
|
24
|
+
`${comment} Owned by the generator: regenerate with \`aid gen\`. See aid.manifest.json.`,
|
|
25
|
+
].join('\n');
|
|
26
|
+
}
|
|
27
|
+
export function normalizeNewlines(text) {
|
|
28
|
+
return text.replace(/\r\n?/g, '\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Exactly one trailing newline, and no trailing blank lines.
|
|
32
|
+
*
|
|
33
|
+
* The run is stripped with a loop rather than `/\n+$/`, which backtracks from every
|
|
34
|
+
* start position when the run is not at the end of the string and is quadratic there.
|
|
35
|
+
*/
|
|
36
|
+
export function ensureTrailingNewline(text) {
|
|
37
|
+
let end = text.length;
|
|
38
|
+
while (end > 0 && text[end - 1] === '\n')
|
|
39
|
+
end--;
|
|
40
|
+
return `${text.slice(0, end)}\n`;
|
|
41
|
+
}
|
|
42
|
+
/** Canonical text: LF endings, no trailing blank lines, exactly one trailing newline. */
|
|
43
|
+
export function normalizeText(text) {
|
|
44
|
+
return ensureTrailingNewline(normalizeNewlines(text));
|
|
45
|
+
}
|
|
46
|
+
export function sha256Hex(text) {
|
|
47
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
48
|
+
}
|
|
49
|
+
export function compareIds(left, right) {
|
|
50
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
51
|
+
}
|
|
52
|
+
/** Stable ordering by a string key. Ties keep their input order. */
|
|
53
|
+
export function stableSortBy(items, key) {
|
|
54
|
+
return items
|
|
55
|
+
.map((item, index) => ({ item, index }))
|
|
56
|
+
.sort((left, right) => {
|
|
57
|
+
const order = compareIds(key(left.item), key(right.item));
|
|
58
|
+
return order === 0 ? left.index - right.index : order;
|
|
59
|
+
})
|
|
60
|
+
.map((entry) => entry.item);
|
|
61
|
+
}
|
|
62
|
+
/** Orders IR-named nodes by their stable `id`, so output never depends on input order. */
|
|
63
|
+
export function sortById(items) {
|
|
64
|
+
return stableSortBy(items, (item) => item.id);
|
|
65
|
+
}
|
|
66
|
+
export function sortByPath(items) {
|
|
67
|
+
return stableSortBy(items, (item) => item.path);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A derived identifier for content that needs a stable suffix. Hashing keeps it
|
|
71
|
+
* deterministic, which `Math.random()`/UUID would not.
|
|
72
|
+
*/
|
|
73
|
+
export function stableId(namespace, value) {
|
|
74
|
+
return `${namespace}-${sha256Hex(value).slice(0, 12)}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The forbidden shapes, as text patterns. This is a text-level lint, so it can only
|
|
78
|
+
* catch what is visible in the emitted bytes; it is deliberately blunt because a
|
|
79
|
+
* false positive is cheap (the generator drops the value) and a false negative is a
|
|
80
|
+
* permanently churning golden file.
|
|
81
|
+
*/
|
|
82
|
+
export const DETERMINISM_PATTERNS = [
|
|
83
|
+
{
|
|
84
|
+
id: 'absolute-path-windows',
|
|
85
|
+
reason: 'an absolute Windows path leaks the generating machine',
|
|
86
|
+
pattern: /[A-Za-z]:[\\/]/,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'absolute-path-unix',
|
|
90
|
+
reason: 'an absolute Unix path leaks the generating machine',
|
|
91
|
+
pattern: /(?:^|[^A-Za-z0-9_.])\/(?:home|Users|tmp|var)\//,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'host-directory',
|
|
95
|
+
reason: 'a host-specific directory leaks the generating machine',
|
|
96
|
+
pattern: /AppData[\\/]|[/\\]\.venv[/\\]/,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'timestamp',
|
|
100
|
+
reason: 'a timestamp makes every regeneration a diff',
|
|
101
|
+
pattern: /\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}/,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'generated-at-phrase',
|
|
105
|
+
reason: 'a generation date makes every regeneration a diff',
|
|
106
|
+
pattern: /\bgenerated\s+(?:on|at)\b/i,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'hostname',
|
|
110
|
+
reason: 'a host name leaks the generating machine',
|
|
111
|
+
pattern: /\bhostname\s*[:=]/i,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: 'runtime-randomness',
|
|
115
|
+
reason: 'generation-time randomness cannot be reproduced',
|
|
116
|
+
pattern: /\b(?:Math\.random|crypto\.randomUUID|uuid4\()/,
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
/** Reports every non-deterministic shape in one emitted file, in line order. */
|
|
120
|
+
export function scanForNonDeterminism(path, content) {
|
|
121
|
+
const violations = [];
|
|
122
|
+
const lines = content.split('\n');
|
|
123
|
+
for (const [index, line] of lines.entries()) {
|
|
124
|
+
for (const candidate of DETERMINISM_PATTERNS) {
|
|
125
|
+
if (!candidate.pattern.test(line))
|
|
126
|
+
continue;
|
|
127
|
+
violations.push({
|
|
128
|
+
path,
|
|
129
|
+
pattern: candidate.id,
|
|
130
|
+
reason: candidate.reason,
|
|
131
|
+
line: index + 1,
|
|
132
|
+
text: line.trim(),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return violations;
|
|
137
|
+
}
|
|
138
|
+
/** Reports every non-deterministic shape across a whole emitted set, ordered by path. */
|
|
139
|
+
export function checkDeterminism(files) {
|
|
140
|
+
return sortByPath(files).flatMap((file) => scanForNonDeterminism(file.path, file.content));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=determinism.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinism.js","sourceRoot":"","sources":["../src/determinism.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics for the generator layer. Reuses `@aid-framework/spec`'s `Diagnostic` shape so the
|
|
3
|
+
* parser, the IR gates, and this layer print one report, while this layer keeps its own
|
|
4
|
+
* closed code union (`generator/*`) for typo checking. Codes are part of the public
|
|
5
|
+
* contract; renaming one is a breaking change.
|
|
6
|
+
*
|
|
7
|
+
* `@aid-framework/spec` locates a diagnostic by a path *inside* a document. This layer's failures
|
|
8
|
+
* are mostly about a whole file — a drifted `generated/` file, an unplanned path — so the
|
|
9
|
+
* helpers here take a flat string: either a repo-relative file path or a dotted location
|
|
10
|
+
* such as `output.generatedDir`. It is passed through as a single path segment, which
|
|
11
|
+
* renders identically and keeps this layer from inventing index arithmetic it does not have.
|
|
12
|
+
*/
|
|
13
|
+
import type { Diagnostic } from '@aid-framework/spec';
|
|
14
|
+
export declare const GENERATOR_DIAGNOSTIC_CODES: {
|
|
15
|
+
readonly manifestNotAMapping: 'generator/manifest-not-a-mapping';
|
|
16
|
+
readonly manifestMissingField: 'generator/manifest-missing-field';
|
|
17
|
+
readonly manifestInvalidField: 'generator/manifest-invalid-field';
|
|
18
|
+
readonly manifestUnknownKey: 'generator/manifest-unknown-key';
|
|
19
|
+
readonly manifestCapabilityUnknown: 'generator/manifest-capability-unknown';
|
|
20
|
+
readonly manifestCapabilityDuplicate: 'generator/manifest-capability-duplicate';
|
|
21
|
+
readonly manifestEmitsAgainstUnknown: 'generator/manifest-emits-against-unknown';
|
|
22
|
+
readonly manifestUnsupportedIr: 'generator/manifest-unsupported-ir';
|
|
23
|
+
readonly manifestNotRelative: 'generator/manifest-not-relative';
|
|
24
|
+
readonly manifestEscapingRoot: 'generator/manifest-escaping-root';
|
|
25
|
+
readonly manifestDuplicateGenerator: 'generator/manifest-duplicate-generator';
|
|
26
|
+
readonly planNotAMapping: 'generator/plan-not-a-mapping';
|
|
27
|
+
readonly planInvalidPath: 'generator/plan-invalid-path';
|
|
28
|
+
readonly planDuplicatePath: 'generator/plan-duplicate-path';
|
|
29
|
+
readonly planOwnerMismatch: 'generator/plan-owner-mismatch';
|
|
30
|
+
readonly planEmpty: 'generator/plan-empty';
|
|
31
|
+
readonly manifestParseFailed: 'generator/manifest-parse-failed';
|
|
32
|
+
readonly manifestVersionUnsupported: 'generator/manifest-version-unsupported';
|
|
33
|
+
readonly determinismViolation: 'generator/determinism-violation';
|
|
34
|
+
readonly generatedDrift: 'generator/generated-drift';
|
|
35
|
+
};
|
|
36
|
+
export type GeneratorDiagnosticCode = (typeof GENERATOR_DIAGNOSTIC_CODES)[keyof typeof GENERATOR_DIAGNOSTIC_CODES];
|
|
37
|
+
export type GeneratorDiagnostic = Diagnostic<GeneratorDiagnosticCode>;
|
|
38
|
+
export interface GeneratorDiagnosticInit {
|
|
39
|
+
code: GeneratorDiagnosticCode;
|
|
40
|
+
message: string;
|
|
41
|
+
/** A repo-relative file path, or a dotted location such as `output.root`. */
|
|
42
|
+
path?: string;
|
|
43
|
+
hint?: string;
|
|
44
|
+
}
|
|
45
|
+
export declare function generatorError(init: GeneratorDiagnosticInit): GeneratorDiagnostic;
|
|
46
|
+
export declare function generatorWarning(init: GeneratorDiagnosticInit): GeneratorDiagnostic;
|
|
47
|
+
/** Binds the generated app's spec file into every diagnostic a generator emits. */
|
|
48
|
+
export declare function withFile(diagnostic: GeneratorDiagnostic, file: string | undefined): GeneratorDiagnostic;
|
|
49
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,eAAO,MAAM,0BAA0B;aACrC,mBAAmB,EAAE,kCAAkC;aACvD,oBAAoB,EAAE,kCAAkC;aACxD,oBAAoB,EAAE,kCAAkC;aACxD,kBAAkB,EAAE,gCAAgC;aACpD,yBAAyB,EAAE,uCAAuC;aAClE,2BAA2B,EAAE,yCAAyC;aACtE,2BAA2B,EAAE,0CAA0C;aACvE,qBAAqB,EAAE,mCAAmC;aAC1D,mBAAmB,EAAE,iCAAiC;aACtD,oBAAoB,EAAE,kCAAkC;aACxD,0BAA0B,EAAE,wCAAwC;aACpE,eAAe,EAAE,8BAA8B;aAC/C,eAAe,EAAE,6BAA6B;aAC9C,iBAAiB,EAAE,+BAA+B;aAClD,iBAAiB,EAAE,+BAA+B;aAClD,SAAS,EAAE,sBAAsB;aACjC,mBAAmB,EAAE,iCAAiC;aACtD,0BAA0B,EAAE,wCAAwC;aACpE,oBAAoB,EAAE,iCAAiC;aACvD,cAAc,EAAE,2BAA2B;CACnC,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,OAAO,0BAA0B,CAAC,CAAC;AAE/E,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,uBAAuB,CAAC,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,cAAc,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAOjF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAOnF;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CACtB,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,mBAAmB,CAErB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics for the generator layer. Reuses `@aid-framework/spec`'s `Diagnostic` shape so the
|
|
3
|
+
* parser, the IR gates, and this layer print one report, while this layer keeps its own
|
|
4
|
+
* closed code union (`generator/*`) for typo checking. Codes are part of the public
|
|
5
|
+
* contract; renaming one is a breaking change.
|
|
6
|
+
*
|
|
7
|
+
* `@aid-framework/spec` locates a diagnostic by a path *inside* a document. This layer's failures
|
|
8
|
+
* are mostly about a whole file — a drifted `generated/` file, an unplanned path — so the
|
|
9
|
+
* helpers here take a flat string: either a repo-relative file path or a dotted location
|
|
10
|
+
* such as `output.generatedDir`. It is passed through as a single path segment, which
|
|
11
|
+
* renders identically and keeps this layer from inventing index arithmetic it does not have.
|
|
12
|
+
*/
|
|
13
|
+
import { errorDiagnostic, warningDiagnostic } from '@aid-framework/spec';
|
|
14
|
+
export const GENERATOR_DIAGNOSTIC_CODES = {
|
|
15
|
+
manifestNotAMapping: 'generator/manifest-not-a-mapping',
|
|
16
|
+
manifestMissingField: 'generator/manifest-missing-field',
|
|
17
|
+
manifestInvalidField: 'generator/manifest-invalid-field',
|
|
18
|
+
manifestUnknownKey: 'generator/manifest-unknown-key',
|
|
19
|
+
manifestCapabilityUnknown: 'generator/manifest-capability-unknown',
|
|
20
|
+
manifestCapabilityDuplicate: 'generator/manifest-capability-duplicate',
|
|
21
|
+
manifestEmitsAgainstUnknown: 'generator/manifest-emits-against-unknown',
|
|
22
|
+
manifestUnsupportedIr: 'generator/manifest-unsupported-ir',
|
|
23
|
+
manifestNotRelative: 'generator/manifest-not-relative',
|
|
24
|
+
manifestEscapingRoot: 'generator/manifest-escaping-root',
|
|
25
|
+
manifestDuplicateGenerator: 'generator/manifest-duplicate-generator',
|
|
26
|
+
planNotAMapping: 'generator/plan-not-a-mapping',
|
|
27
|
+
planInvalidPath: 'generator/plan-invalid-path',
|
|
28
|
+
planDuplicatePath: 'generator/plan-duplicate-path',
|
|
29
|
+
planOwnerMismatch: 'generator/plan-owner-mismatch',
|
|
30
|
+
planEmpty: 'generator/plan-empty',
|
|
31
|
+
manifestParseFailed: 'generator/manifest-parse-failed',
|
|
32
|
+
manifestVersionUnsupported: 'generator/manifest-version-unsupported',
|
|
33
|
+
determinismViolation: 'generator/determinism-violation',
|
|
34
|
+
generatedDrift: 'generator/generated-drift',
|
|
35
|
+
};
|
|
36
|
+
function toDiagnosticPath(path) {
|
|
37
|
+
return path === undefined || path === '' ? [] : [path];
|
|
38
|
+
}
|
|
39
|
+
export function generatorError(init) {
|
|
40
|
+
return errorDiagnostic({
|
|
41
|
+
code: init.code,
|
|
42
|
+
message: init.message,
|
|
43
|
+
path: toDiagnosticPath(init.path),
|
|
44
|
+
...(init.hint === undefined ? {} : { hint: init.hint }),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function generatorWarning(init) {
|
|
48
|
+
return warningDiagnostic({
|
|
49
|
+
code: init.code,
|
|
50
|
+
message: init.message,
|
|
51
|
+
path: toDiagnosticPath(init.path),
|
|
52
|
+
...(init.hint === undefined ? {} : { hint: init.hint }),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** Binds the generated app's spec file into every diagnostic a generator emits. */
|
|
56
|
+
export function withFile(diagnostic, file) {
|
|
57
|
+
return file === undefined ? diagnostic : { ...diagnostic, file };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEzE,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,mBAAmB,EAAE,kCAAkC;IACvD,oBAAoB,EAAE,kCAAkC;IACxD,oBAAoB,EAAE,kCAAkC;IACxD,kBAAkB,EAAE,gCAAgC;IACpD,yBAAyB,EAAE,uCAAuC;IAClE,2BAA2B,EAAE,yCAAyC;IACtE,2BAA2B,EAAE,0CAA0C;IACvE,qBAAqB,EAAE,mCAAmC;IAC1D,mBAAmB,EAAE,iCAAiC;IACtD,oBAAoB,EAAE,kCAAkC;IACxD,0BAA0B,EAAE,wCAAwC;IACpE,eAAe,EAAE,8BAA8B;IAC/C,eAAe,EAAE,6BAA6B;IAC9C,iBAAiB,EAAE,+BAA+B;IAClD,iBAAiB,EAAE,+BAA+B;IAClD,SAAS,EAAE,sBAAsB;IACjC,mBAAmB,EAAE,iCAAiC;IACtD,0BAA0B,EAAE,wCAAwC;IACpE,oBAAoB,EAAE,iCAAiC;IACvD,cAAc,EAAE,2BAA2B;CACnC,CAAC;AAeX,SAAS,gBAAgB,CAAC,IAAwB;IAChD,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAA6B;IAC1D,OAAO,eAAe,CAAC;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;KACxD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAA6B;IAC5D,OAAO,iBAAiB,CAAC;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;KACxD,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,QAAQ,CACtB,UAA+B,EAC/B,IAAwB;IAExB,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE,CAAC;AACnE,CAAC"}
|
package/dist/drift.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regeneration and drift (§10). This is the algorithm the whole ownership model exists
|
|
3
|
+
* to support, so it is stated once, here, in terms of a plan, the previous manifest, and
|
|
4
|
+
* a byte-level view of the tree:
|
|
5
|
+
*
|
|
6
|
+
* 1. Plan the new file set (already done; see {@link Plan}).
|
|
7
|
+
* 2. For each planned `generated/` file: if it exists on disk and its hash is not the
|
|
8
|
+
* one recorded in the manifest, a human edited generated code. Do not overwrite it.
|
|
9
|
+
* Write the new content to `<path>.aid-rej` and fail with guidance.
|
|
10
|
+
* 3. For each planned `business/` file: create only if missing. Never overwrite.
|
|
11
|
+
* 4. Write atomically; update the manifest.
|
|
12
|
+
* 5. Report created / updated / unchanged / conflicts.
|
|
13
|
+
*
|
|
14
|
+
* The rule that makes this worth having is step 2. A generator that overwrites
|
|
15
|
+
* `generated/` unconditionally destroys the one signal it has that a human disagreed
|
|
16
|
+
* with it, and the loss is silent. Refusing, keeping the rejected bytes alongside the
|
|
17
|
+
* file, and naming the two escapes (`aid eject <path>` to take ownership, `--force` to
|
|
18
|
+
* discard the edits) turns a silent data loss into a decision.
|
|
19
|
+
*
|
|
20
|
+
* Two limits are deliberate. A planned file that is *newer* than the manifest but has no
|
|
21
|
+
* record at all is treated as drift, not as a file to adopt — an unrecorded file under
|
|
22
|
+
* `generated/` cannot be proven unmodified. And stale generated files (recorded, but no
|
|
23
|
+
* longer planned) are reported but not deleted unless `prune` is requested explicitly,
|
|
24
|
+
* because deletion is the one operation with no recovery.
|
|
25
|
+
*/
|
|
26
|
+
import { type AidManifest, type AidManifestProvenance } from './aid-manifest.js';
|
|
27
|
+
import { type GeneratorDiagnostic } from './diagnostics.js';
|
|
28
|
+
import { type FileOwner } from './ownership.js';
|
|
29
|
+
import type { GeneratedFile, Plan } from './plan.js';
|
|
30
|
+
/** The byte-level view of the tree. Tests pass an in-memory map; real runs use the filesystem. */
|
|
31
|
+
export interface RegenerationSink {
|
|
32
|
+
read(path: string): string | undefined;
|
|
33
|
+
write(path: string, content: string): void;
|
|
34
|
+
remove(path: string): void;
|
|
35
|
+
}
|
|
36
|
+
export interface DriftedFile {
|
|
37
|
+
path: string;
|
|
38
|
+
/** The hash the last generation recorded; absent when the file was never recorded. */
|
|
39
|
+
recordedSha256?: string;
|
|
40
|
+
actualSha256: string;
|
|
41
|
+
}
|
|
42
|
+
export type RegenerationAction = {
|
|
43
|
+
kind: 'create';
|
|
44
|
+
path: string;
|
|
45
|
+
owner: FileOwner;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'update';
|
|
48
|
+
path: string;
|
|
49
|
+
owner: FileOwner;
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'unchanged';
|
|
52
|
+
path: string;
|
|
53
|
+
owner: FileOwner;
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'keep-business';
|
|
56
|
+
path: string;
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'drift';
|
|
59
|
+
path: string;
|
|
60
|
+
recordedSha256?: string;
|
|
61
|
+
actualSha256: string;
|
|
62
|
+
};
|
|
63
|
+
export interface RegenerationReport {
|
|
64
|
+
actions: readonly RegenerationAction[];
|
|
65
|
+
created: string[];
|
|
66
|
+
updated: string[];
|
|
67
|
+
unchanged: string[];
|
|
68
|
+
/** Business files that already existed and were left exactly as they were. */
|
|
69
|
+
kept: string[];
|
|
70
|
+
drifted: DriftedFile[];
|
|
71
|
+
/** Recorded generated files that are no longer planned. */
|
|
72
|
+
stale: string[];
|
|
73
|
+
/** Subset of {@link stale} that this run deleted, when `prune` was set. */
|
|
74
|
+
pruned: string[];
|
|
75
|
+
diagnostics: GeneratorDiagnostic[];
|
|
76
|
+
}
|
|
77
|
+
export interface RegenerationOptions {
|
|
78
|
+
sink: RegenerationSink;
|
|
79
|
+
manifest?: AidManifest;
|
|
80
|
+
/** Discard hand edits to generated files instead of refusing. */
|
|
81
|
+
force?: boolean;
|
|
82
|
+
/** Delete stale generated files instead of only reporting them. */
|
|
83
|
+
prune?: boolean;
|
|
84
|
+
}
|
|
85
|
+
export declare function planRegeneration(plan: Plan, options: RegenerationOptions): RegenerationReport;
|
|
86
|
+
/**
|
|
87
|
+
* Generated files the manifest records that the plan no longer contains. Business files
|
|
88
|
+
* are excluded: a generator is expected to stop planning one once a developer takes it
|
|
89
|
+
* over, and flagging that would punish the intended path.
|
|
90
|
+
*/
|
|
91
|
+
export declare function staleGeneratedFiles(plan: Plan, manifest: AidManifest | undefined): string[];
|
|
92
|
+
export interface RegenerationResult {
|
|
93
|
+
report: RegenerationReport;
|
|
94
|
+
manifest: AidManifest;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Plans, then applies. Drifted generated files are never written unless `force` is set;
|
|
98
|
+
* their newly generated content goes to `<path>.aid-rej` instead, and an error-severity
|
|
99
|
+
* diagnostic is returned so a caller cannot mistake the run for a success.
|
|
100
|
+
*/
|
|
101
|
+
export declare function regenerate(plan: Plan, options: RegenerationOptions & {
|
|
102
|
+
provenance: AidManifestProvenance;
|
|
103
|
+
}): RegenerationResult;
|
|
104
|
+
/**
|
|
105
|
+
* Drift check without writing anything: the shape a CI gate or `aid gen --check` wants.
|
|
106
|
+
* `regenerate` reports the same diagnostics; this exists so a caller cannot accidentally
|
|
107
|
+
* write while only trying to verify.
|
|
108
|
+
*/
|
|
109
|
+
export declare function checkDrift(plan: Plan, options: RegenerationOptions): GeneratorDiagnostic[];
|
|
110
|
+
/** Human-readable one-line summary of what a run did, in reporting order. */
|
|
111
|
+
export declare function formatRegenerationSummary(report: RegenerationReport): string;
|
|
112
|
+
export declare function hasDrift(report: RegenerationReport): boolean;
|
|
113
|
+
export declare function generatedFiles(files: readonly GeneratedFile[]): GeneratedFile[];
|
|
114
|
+
//# sourceMappingURL=drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../src/drift.ts"],"names":[],"mappings":"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"}
|