@pajh/buldng 0.0.2 → 0.0.4
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/package.json +14 -10
- package/src/buldng-dev-errors.js +84 -0
- package/src/buldng-lib.js +465 -0
- package/src/buldng-ops.js +258 -0
- package/src/buldng-validate.js +207 -0
- package/src/buldng-web.ts +267 -0
- package/src/buldng.css +148 -0
- package/src/clean.sh +14 -0
- package/src/layout.ts +184 -0
- package/src/types/global.d.ts +10 -0
- package/src/workfile.js +69 -0
- package/src/wrapper.html +24 -0
- package/dist/buldng-lib.js +0 -194
- package/dist/buldng-validate.js +0 -102
- package/dist/workfile.js +0 -162
- /package/{dist → src}/init.js +0 -0
package/src/wrapper.html
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>BULDR.IO</title>
|
|
7
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
8
|
+
<link rel="stylesheet" href="/buldng.css">
|
|
9
|
+
|
|
10
|
+
<!--CSS-->
|
|
11
|
+
<script>
|
|
12
|
+
window.__ready = {};
|
|
13
|
+
window.__ready.a = new Promise((resolve) => { window.__ready._resolveA = resolve; });
|
|
14
|
+
</script>
|
|
15
|
+
<script type="module" src="/layout.js"></script>
|
|
16
|
+
<!--SCRIPTS-->
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="b-camera">
|
|
20
|
+
<!-- Project outline (camera-style) will be stitched here -->
|
|
21
|
+
<!--CAMERA-STYLE-->
|
|
22
|
+
</div>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
package/dist/buldng-lib.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
// tools/build-lib.js
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import esbuild from "esbuild";
|
|
5
|
-
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
8
|
-
import { readFileSync } from "node:fs";
|
|
9
|
-
|
|
10
|
-
import { WorkFile } from "./workfile.js";
|
|
11
|
-
import { getDest, assertDestWrite, assertSourceRead, getInputs } from "./buldng-validate.js";
|
|
12
|
-
export { assertSourceRead, assertDestWrite, setSource, setDest } from "./buldng-validate.js";
|
|
13
|
-
|
|
14
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const pkg = JSON.parse(readFileSync(join(here, "../package.json"), "utf8"));
|
|
16
|
-
|
|
17
|
-
let headerPrinted = false;
|
|
18
|
-
export function printHeader(importMeta) {
|
|
19
|
-
if (headerPrinted) return;
|
|
20
|
-
headerPrinted = true;
|
|
21
|
-
|
|
22
|
-
const version = pkg.version;
|
|
23
|
-
const timestamp = new Date().toLocaleString("en-IE", { hour12: false });
|
|
24
|
-
|
|
25
|
-
const callerFile = fileURLToPath(importMeta.url);
|
|
26
|
-
const callerDir = dirname(callerFile);
|
|
27
|
-
|
|
28
|
-
console.log(`Xx buldng build system v${version} — ${timestamp}`);
|
|
29
|
-
console.log(`${callerDir}/${callerFile.split("/").pop()}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// --------------------------------------------------
|
|
33
|
-
// mkdir("puzzle")
|
|
34
|
-
// --------------------------------------------------
|
|
35
|
-
export function mkdir(relDir) {
|
|
36
|
-
const abs = assertDestWrite(relDir);
|
|
37
|
-
fs.mkdirSync(abs, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// --------------------------------------------------
|
|
41
|
-
// deepCopy — raw filesystem path
|
|
42
|
-
// --------------------------------------------------
|
|
43
|
-
export function deepCopy(from, to) {
|
|
44
|
-
let DEST = getDest();
|
|
45
|
-
|
|
46
|
-
console.log(`deepCopy: ${from} → ${to}`);
|
|
47
|
-
|
|
48
|
-
const absFrom = path.resolve(from);
|
|
49
|
-
|
|
50
|
-
if (to.includes("..")) {
|
|
51
|
-
throw new Error("SECURITY: Illegal path traversal in deepCopy()");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const absTo = to === "/" ? DEST : path.resolve(DEST, to);
|
|
55
|
-
|
|
56
|
-
if (!absTo.startsWith(DEST)) {
|
|
57
|
-
throw new Error(`SECURITY: deepCopy target escapes dest:
|
|
58
|
-
dest: ${DEST}
|
|
59
|
-
target: ${absTo}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!fs.existsSync(absFrom)) {
|
|
63
|
-
throw new Error(`deepCopy: source does not exist: ${absFrom}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function copyRecursive(src, dst) {
|
|
67
|
-
const stat = fs.statSync(src);
|
|
68
|
-
|
|
69
|
-
if (stat.isDirectory()) {
|
|
70
|
-
fs.mkdirSync(dst, { recursive: true });
|
|
71
|
-
const entries = fs.readdirSync(src);
|
|
72
|
-
for (const entry of entries) {
|
|
73
|
-
copyRecursive(path.join(src, entry), path.join(dst, entry));
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
77
|
-
fs.copyFileSync(src, dst);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
copyRecursive(absFrom, absTo);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function header() {
|
|
85
|
-
printHeader(import.meta);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// --------------------------------------------------
|
|
89
|
-
// file`path.ext` — tagged template literal
|
|
90
|
-
// --------------------------------------------------
|
|
91
|
-
export function file(strings, ...values) {
|
|
92
|
-
if (values.length > 0) {
|
|
93
|
-
throw new Error("file`` does not support interpolation");
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const relPath = strings.join("");
|
|
97
|
-
const absPath = assertSourceRead(relPath);
|
|
98
|
-
|
|
99
|
-
return new WorkFile("file", { relPath, absPath }, []);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// --------------------------------------------------
|
|
103
|
-
// literal(text)
|
|
104
|
-
// --------------------------------------------------
|
|
105
|
-
export function literal(value) {
|
|
106
|
-
return new WorkFile("literal", { value }, []);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// --------------------------------------------------
|
|
110
|
-
// ensureWorkFile(x)
|
|
111
|
-
// --------------------------------------------------
|
|
112
|
-
function ensureWorkFile(x, fieldName = "value") {
|
|
113
|
-
if (x instanceof WorkFile) return x;
|
|
114
|
-
|
|
115
|
-
if (typeof x === "string") {
|
|
116
|
-
return literal(x);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
throw new Error(`${fieldName} must be WorkFile or string`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// --------------------------------------------------
|
|
123
|
-
// csslink(filename)
|
|
124
|
-
// --------------------------------------------------
|
|
125
|
-
export function csslink(filename) {
|
|
126
|
-
return new WorkFile(
|
|
127
|
-
"literal",
|
|
128
|
-
{ value: `<link rel="stylesheet" href="/${filename}">` },
|
|
129
|
-
[]
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// --------------------------------------------------
|
|
134
|
-
// scriptlink(filename)
|
|
135
|
-
// --------------------------------------------------
|
|
136
|
-
export function scriptlink(filename) {
|
|
137
|
-
return new WorkFile(
|
|
138
|
-
"literal",
|
|
139
|
-
{ value: `<script type="module" src="/${filename}"></script>` },
|
|
140
|
-
[]
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// --------------------------------------------------
|
|
145
|
-
// append(...items)
|
|
146
|
-
// --------------------------------------------------
|
|
147
|
-
export function append(...items) {
|
|
148
|
-
const children = items.map(item => {
|
|
149
|
-
if (item instanceof WorkFile) return item;
|
|
150
|
-
if (typeof item === "string") return literal(item);
|
|
151
|
-
throw new Error("append(): each item must be WorkFile or string");
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
if (children.length < 2) {
|
|
155
|
-
throw new Error("append(): requires at least 2 items");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return new WorkFile("append", {}, children);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// --------------------------------------------------
|
|
162
|
-
// replace(source, tag, replacement)
|
|
163
|
-
// --------------------------------------------------
|
|
164
|
-
export function replace(source, tag, replacement) {
|
|
165
|
-
const srcWF = ensureWorkFile(source, "source");
|
|
166
|
-
const tagWF = ensureWorkFile(tag, "tag");
|
|
167
|
-
const repWF = ensureWorkFile(replacement, "replacement");
|
|
168
|
-
|
|
169
|
-
if (tagWF.op === "literal" && tagWF.config.value.trim() === "") {
|
|
170
|
-
throw new Error(`replace(): tag cannot be blank`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return new WorkFile("replace", {}, [srcWF, tagWF, repWF]);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// --------------------------------------------------
|
|
177
|
-
// compile(source)
|
|
178
|
-
// --------------------------------------------------
|
|
179
|
-
export function compile(source, flags = {}) {
|
|
180
|
-
const srcWF = ensureWorkFile(source, "source");
|
|
181
|
-
return new WorkFile("compile", { flags }, [srcWF]);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// --------------------------------------------------
|
|
185
|
-
// build-inputs.json manifest
|
|
186
|
-
// --------------------------------------------------
|
|
187
|
-
process.on("exit", () => {
|
|
188
|
-
if (process.env.BULDNG_HOT !== "1") return;
|
|
189
|
-
let DEST = getDest();
|
|
190
|
-
let INPUTS = getInputs();
|
|
191
|
-
const manifest = Array.from(INPUTS);
|
|
192
|
-
const out = path.join(DEST, "build-inputs.json");
|
|
193
|
-
fs.writeFileSync(out, JSON.stringify(manifest, null, 2));
|
|
194
|
-
});
|
package/dist/buldng-validate.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
// --------------------------------------------------
|
|
5
|
-
// GLOBAL SOURCE & DEST ROOTS
|
|
6
|
-
// --------------------------------------------------
|
|
7
|
-
|
|
8
|
-
let SRC = null;
|
|
9
|
-
let DEST = null;
|
|
10
|
-
|
|
11
|
-
// --------------------------------------------------
|
|
12
|
-
// SETTERS WITH SAFETY CHECKS
|
|
13
|
-
// --------------------------------------------------
|
|
14
|
-
|
|
15
|
-
export function setSource(dir) {
|
|
16
|
-
const abs = path.resolve(dir);
|
|
17
|
-
const sentinel = path.join(abs, "BULDNG_SRC");
|
|
18
|
-
if (!fs.existsSync(sentinel)) {
|
|
19
|
-
throw new Error(`SECURITY: Source directory "${abs}" does not contain BLDNG_SRC sentinel`);
|
|
20
|
-
}
|
|
21
|
-
SRC = abs;
|
|
22
|
-
validateRoots();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function setDest(dir) {
|
|
26
|
-
const abs = path.resolve(dir);
|
|
27
|
-
|
|
28
|
-
if (fs.existsSync(abs)) {
|
|
29
|
-
const sentinel = path.join(abs, "BULDNG_SRC");
|
|
30
|
-
if (fs.existsSync(sentinel)) {
|
|
31
|
-
throw new Error(`SECURITY: Dest directory "${abs}" contains BLDNG_SRC sentinel`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const entries = fs.readdirSync(abs, { withFileTypes: true });
|
|
35
|
-
for (const entry of entries) {
|
|
36
|
-
fs.rmSync(path.join(abs, entry.name), { recursive: true, force: true });
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
fs.mkdirSync(abs, { recursive: true });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
DEST = abs;
|
|
43
|
-
validateRoots();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function getDest() {
|
|
47
|
-
if (!DEST) throw new Error("SECURITY: Dest root not set");
|
|
48
|
-
return DEST;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// --------------------------------------------------
|
|
52
|
-
// PATH SAFETY HELPERS
|
|
53
|
-
// --------------------------------------------------
|
|
54
|
-
|
|
55
|
-
export function assertSourceRead(relPath) {
|
|
56
|
-
if (!SRC) throw new Error("SECURITY: Source root not set");
|
|
57
|
-
if (relPath.includes("..")) throw new Error("SECURITY: Illegal path traversal in read()");
|
|
58
|
-
const abs = path.resolve(SRC, relPath);
|
|
59
|
-
if (!abs.startsWith(SRC)) throw new Error("SECURITY: Read outside src/");
|
|
60
|
-
trackInput(abs);
|
|
61
|
-
return abs;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function assertDestWrite(relPath) {
|
|
65
|
-
if (!DEST) throw new Error("SECURITY: Dest root not set");
|
|
66
|
-
if (relPath.includes("..")) throw new Error("SECURITY: Illegal path traversal in save()");
|
|
67
|
-
const abs = path.resolve(DEST, relPath);
|
|
68
|
-
if (!abs.startsWith(DEST)) throw new Error("SECURITY: Write outside dest/");
|
|
69
|
-
return abs;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function validateRoots() {
|
|
73
|
-
if (!SRC || !DEST) return;
|
|
74
|
-
|
|
75
|
-
const srcReal = fs.realpathSync(SRC);
|
|
76
|
-
const destReal = fs.realpathSync(DEST);
|
|
77
|
-
|
|
78
|
-
if (srcReal === destReal) {
|
|
79
|
-
throw new Error(`SECURITY: src and dest resolve to the same directory:
|
|
80
|
-
src: ${SRC}
|
|
81
|
-
dest: ${DEST}`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (srcReal.startsWith(destReal) || destReal.startsWith(srcReal)) {
|
|
85
|
-
throw new Error(`SECURITY: src and dest cannot be nested:
|
|
86
|
-
src: ${SRC}
|
|
87
|
-
dest: ${DEST}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const INPUTS = new Set();
|
|
92
|
-
|
|
93
|
-
export function getInputs() {
|
|
94
|
-
return INPUTS;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function trackInput(absPath) {
|
|
98
|
-
if (!SRC || !DEST) return;
|
|
99
|
-
if (absPath.startsWith(SRC) && !absPath.startsWith(DEST)) {
|
|
100
|
-
INPUTS.add(absPath);
|
|
101
|
-
}
|
|
102
|
-
}
|
package/dist/workfile.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// --------------------------------------------------
|
|
2
|
-
// WorkFile — immutable, lazy, tree-structured build node
|
|
3
|
-
// --------------------------------------------------
|
|
4
|
-
|
|
5
|
-
import fs from "node:fs";
|
|
6
|
-
import path from "node:path";
|
|
7
|
-
import esbuild from "esbuild";
|
|
8
|
-
import { assertDestWrite } from "./buldng-lib.js";
|
|
9
|
-
|
|
10
|
-
export class WorkFile {
|
|
11
|
-
constructor(op, config = {}, children = []) {
|
|
12
|
-
this.op = op; // "file", "literal", "append", "replace", "compile"
|
|
13
|
-
this.config = Object.freeze(config);
|
|
14
|
-
this.children = Object.freeze(children);
|
|
15
|
-
|
|
16
|
-
Object.freeze(this); // full immutability
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// --------------------------------------------------
|
|
20
|
-
// execute(): recursively produce output string
|
|
21
|
-
// --------------------------------------------------
|
|
22
|
-
execute() {
|
|
23
|
-
switch (this.op) {
|
|
24
|
-
|
|
25
|
-
// ----------------------------------------------
|
|
26
|
-
// FILE — lazy read from disk
|
|
27
|
-
// ----------------------------------------------
|
|
28
|
-
case "file": {
|
|
29
|
-
const abs = this.config.absPath;
|
|
30
|
-
return fs.readFileSync(abs, "utf8");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ----------------------------------------------
|
|
34
|
-
// LITERAL — inline text
|
|
35
|
-
// ----------------------------------------------
|
|
36
|
-
case "literal": {
|
|
37
|
-
return this.config.value;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ----------------------------------------------
|
|
41
|
-
// APPEND — concat children in order
|
|
42
|
-
// ----------------------------------------------
|
|
43
|
-
case "append": {
|
|
44
|
-
let out = "";
|
|
45
|
-
|
|
46
|
-
for (const child of this.children) {
|
|
47
|
-
const chunk = child.execute();
|
|
48
|
-
|
|
49
|
-
if (out.length > 0 &&
|
|
50
|
-
!out.endsWith("\n") &&
|
|
51
|
-
!chunk.startsWith("\n")) {
|
|
52
|
-
out += "\n";
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
out += chunk;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return out;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ----------------------------------------------
|
|
62
|
-
// REPLACE — replace tag with replacement
|
|
63
|
-
// ----------------------------------------------
|
|
64
|
-
case "replace": {
|
|
65
|
-
if (this.children.length !== 3) {
|
|
66
|
-
throw new Error(`replace(): expected 3 children, got ${this.children.length}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const [srcWF, tagWF, repWF] = this.children;
|
|
70
|
-
|
|
71
|
-
const src = srcWF.execute();
|
|
72
|
-
const tag = tagWF.execute();
|
|
73
|
-
const rep = repWF.execute();
|
|
74
|
-
|
|
75
|
-
if (!src.includes(tag)) {
|
|
76
|
-
throw new Error(`replace(): tag "${tag}" not found in source`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return src.replace(tag, rep);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ----------------------------------------------
|
|
83
|
-
// COMPILE — esbuild wrapper
|
|
84
|
-
// ----------------------------------------------
|
|
85
|
-
case "compile": {
|
|
86
|
-
if (this.children.length !== 1) {
|
|
87
|
-
throw new Error(`compile(): expected 1 child, got ${this.children.length}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const child = this.children[0];
|
|
91
|
-
|
|
92
|
-
// If child is a file WorkFile, use its absolute path directly
|
|
93
|
-
if (child.op === "file" && child.config.absPath) {
|
|
94
|
-
const entry = child.config.absPath;
|
|
95
|
-
|
|
96
|
-
const result = esbuild.buildSync({
|
|
97
|
-
entryPoints: [entry],
|
|
98
|
-
bundle: true,
|
|
99
|
-
minify: true,
|
|
100
|
-
sourcemap: true,
|
|
101
|
-
format: "esm",
|
|
102
|
-
target: "esnext",
|
|
103
|
-
write: false
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
if (result.errors?.length) {
|
|
107
|
-
throw new Error("Build failed:\n" + result.errors.map(e => e.text).join("\n"));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return result.outputFiles[0].text;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Otherwise compile from stdin
|
|
114
|
-
const srcText = child.execute();
|
|
115
|
-
|
|
116
|
-
const result = esbuild.buildSync({
|
|
117
|
-
stdin: {
|
|
118
|
-
contents: srcText,
|
|
119
|
-
resolveDir: process.cwd(),
|
|
120
|
-
sourcefile: "input.ts"
|
|
121
|
-
},
|
|
122
|
-
bundle: true,
|
|
123
|
-
minify: true,
|
|
124
|
-
sourcemap: true,
|
|
125
|
-
format: "esm",
|
|
126
|
-
target: "esnext",
|
|
127
|
-
write: false
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
if (result.errors?.length) {
|
|
131
|
-
throw new Error("Build failed:\n" + result.errors.map(e => e.text).join("\n"));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return result.outputFiles[0].text;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ----------------------------------------------
|
|
138
|
-
// Unknown op
|
|
139
|
-
// ----------------------------------------------
|
|
140
|
-
default:
|
|
141
|
-
throw new Error(`WorkFile.execute(): unknown op "${this.op}"`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// --------------------------------------------------
|
|
146
|
-
// save(): write output to disk
|
|
147
|
-
// --------------------------------------------------
|
|
148
|
-
save(target) {
|
|
149
|
-
if (!target) {
|
|
150
|
-
throw new Error("WorkFile.save(): target filename required");
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const abs = assertDestWrite(target);
|
|
154
|
-
const out = this.execute();
|
|
155
|
-
|
|
156
|
-
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
157
|
-
fs.writeFileSync(abs, out, "utf8");
|
|
158
|
-
|
|
159
|
-
console.log(`Saved: ${abs}`);
|
|
160
|
-
return abs;
|
|
161
|
-
}
|
|
162
|
-
}
|
/package/{dist → src}/init.js
RENAMED
|
File without changes
|