knitto 0.0.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.
- package/LICENSE +21 -0
- package/README.md +869 -0
- package/dist/src/checks/run.d.ts +3 -0
- package/dist/src/checks/run.js +173 -0
- package/dist/src/checks/run.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +406 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +11 -0
- package/dist/src/config.js +585 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/context/build.d.ts +2 -0
- package/dist/src/context/build.js +147 -0
- package/dist/src/context/build.js.map +1 -0
- package/dist/src/context/render.d.ts +7 -0
- package/dist/src/context/render.js +74 -0
- package/dist/src/context/render.js.map +1 -0
- package/dist/src/engine/apply.d.ts +2 -0
- package/dist/src/engine/apply.js +96 -0
- package/dist/src/engine/apply.js.map +1 -0
- package/dist/src/engine/diff.d.ts +2 -0
- package/dist/src/engine/diff.js +100 -0
- package/dist/src/engine/diff.js.map +1 -0
- package/dist/src/engine/plan.d.ts +2 -0
- package/dist/src/engine/plan.js +259 -0
- package/dist/src/engine/plan.js.map +1 -0
- package/dist/src/errors.d.ts +14 -0
- package/dist/src/errors.js +31 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/filesystem/paths.d.ts +2 -0
- package/dist/src/filesystem/paths.js +47 -0
- package/dist/src/filesystem/paths.js.map +1 -0
- package/dist/src/hooks/run.d.ts +10 -0
- package/dist/src/hooks/run.js +105 -0
- package/dist/src/hooks/run.js.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lock.d.ts +2 -0
- package/dist/src/lock.js +16 -0
- package/dist/src/lock.js.map +1 -0
- package/dist/src/onboarding.d.ts +26 -0
- package/dist/src/onboarding.js +212 -0
- package/dist/src/onboarding.js.map +1 -0
- package/dist/src/parsers/index.d.ts +18 -0
- package/dist/src/parsers/index.js +194 -0
- package/dist/src/parsers/index.js.map +1 -0
- package/dist/src/parsers/json.d.ts +17 -0
- package/dist/src/parsers/json.js +214 -0
- package/dist/src/parsers/json.js.map +1 -0
- package/dist/src/parsers/merge.d.ts +1 -0
- package/dist/src/parsers/merge.js +17 -0
- package/dist/src/parsers/merge.js.map +1 -0
- package/dist/src/project/discover.d.ts +2 -0
- package/dist/src/project/discover.js +144 -0
- package/dist/src/project/discover.js.map +1 -0
- package/dist/src/rules/json-pointer.d.ts +3 -0
- package/dist/src/rules/json-pointer.js +114 -0
- package/dist/src/rules/json-pointer.js.map +1 -0
- package/dist/src/snapshots/canonical.d.ts +11 -0
- package/dist/src/snapshots/canonical.js +150 -0
- package/dist/src/snapshots/canonical.js.map +1 -0
- package/dist/src/sources/process.d.ts +3 -0
- package/dist/src/sources/process.js +28 -0
- package/dist/src/sources/process.js.map +1 -0
- package/dist/src/sources/resolve.d.ts +3 -0
- package/dist/src/sources/resolve.js +144 -0
- package/dist/src/sources/resolve.js.map +1 -0
- package/dist/src/template/init.d.ts +1 -0
- package/dist/src/template/init.js +62 -0
- package/dist/src/template/init.js.map +1 -0
- package/dist/src/template/manifest.d.ts +2 -0
- package/dist/src/template/manifest.js +80 -0
- package/dist/src/template/manifest.js.map +1 -0
- package/dist/src/template/release.d.ts +3 -0
- package/dist/src/template/release.js +8 -0
- package/dist/src/template/release.js.map +1 -0
- package/dist/src/template/validate.d.ts +2 -0
- package/dist/src/template/validate.js +62 -0
- package/dist/src/template/validate.js.map +1 -0
- package/dist/src/types.d.ts +242 -0
- package/dist/src/types.js +4 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.js +3 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { chmod, cp, lstat, mkdir, readdir, readFile, rename, rm, stat, } from "node:fs/promises";
|
|
4
|
+
import { KnittoError } from "../errors.js";
|
|
5
|
+
import { loadTemplateManifest } from "../template/manifest.js";
|
|
6
|
+
async function collectEntries(root, directory = root) {
|
|
7
|
+
const entries = [];
|
|
8
|
+
const children = await readdir(directory, { withFileTypes: true });
|
|
9
|
+
for (const child of children) {
|
|
10
|
+
if (child.name === ".git")
|
|
11
|
+
continue;
|
|
12
|
+
const absolute = path.join(directory, child.name);
|
|
13
|
+
const relative = path.relative(root, absolute).split(path.sep).join("/");
|
|
14
|
+
const metadata = await lstat(absolute);
|
|
15
|
+
if (metadata.isSymbolicLink()) {
|
|
16
|
+
throw new KnittoError(`Template snapshots cannot contain symlinks: ${relative}`, "TEMPLATE");
|
|
17
|
+
}
|
|
18
|
+
if (metadata.isDirectory()) {
|
|
19
|
+
entries.push(...(await collectEntries(root, absolute)));
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!metadata.isFile()) {
|
|
23
|
+
throw new KnittoError(`Unsupported template entry: ${relative}`, "TEMPLATE");
|
|
24
|
+
}
|
|
25
|
+
entries.push({
|
|
26
|
+
path: relative,
|
|
27
|
+
mode: metadata.mode & 0o111 ? 0o755 : 0o644,
|
|
28
|
+
contents: await readFile(absolute),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return entries;
|
|
32
|
+
}
|
|
33
|
+
function frame(value) {
|
|
34
|
+
const buffer = typeof value === "string" ? Buffer.from(value) : value;
|
|
35
|
+
return Buffer.concat([Buffer.from(`${buffer.length}:`), buffer]);
|
|
36
|
+
}
|
|
37
|
+
export async function digestDirectory(root) {
|
|
38
|
+
let metadata;
|
|
39
|
+
try {
|
|
40
|
+
metadata = await stat(root);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new KnittoError(`Template directory does not exist: ${root}`, "SOURCE", { cause: error });
|
|
44
|
+
}
|
|
45
|
+
if (!metadata.isDirectory()) {
|
|
46
|
+
throw new KnittoError(`Template source is not a directory: ${root}`, "SOURCE");
|
|
47
|
+
}
|
|
48
|
+
const entries = await collectEntries(root);
|
|
49
|
+
entries.sort((left, right) => left.path.localeCompare(right.path));
|
|
50
|
+
const hash = createHash("sha256");
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
hash.update(frame(entry.path));
|
|
53
|
+
hash.update(frame(entry.mode.toString(8)));
|
|
54
|
+
hash.update(frame(entry.contents));
|
|
55
|
+
}
|
|
56
|
+
return `sha256:${hash.digest("hex")}`;
|
|
57
|
+
}
|
|
58
|
+
export function cacheRoot() {
|
|
59
|
+
const configured = process.env.XDG_CACHE_HOME;
|
|
60
|
+
const base = configured
|
|
61
|
+
? path.resolve(configured)
|
|
62
|
+
: path.join(process.env.HOME ?? process.cwd(), ".cache");
|
|
63
|
+
return path.join(base, "knitto", "snapshots");
|
|
64
|
+
}
|
|
65
|
+
export function cachePath(digest) {
|
|
66
|
+
const value = digest.replace(/^sha256:/, "");
|
|
67
|
+
if (!/^[a-f0-9]{64}$/.test(value)) {
|
|
68
|
+
throw new KnittoError(`Invalid snapshot digest: ${digest}`, "CONFIG");
|
|
69
|
+
}
|
|
70
|
+
return path.join(cacheRoot(), value);
|
|
71
|
+
}
|
|
72
|
+
export async function cacheSnapshot(sourceDirectory, digest) {
|
|
73
|
+
const destination = cachePath(digest);
|
|
74
|
+
try {
|
|
75
|
+
const metadata = await stat(destination);
|
|
76
|
+
if (metadata.isDirectory()) {
|
|
77
|
+
const actualDigest = await digestDirectory(destination);
|
|
78
|
+
if (actualDigest !== digest) {
|
|
79
|
+
throw new KnittoError(`Cached snapshot is corrupt: expected ${digest}, found ${actualDigest}`, "SOURCE");
|
|
80
|
+
}
|
|
81
|
+
return destination;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (typeof error !== "object" ||
|
|
86
|
+
error === null ||
|
|
87
|
+
!("code" in error) ||
|
|
88
|
+
error.code !== "ENOENT") {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
93
|
+
const temporary = `${destination}.tmp-${process.pid}-${Date.now()}`;
|
|
94
|
+
try {
|
|
95
|
+
await cp(sourceDirectory, temporary, {
|
|
96
|
+
recursive: true,
|
|
97
|
+
errorOnExist: true,
|
|
98
|
+
force: false,
|
|
99
|
+
});
|
|
100
|
+
await chmod(temporary, 0o755);
|
|
101
|
+
await rename(temporary, destination);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
try {
|
|
105
|
+
const metadata = await stat(destination);
|
|
106
|
+
if (!metadata.isDirectory())
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
await rm(temporary, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
return destination;
|
|
117
|
+
}
|
|
118
|
+
export async function loadCachedSnapshot(digest, provenance) {
|
|
119
|
+
const directory = cachePath(digest);
|
|
120
|
+
try {
|
|
121
|
+
await stat(directory);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (typeof error === "object" &&
|
|
125
|
+
error !== null &&
|
|
126
|
+
"code" in error &&
|
|
127
|
+
error.code === "ENOENT") {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const actualDigest = await digestDirectory(directory);
|
|
134
|
+
if (actualDigest !== digest) {
|
|
135
|
+
throw new KnittoError(`Cached snapshot is corrupt: expected ${digest}, found ${actualDigest}`, "SOURCE");
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
digest,
|
|
139
|
+
directory,
|
|
140
|
+
manifest: await loadTemplateManifest(directory),
|
|
141
|
+
provenance,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
throw new KnittoError(`Unable to load cached snapshot: ${digest}`, "SOURCE", {
|
|
146
|
+
cause: error,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../src/snapshots/canonical.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,KAAK,EACL,EAAE,EACF,KAAK,EACL,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,EAAE,EACF,IAAI,GACL,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAQ/D,KAAK,UAAU,cAAc,CAC3B,IAAY,EACZ,SAAS,GAAG,IAAI;IAEhB,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAEpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;QAEvC,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;YAC9B,MAAM,IAAI,WAAW,CACnB,+CAA+C,QAAQ,EAAE,EACzD,UAAU,CACX,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,WAAW,CACnB,+BAA+B,QAAQ,EAAE,EACzC,UAAU,CACX,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK;YAC3C,QAAQ,EAAE,MAAM,QAAQ,CAAC,QAAQ,CAAC;SACnC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,KAAK,CAAC,KAAsB;IACnC,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CACnB,sCAAsC,IAAI,EAAE,EAC5C,QAAQ,EACR,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,WAAW,CAAC,uCAAuC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEnE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC9C,MAAM,IAAI,GAAG,UAAU;QACrB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC1B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,WAAW,CAAC,4BAA4B,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,eAAuB,EACvB,MAAc;IAEd,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;YACxD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,IAAI,WAAW,CACnB,wCAAwC,MAAM,WAAW,YAAY,EAAE,EACvE,QAAQ,CACT,CAAC;YACJ,CAAC;YACD,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACd,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;YAClB,KAAK,CAAC,IAAI,KAAK,QAAQ,EACvB,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,GAAG,WAAW,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAEpE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE;YACnC,SAAS,EAAE,IAAI;YACf,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;QACH,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE;gBAAE,MAAM,KAAK,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,UAA8B;IAE9B,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACd,MAAM,IAAI,KAAK;YACf,KAAK,CAAC,IAAI,KAAK,QAAQ,EACvB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,WAAW,CACnB,wCAAwC,MAAM,WAAW,YAAY,EAAE,EACvE,QAAQ,CACT,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM;YACN,SAAS;YACT,QAAQ,EAAE,MAAM,oBAAoB,CAAC,SAAS,CAAC;YAC/C,UAAU;SACX,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC,mCAAmC,MAAM,EAAE,EAAE,QAAQ,EAAE;YAC3E,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { KnittoError } from "../errors.js";
|
|
3
|
+
export async function run(command, args, options = {}) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const child = spawn(command, args, {
|
|
6
|
+
cwd: options.cwd,
|
|
7
|
+
env: process.env,
|
|
8
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
9
|
+
});
|
|
10
|
+
const stdout = [];
|
|
11
|
+
const stderr = [];
|
|
12
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
13
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
14
|
+
child.on("error", (error) => {
|
|
15
|
+
reject(new KnittoError(`Unable to run ${command}`, "SOURCE", {
|
|
16
|
+
cause: error,
|
|
17
|
+
}));
|
|
18
|
+
});
|
|
19
|
+
child.on("close", (code) => {
|
|
20
|
+
if (code === 0) {
|
|
21
|
+
resolve(Buffer.concat(stdout).toString("utf8").trim());
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
reject(new KnittoError(`${command} failed with exit code ${code}: ${Buffer.concat(stderr).toString("utf8").trim()}`, "SOURCE"));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../../src/sources/process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,OAAe,EACf,IAAc,EACd,UAA4B,EAAE;IAE9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QACH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,MAAM,CACJ,IAAI,WAAW,CAAC,iBAAiB,OAAO,EAAE,EAAE,QAAQ,EAAE;gBACpD,KAAK,EAAE,KAAK;aACb,CAAC,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;YACD,MAAM,CACJ,IAAI,WAAW,CACb,GAAG,OAAO,0BAA0B,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAC5F,QAAQ,CACT,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type ProjectLock, type Snapshot, type SourceConfig } from "../types.js";
|
|
2
|
+
export declare function resolveCurrentSnapshot(source: SourceConfig, projectRoot: string): Promise<Snapshot>;
|
|
3
|
+
export declare function resolveLockedSnapshot(lock: ProjectLock, projectRoot: string): Promise<Snapshot>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import { mkdir, mkdtemp, rm, writeFile, } from "node:fs/promises";
|
|
4
|
+
import * as tar from "tar";
|
|
5
|
+
import { KnittoError } from "../errors.js";
|
|
6
|
+
import { resolveInside } from "../filesystem/paths.js";
|
|
7
|
+
import { loadTemplateManifest } from "../template/manifest.js";
|
|
8
|
+
import { cacheSnapshot, digestDirectory, loadCachedSnapshot, } from "../snapshots/canonical.js";
|
|
9
|
+
import { run } from "./process.js";
|
|
10
|
+
async function materializeLocal(source, projectRoot) {
|
|
11
|
+
return {
|
|
12
|
+
root: path.resolve(projectRoot, source.path),
|
|
13
|
+
provenance: {
|
|
14
|
+
sourceType: "local",
|
|
15
|
+
locator: source.path,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async function materializeHttp(source) {
|
|
20
|
+
const temporary = await mkdtemp(path.join(os.tmpdir(), "knitto-http-"));
|
|
21
|
+
const archive = path.join(temporary, "template.tar");
|
|
22
|
+
const extracted = path.join(temporary, "extracted");
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(source.url, {
|
|
25
|
+
headers: { accept: "application/gzip, application/x-tar, application/octet-stream" },
|
|
26
|
+
redirect: "follow",
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new KnittoError(`Template request failed with HTTP ${response.status}: ${source.url}`, "SOURCE");
|
|
30
|
+
}
|
|
31
|
+
await mkdir(extracted);
|
|
32
|
+
await writeFile(archive, Buffer.from(await response.arrayBuffer()));
|
|
33
|
+
await tar.x({
|
|
34
|
+
file: archive,
|
|
35
|
+
cwd: extracted,
|
|
36
|
+
strict: true,
|
|
37
|
+
preservePaths: false,
|
|
38
|
+
});
|
|
39
|
+
const etag = response.headers.get("etag");
|
|
40
|
+
const lastModified = response.headers.get("last-modified");
|
|
41
|
+
return {
|
|
42
|
+
root: source.path ? resolveInside(extracted, source.path) : extracted,
|
|
43
|
+
provenance: {
|
|
44
|
+
sourceType: "http",
|
|
45
|
+
locator: source.url,
|
|
46
|
+
...(source.path ? { templatePath: source.path } : {}),
|
|
47
|
+
...(etag ? { etag } : {}),
|
|
48
|
+
...(lastModified ? { lastModified } : {}),
|
|
49
|
+
},
|
|
50
|
+
cleanup: () => rm(temporary, { recursive: true, force: true }),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
await rm(temporary, { recursive: true, force: true });
|
|
55
|
+
if (error instanceof KnittoError)
|
|
56
|
+
throw error;
|
|
57
|
+
throw new KnittoError(`Unable to resolve HTTP source: ${source.url}`, "SOURCE", {
|
|
58
|
+
cause: error,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function materializeGit(source, lockedRevision) {
|
|
63
|
+
const temporary = await mkdtemp(path.join(os.tmpdir(), "knitto-git-"));
|
|
64
|
+
const checkout = path.join(temporary, "checkout");
|
|
65
|
+
const requestedRef = lockedRevision ?? source.ref ?? "HEAD";
|
|
66
|
+
try {
|
|
67
|
+
await mkdir(checkout);
|
|
68
|
+
await run("git", ["init", "--quiet"], { cwd: checkout });
|
|
69
|
+
await run("git", ["remote", "add", "origin", source.url], { cwd: checkout });
|
|
70
|
+
await run("git", ["fetch", "--quiet", "--depth=1", "origin", requestedRef], {
|
|
71
|
+
cwd: checkout,
|
|
72
|
+
});
|
|
73
|
+
await run("git", ["checkout", "--quiet", "--detach", "FETCH_HEAD"], {
|
|
74
|
+
cwd: checkout,
|
|
75
|
+
});
|
|
76
|
+
const revision = await run("git", ["rev-parse", "HEAD"], { cwd: checkout });
|
|
77
|
+
return {
|
|
78
|
+
root: source.path ? resolveInside(checkout, source.path) : checkout,
|
|
79
|
+
provenance: {
|
|
80
|
+
sourceType: "git",
|
|
81
|
+
locator: source.url,
|
|
82
|
+
...(source.path ? { templatePath: source.path } : {}),
|
|
83
|
+
revision,
|
|
84
|
+
},
|
|
85
|
+
cleanup: () => rm(temporary, { recursive: true, force: true }),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
await rm(temporary, { recursive: true, force: true });
|
|
90
|
+
if (error instanceof KnittoError)
|
|
91
|
+
throw error;
|
|
92
|
+
throw new KnittoError(`Unable to resolve Git source: ${source.url}`, "SOURCE", {
|
|
93
|
+
cause: error,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function materialize(source, projectRoot, lockedRevision) {
|
|
98
|
+
switch (source.type) {
|
|
99
|
+
case "local":
|
|
100
|
+
return materializeLocal(source, projectRoot);
|
|
101
|
+
case "http":
|
|
102
|
+
return materializeHttp(source);
|
|
103
|
+
case "git":
|
|
104
|
+
return materializeGit(source, lockedRevision);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function snapshotMaterialized(materialized) {
|
|
108
|
+
try {
|
|
109
|
+
const manifest = await loadTemplateManifest(materialized.root);
|
|
110
|
+
const digest = await digestDirectory(materialized.root);
|
|
111
|
+
const directory = await cacheSnapshot(materialized.root, digest);
|
|
112
|
+
return {
|
|
113
|
+
digest,
|
|
114
|
+
directory,
|
|
115
|
+
manifest,
|
|
116
|
+
provenance: materialized.provenance,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (error instanceof KnittoError)
|
|
121
|
+
throw error;
|
|
122
|
+
throw new KnittoError("Unable to create template snapshot", "TEMPLATE", {
|
|
123
|
+
cause: error,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await materialized.cleanup?.();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export async function resolveCurrentSnapshot(source, projectRoot) {
|
|
131
|
+
return snapshotMaterialized(await materialize(source, projectRoot));
|
|
132
|
+
}
|
|
133
|
+
export async function resolveLockedSnapshot(lock, projectRoot) {
|
|
134
|
+
const cached = await loadCachedSnapshot(lock.digest, lock.provenance);
|
|
135
|
+
if (cached)
|
|
136
|
+
return cached;
|
|
137
|
+
const materialized = await materialize(lock.source, projectRoot, lock.provenance.revision);
|
|
138
|
+
const snapshot = await snapshotMaterialized(materialized);
|
|
139
|
+
if (snapshot.digest !== lock.digest) {
|
|
140
|
+
throw new KnittoError(`Locked snapshot ${lock.digest} is unavailable; source resolved to ${snapshot.digest}`, "SOURCE");
|
|
141
|
+
}
|
|
142
|
+
return snapshot;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/sources/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initializeTemplate(root: string, name?: string): Promise<void>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { access, mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { KnittoError } from "../errors.js";
|
|
4
|
+
import { CONFIG_FILE, TEMPLATE_MANIFEST } from "../types.js";
|
|
5
|
+
import { KNITTO_PACKAGE, KNITTO_VERSION } from "../version.js";
|
|
6
|
+
async function exists(file) {
|
|
7
|
+
return access(file)
|
|
8
|
+
.then(() => true)
|
|
9
|
+
.catch(() => false);
|
|
10
|
+
}
|
|
11
|
+
export async function initializeTemplate(root, name = path.basename(root)) {
|
|
12
|
+
const templateRoot = path.join(root, ".knitto");
|
|
13
|
+
const configFile = path.join(root, CONFIG_FILE);
|
|
14
|
+
const existing = (await Promise.all([
|
|
15
|
+
[templateRoot, await exists(templateRoot)],
|
|
16
|
+
[configFile, await exists(configFile)],
|
|
17
|
+
]))
|
|
18
|
+
.filter(([, present]) => present)
|
|
19
|
+
.map(([file]) => file);
|
|
20
|
+
if (existing.length > 0) {
|
|
21
|
+
throw new KnittoError(`Refusing to initialize a template because ${existing.join(", ")} already exists`, "CONFIG");
|
|
22
|
+
}
|
|
23
|
+
await mkdir(root, { recursive: true });
|
|
24
|
+
let templateCreated = false;
|
|
25
|
+
let configCreated = false;
|
|
26
|
+
try {
|
|
27
|
+
await mkdir(templateRoot);
|
|
28
|
+
templateCreated = true;
|
|
29
|
+
await mkdir(path.join(templateRoot, "files"));
|
|
30
|
+
await writeFile(path.join(templateRoot, TEMPLATE_MANIFEST), `${JSON.stringify({
|
|
31
|
+
schemaVersion: 1,
|
|
32
|
+
name,
|
|
33
|
+
engine: {
|
|
34
|
+
package: KNITTO_PACKAGE,
|
|
35
|
+
version: KNITTO_VERSION,
|
|
36
|
+
},
|
|
37
|
+
rules: [],
|
|
38
|
+
}, null, 2)}\n`, { flag: "wx" });
|
|
39
|
+
await writeFile(configFile, `${JSON.stringify({
|
|
40
|
+
source: {
|
|
41
|
+
type: "local",
|
|
42
|
+
path: ".knitto",
|
|
43
|
+
},
|
|
44
|
+
engine: {
|
|
45
|
+
package: KNITTO_PACKAGE,
|
|
46
|
+
version: KNITTO_VERSION,
|
|
47
|
+
},
|
|
48
|
+
}, null, 2)}\n`, { flag: "wx" });
|
|
49
|
+
configCreated = true;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (templateCreated) {
|
|
53
|
+
await rm(templateRoot, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
if (configCreated)
|
|
56
|
+
await rm(configFile, { force: true });
|
|
57
|
+
throw new KnittoError(`Unable to initialize template: ${root}`, "CONFIG", {
|
|
58
|
+
cause: error,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/template/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { validateTemplateManifest } from "../config.js";
|
|
4
|
+
import { KnittoError } from "../errors.js";
|
|
5
|
+
import { resolveInside } from "../filesystem/paths.js";
|
|
6
|
+
import { TEMPLATE_MANIFEST } from "../types.js";
|
|
7
|
+
function mergeManifests(base, overlay) {
|
|
8
|
+
const rules = [...base.rules];
|
|
9
|
+
for (const rule of overlay.rules) {
|
|
10
|
+
const existing = rules.findIndex((candidate) => candidate.id === rule.id);
|
|
11
|
+
if (existing === -1)
|
|
12
|
+
rules.push(rule);
|
|
13
|
+
else
|
|
14
|
+
rules[existing] = rule;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
schemaVersion: 1,
|
|
18
|
+
name: overlay.name,
|
|
19
|
+
...(overlay.engine
|
|
20
|
+
? { engine: overlay.engine }
|
|
21
|
+
: base.engine
|
|
22
|
+
? { engine: base.engine }
|
|
23
|
+
: {}),
|
|
24
|
+
...(overlay.release
|
|
25
|
+
? { release: overlay.release }
|
|
26
|
+
: base.release
|
|
27
|
+
? { release: base.release }
|
|
28
|
+
: {}),
|
|
29
|
+
rules,
|
|
30
|
+
checks: [
|
|
31
|
+
...(base.checks ?? []).filter((check) => !(overlay.checks ?? []).some((entry) => entry.id === check.id)),
|
|
32
|
+
...(overlay.checks ?? []),
|
|
33
|
+
],
|
|
34
|
+
hooks: [
|
|
35
|
+
...(base.hooks ?? []).filter((hook) => !(overlay.hooks ?? []).some((entry) => entry.id === hook.id)),
|
|
36
|
+
...(overlay.hooks ?? []),
|
|
37
|
+
],
|
|
38
|
+
variables: {
|
|
39
|
+
...(base.variables ?? {}),
|
|
40
|
+
...(overlay.variables ?? {}),
|
|
41
|
+
},
|
|
42
|
+
inputs: [...new Set([...(base.inputs ?? []), ...(overlay.inputs ?? [])])],
|
|
43
|
+
partials: {
|
|
44
|
+
...(base.partials ?? {}),
|
|
45
|
+
...(overlay.partials ?? {}),
|
|
46
|
+
},
|
|
47
|
+
prompts: [
|
|
48
|
+
...(base.prompts ?? []).filter((prompt) => !(overlay.prompts ?? []).some((entry) => entry.path === prompt.path)),
|
|
49
|
+
...(overlay.prompts ?? []),
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export async function loadTemplateManifest(root, manifestPath = TEMPLATE_MANIFEST, loading = new Set()) {
|
|
54
|
+
const normalized = manifestPath.split(path.sep).join("/");
|
|
55
|
+
if (loading.has(normalized)) {
|
|
56
|
+
throw new KnittoError(`Template manifest inheritance cycle: ${[...loading, normalized].join(" -> ")}`, "TEMPLATE");
|
|
57
|
+
}
|
|
58
|
+
loading.add(normalized);
|
|
59
|
+
let manifest;
|
|
60
|
+
try {
|
|
61
|
+
const value = JSON.parse(await readFile(resolveInside(root, normalized), "utf8"));
|
|
62
|
+
manifest = validateTemplateManifest(value);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof KnittoError)
|
|
66
|
+
throw error;
|
|
67
|
+
throw new KnittoError(`Unable to load template manifest: ${normalized}`, "TEMPLATE", { cause: error });
|
|
68
|
+
}
|
|
69
|
+
let resolved = {
|
|
70
|
+
schemaVersion: 1,
|
|
71
|
+
name: manifest.name,
|
|
72
|
+
rules: [],
|
|
73
|
+
};
|
|
74
|
+
for (const parent of manifest.extends ?? []) {
|
|
75
|
+
resolved = mergeManifests(resolved, await loadTemplateManifest(root, parent, new Set(loading)));
|
|
76
|
+
}
|
|
77
|
+
loading.delete(normalized);
|
|
78
|
+
return mergeManifests(resolved, manifest);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/template/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const UNRELEASED_TEMPLATE_VERSION = "0.0.0";
|
|
2
|
+
export function templateReleaseTag(release) {
|
|
3
|
+
if (!release || release.version === UNRELEASED_TEMPLATE_VERSION) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
return release.tagFormat.replaceAll("{version}", release.version);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release.js","sourceRoot":"","sources":["../../../src/template/release.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAC;AAEnD,MAAM,UAAU,kBAAkB,CAChC,OAAoC;IAEpC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,2BAA2B,EAAE,CAAC;QAChE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import Handlebars from "handlebars";
|
|
3
|
+
import { KnittoError } from "../errors.js";
|
|
4
|
+
import { assertNoEscapingSymlink, resolveInside, } from "../filesystem/paths.js";
|
|
5
|
+
async function validateAsset(snapshot, asset) {
|
|
6
|
+
const file = resolveInside(snapshot.directory, asset.path);
|
|
7
|
+
await assertNoEscapingSymlink(snapshot.directory, file);
|
|
8
|
+
let fileStat;
|
|
9
|
+
try {
|
|
10
|
+
fileStat = await stat(file);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
throw new KnittoError(`Template ${asset.kind} for ${asset.owner} does not exist: ${asset.path}`, "TEMPLATE", { cause: error });
|
|
14
|
+
}
|
|
15
|
+
if (!fileStat.isFile()) {
|
|
16
|
+
throw new KnittoError(`Template ${asset.kind} for ${asset.owner} is not a file: ${asset.path}`, "TEMPLATE");
|
|
17
|
+
}
|
|
18
|
+
if (asset.kind !== "hook") {
|
|
19
|
+
try {
|
|
20
|
+
Handlebars.parse(await readFile(file, "utf8"));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw new KnittoError(`Template ${asset.kind} for ${asset.owner} contains invalid Handlebars: ${asset.path}`, "TEMPLATE", { cause: error });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (asset.kind === "hook" && (fileStat.mode & 0o111) === 0) {
|
|
27
|
+
throw new KnittoError(`Template hook ${asset.owner} is not executable: ${asset.path}`, "TEMPLATE");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function validateTemplateSnapshot(snapshot) {
|
|
31
|
+
const assets = [];
|
|
32
|
+
for (const [name, partial] of Object.entries(snapshot.manifest.partials ?? {})) {
|
|
33
|
+
assets.push({ path: partial, kind: "file", owner: `partial ${name}` });
|
|
34
|
+
}
|
|
35
|
+
for (const rule of snapshot.manifest.rules) {
|
|
36
|
+
if (rule.type === "delete")
|
|
37
|
+
continue;
|
|
38
|
+
assets.push({
|
|
39
|
+
path: rule.template,
|
|
40
|
+
kind: "file",
|
|
41
|
+
owner: `rule ${rule.id}`,
|
|
42
|
+
});
|
|
43
|
+
if ("schema" in rule && rule.schema) {
|
|
44
|
+
assets.push({
|
|
45
|
+
path: rule.schema,
|
|
46
|
+
kind: "schema",
|
|
47
|
+
owner: `rule ${rule.id}`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (rule.type === "content" && rule.parser === "hook") {
|
|
51
|
+
const hook = snapshot.manifest.hooks?.find((candidate) => candidate.id === rule.hook && candidate.kind === "parser");
|
|
52
|
+
if (!hook) {
|
|
53
|
+
throw new KnittoError(`Parser hook does not exist for rule ${rule.id}: ${rule.hook ?? ""}`, "TEMPLATE");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const hook of snapshot.manifest.hooks ?? []) {
|
|
58
|
+
assets.push({ path: hook.command, kind: "hook", owner: hook.id });
|
|
59
|
+
}
|
|
60
|
+
await Promise.all(assets.map((asset) => validateAsset(snapshot, asset)));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/template/validate.ts"],"names":[],"mappings":"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"}
|