brepjs-cad 0.1.0 → 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.
- package/CHANGELOG.md +23 -0
- package/dist/brepjs-cad.cjs +1 -1
- package/dist/brepjs-cad.js +1 -1
- package/dist/cli/main.cjs +60 -53
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +61 -55
- package/dist/cli/watch.d.ts +0 -5
- package/dist/{diff-ByiVwVrr.js → diff-Bi3sMI-Z.js} +59 -26
- package/dist/{diff-4UNdqx4k.cjs → diff-DJSNDa-j.cjs} +0 -0
- package/dist/disposeShape.d.ts +0 -5
- package/dist/snapshot/registry.cjs +1 -1
- package/dist/snapshot/registry.js +1 -1
- package/dist/snapshot/static.cjs +3 -2
- package/dist/snapshot/static.js +3 -2
- package/dist/verify/report.d.ts +0 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1](https://github.com/andymai/brepjs/compare/brepjs-cad-v0.2.0...brepjs-cad-v0.2.1) (2026-06-04)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **brepjs-cad:** load .ts parts via native type-stripping ([#1207](https://github.com/andymai/brepjs/issues/1207)) ([198078b](https://github.com/andymai/brepjs/commit/198078becf570614c0cbf61537714fc94c2de43a))
|
|
9
|
+
|
|
10
|
+
## [0.2.0](https://github.com/andymai/brepjs/compare/brepjs-cad-v0.1.0...brepjs-cad-v0.2.0) (2026-06-04)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **brepjs-cad:** CLI subcommands + verify hints + gridfinity examples + eval harness ([#1204](https://github.com/andymai/brepjs/issues/1204)) ([4d57198](https://github.com/andymai/brepjs/commit/4d5719874b5f5e685a4f909fd2d2363c0331770b))
|
|
16
|
+
* **brepjs-cad:** rename from brepjs-agent + make npm-publishable (publish held) ([#1201](https://github.com/andymai/brepjs/issues/1201)) ([630bbba](https://github.com/andymai/brepjs/commit/630bbbab4885604bd4d5fb2148584a6572c8d99c))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **brepjs-cad:** run CLI via bin symlink + quality pass ([#1206](https://github.com/andymai/brepjs/issues/1206)) ([ac5b1fe](https://github.com/andymai/brepjs/commit/ac5b1feee3c5b424c37716ca06c397f7898838f1))
|
|
22
|
+
* **opencascade:** prevent LTO stripping of custom bindings ([#666](https://github.com/andymai/brepjs/issues/666)) ([977dd75](https://github.com/andymai/brepjs/commit/977dd757e162d6fa47152b14aa31bac4edd9ae82))
|
|
23
|
+
|
|
24
|
+
## Changelog
|
package/dist/brepjs-cad.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_diff = require("./diff-
|
|
2
|
+
const require_diff = require("./diff-DJSNDa-j.cjs");
|
|
3
3
|
exports.emptyReport = require_diff.emptyReport;
|
|
4
4
|
exports.runChecks = require_diff.runChecks;
|
|
5
5
|
exports.runDiff = require_diff.runDiff;
|
package/dist/brepjs-cad.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as emptyReport, i as runChecks, n as runMeasure, r as runPart,
|
|
1
|
+
import { a as emptyReport, c as serializeReport, i as runChecks, n as runMeasure, r as runPart, t as runDiff } from "./diff-Bi3sMI-Z.js";
|
|
2
2
|
export { emptyReport, runChecks, runDiff, runMeasure, runPart, serializeReport };
|
package/dist/cli/main.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_diff = require("../diff-
|
|
3
|
+
const require_diff = require("../diff-DJSNDa-j.cjs");
|
|
4
4
|
let brepjs = require("brepjs");
|
|
5
|
+
let node_url = require("node:url");
|
|
5
6
|
let commander = require("commander");
|
|
6
7
|
let node_fs = require("node:fs");
|
|
7
8
|
let node_path = require("node:path");
|
|
8
9
|
let node_os = require("node:os");
|
|
9
|
-
let node_url = require("node:url");
|
|
10
10
|
//#region src/cli/scaffold.ts
|
|
11
11
|
function partTemplate(name) {
|
|
12
12
|
return `import { box, cut, unwrap } from 'brepjs';
|
|
@@ -97,11 +97,6 @@ function scaffoldPart(name, dir) {
|
|
|
97
97
|
files
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Wraps a handler so bursts of rapid calls collapse into a single trailing
|
|
102
|
-
* invocation after `delayMs` of quiet — fs.watch fires twice per save on many
|
|
103
|
-
* platforms, so the model is re-run once rather than per raw event.
|
|
104
|
-
*/
|
|
105
100
|
function debounce(fn, delayMs = 150) {
|
|
106
101
|
let timer;
|
|
107
102
|
const cancel = () => {
|
|
@@ -124,11 +119,6 @@ function debounce(fn, delayMs = 150) {
|
|
|
124
119
|
}
|
|
125
120
|
//#endregion
|
|
126
121
|
//#region src/disposeShape.ts
|
|
127
|
-
/**
|
|
128
|
-
* Release a live WASM-backed kernel shape handle returned by `runPart`.
|
|
129
|
-
* No-op for null/undefined or shapes without a disposer, so callers can pass
|
|
130
|
-
* `result.shape` unconditionally. WASM memory accumulates without this.
|
|
131
|
-
*/
|
|
132
122
|
function disposeShape(shape) {
|
|
133
123
|
const disposer = shape?.[Symbol.dispose];
|
|
134
124
|
if (typeof disposer === "function") disposer.call(shape);
|
|
@@ -139,7 +129,6 @@ function stem(file) {
|
|
|
139
129
|
return (0, node_path.basename)(file).replace(/\.brep\.ts$/, "").replace(/\.ts$/, "");
|
|
140
130
|
}
|
|
141
131
|
async function exportPart(modulePath, formats, outDir) {
|
|
142
|
-
const wantStl = Boolean(formats.stl);
|
|
143
132
|
const { shape, report, step, glb } = await require_diff.runPart(modulePath, {
|
|
144
133
|
step: Boolean(formats.step),
|
|
145
134
|
glb: Boolean(formats.glb)
|
|
@@ -148,34 +137,38 @@ async function exportPart(modulePath, formats, outDir) {
|
|
|
148
137
|
const written = [];
|
|
149
138
|
if (!(require_diff.reportOk(report) && shape !== null)) {
|
|
150
139
|
disposeShape(shape);
|
|
140
|
+
const failures = report.errorInfos.map((e) => e.message);
|
|
151
141
|
return {
|
|
152
142
|
ok: false,
|
|
153
143
|
report,
|
|
154
144
|
written,
|
|
155
|
-
errors: report.errors
|
|
145
|
+
errors: failures.length > 0 ? failures : report.errors
|
|
156
146
|
};
|
|
157
147
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
} else errors.push("STEP export produced no data");
|
|
165
|
-
if (formats.glb) if (glb) {
|
|
166
|
-
const p = (0, node_path.join)(outDir, `${base}.glb`);
|
|
167
|
-
(0, node_fs.writeFileSync)(p, Buffer.from(glb));
|
|
168
|
-
written.push(p);
|
|
169
|
-
} else errors.push("GLB export produced no data");
|
|
170
|
-
if (wantStl) {
|
|
171
|
-
const r = (0, brepjs.exportSTL)(shape);
|
|
172
|
-
if ((0, brepjs.isOk)(r)) {
|
|
173
|
-
const p = (0, node_path.join)(outDir, `${base}.stl`);
|
|
174
|
-
(0, node_fs.writeFileSync)(p, Buffer.from(await r.value.arrayBuffer()));
|
|
148
|
+
try {
|
|
149
|
+
if (!(0, node_fs.existsSync)(outDir)) (0, node_fs.mkdirSync)(outDir, { recursive: true });
|
|
150
|
+
const base = stem(modulePath);
|
|
151
|
+
if (formats.step) if (step) {
|
|
152
|
+
const p = (0, node_path.join)(outDir, `${base}.step`);
|
|
153
|
+
(0, node_fs.writeFileSync)(p, Buffer.from(step));
|
|
175
154
|
written.push(p);
|
|
176
|
-
} else errors.push(
|
|
155
|
+
} else errors.push("STEP export produced no data");
|
|
156
|
+
if (formats.glb) if (glb) {
|
|
157
|
+
const p = (0, node_path.join)(outDir, `${base}.glb`);
|
|
158
|
+
(0, node_fs.writeFileSync)(p, Buffer.from(glb));
|
|
159
|
+
written.push(p);
|
|
160
|
+
} else errors.push("GLB export produced no data");
|
|
161
|
+
if (formats.stl) {
|
|
162
|
+
const r = (0, brepjs.exportSTL)(shape);
|
|
163
|
+
if ((0, brepjs.isOk)(r)) {
|
|
164
|
+
const p = (0, node_path.join)(outDir, `${base}.stl`);
|
|
165
|
+
(0, node_fs.writeFileSync)(p, Buffer.from(await r.value.arrayBuffer()));
|
|
166
|
+
written.push(p);
|
|
167
|
+
} else errors.push(`STL export: ${r.error.message}`);
|
|
168
|
+
}
|
|
169
|
+
} finally {
|
|
170
|
+
disposeShape(shape);
|
|
177
171
|
}
|
|
178
|
-
disposeShape(shape);
|
|
179
172
|
return {
|
|
180
173
|
ok: errors.length === 0,
|
|
181
174
|
report,
|
|
@@ -201,32 +194,37 @@ var program = new commander.Command();
|
|
|
201
194
|
program.name("brepjs");
|
|
202
195
|
program.command("verify", { isDefault: true }).argument("<file>", "path to a .brep.ts module with a default-exported part function").option("--step <out>", "write the primary STEP artifact to this path").option("--glb <out>", "write a derived GLB preview to this path").option("--json <out>", "write the JSON report to this path").option("--snapshot <dir>", "render iso/front/top/right PNGs to this dir (requires built viewer)").option("--serve", "after verifying, start a preview server and print a ?dir=&file= deep link (stays running)").action(async (file, opts) => {
|
|
203
196
|
const wantStep = Boolean(opts.step) || Boolean(opts.snapshot) || Boolean(opts.serve);
|
|
204
|
-
const { report, step, glb } = await require_diff.runPart((0, node_path.resolve)(file), {
|
|
197
|
+
const { report, step, glb, shape } = await require_diff.runPart((0, node_path.resolve)(file), {
|
|
205
198
|
step: wantStep,
|
|
206
199
|
glb: Boolean(opts.glb)
|
|
207
200
|
});
|
|
208
|
-
const json = require_diff.serializeReport(report);
|
|
209
|
-
if (opts.json) (0, node_fs.writeFileSync)(opts.json, json);
|
|
210
|
-
if (opts.glb && glb) (0, node_fs.writeFileSync)(opts.glb, Buffer.from(glb));
|
|
211
201
|
let stepPath = opts.step;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const shoot = await loadSnapshotShoot();
|
|
218
|
-
if (shoot) {
|
|
219
|
-
const { pngs } = await shoot({
|
|
220
|
-
file: stepPath,
|
|
221
|
-
outDir: opts.snapshot
|
|
222
|
-
});
|
|
223
|
-
for (const p of pngs) process.stderr.write(`snapshot: ${p}\n`);
|
|
202
|
+
try {
|
|
203
|
+
if (opts.glb && glb) (0, node_fs.writeFileSync)(opts.glb, Buffer.from(glb));
|
|
204
|
+
if (wantStep && step) {
|
|
205
|
+
stepPath = opts.step ?? (0, node_path.join)((0, node_os.tmpdir)(), `brepjs-cad-${(0, node_path.basename)(file)}.step`);
|
|
206
|
+
(0, node_fs.writeFileSync)(stepPath, Buffer.from(step));
|
|
224
207
|
}
|
|
208
|
+
if (opts.snapshot && stepPath) {
|
|
209
|
+
const shoot = await loadSnapshotShoot();
|
|
210
|
+
if (shoot) {
|
|
211
|
+
const { pngs } = await shoot({
|
|
212
|
+
file: stepPath,
|
|
213
|
+
outDir: opts.snapshot
|
|
214
|
+
});
|
|
215
|
+
for (const p of pngs) process.stderr.write(`snapshot: ${p}\n`);
|
|
216
|
+
}
|
|
217
|
+
} else if (opts.snapshot) process.stderr.write("snapshot skipped: STEP export produced no artifact\n");
|
|
218
|
+
} catch (e) {
|
|
219
|
+
require_diff.pushError(report, { message: `artifact write failed: ${e.message}` });
|
|
220
|
+
} finally {
|
|
221
|
+
disposeShape(shape);
|
|
225
222
|
}
|
|
223
|
+
const json = require_diff.serializeReport(report);
|
|
224
|
+
if (opts.json) (0, node_fs.writeFileSync)(opts.json, json);
|
|
226
225
|
process.stdout.write(json + "\n");
|
|
227
|
-
|
|
228
|
-
if (
|
|
229
|
-
if (opts.serve && stepPath) {
|
|
226
|
+
if (!require_diff.reportOk(report)) process.exitCode = 1;
|
|
227
|
+
if (Boolean(opts.serve) && stepPath !== void 0 && require_diff.reportOk(report) && stepPath) {
|
|
230
228
|
const { serve } = await Promise.resolve().then(() => require("../snapshot/serve.cjs"));
|
|
231
229
|
const { url } = await serve({ file: stepPath });
|
|
232
230
|
process.stderr.write(`viewer: ${url}\n`);
|
|
@@ -312,6 +310,15 @@ program.command("export").argument("<file>", "path to a .brep.ts module").option
|
|
|
312
310
|
}, null, 2) + "\n");
|
|
313
311
|
if (!result.ok) process.exitCode = 1;
|
|
314
312
|
});
|
|
315
|
-
|
|
313
|
+
function isEntrypoint(argv1, moduleUrl) {
|
|
314
|
+
if (!argv1) return false;
|
|
315
|
+
try {
|
|
316
|
+
return (0, node_fs.realpathSync)(argv1) === (0, node_fs.realpathSync)((0, node_url.fileURLToPath)(moduleUrl));
|
|
317
|
+
} catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (isEntrypoint(process.argv[1], {}.url)) program.parseAsync();
|
|
316
322
|
//#endregion
|
|
323
|
+
exports.isEntrypoint = isEntrypoint;
|
|
317
324
|
exports.loadSnapshotShoot = loadSnapshotShoot;
|
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as runMeasure, o as
|
|
2
|
+
import { c as serializeReport, n as runMeasure, o as pushError, r as runPart, s as reportOk, t as runDiff } from "../diff-Bi3sMI-Z.js";
|
|
3
3
|
import { exportSTL, isOk } from "brepjs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { Command } from "commander";
|
|
5
|
-
import { existsSync, mkdirSync, watch, writeFileSync } from "node:fs";
|
|
6
|
+
import { existsSync, mkdirSync, realpathSync, watch, writeFileSync } from "node:fs";
|
|
6
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
7
8
|
import { tmpdir } from "node:os";
|
|
8
|
-
import { pathToFileURL } from "node:url";
|
|
9
9
|
//#region src/cli/scaffold.ts
|
|
10
10
|
function partTemplate(name) {
|
|
11
11
|
return `import { box, cut, unwrap } from 'brepjs';
|
|
@@ -96,11 +96,6 @@ function scaffoldPart(name, dir) {
|
|
|
96
96
|
files
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Wraps a handler so bursts of rapid calls collapse into a single trailing
|
|
101
|
-
* invocation after `delayMs` of quiet — fs.watch fires twice per save on many
|
|
102
|
-
* platforms, so the model is re-run once rather than per raw event.
|
|
103
|
-
*/
|
|
104
99
|
function debounce(fn, delayMs = 150) {
|
|
105
100
|
let timer;
|
|
106
101
|
const cancel = () => {
|
|
@@ -123,11 +118,6 @@ function debounce(fn, delayMs = 150) {
|
|
|
123
118
|
}
|
|
124
119
|
//#endregion
|
|
125
120
|
//#region src/disposeShape.ts
|
|
126
|
-
/**
|
|
127
|
-
* Release a live WASM-backed kernel shape handle returned by `runPart`.
|
|
128
|
-
* No-op for null/undefined or shapes without a disposer, so callers can pass
|
|
129
|
-
* `result.shape` unconditionally. WASM memory accumulates without this.
|
|
130
|
-
*/
|
|
131
121
|
function disposeShape(shape) {
|
|
132
122
|
const disposer = shape?.[Symbol.dispose];
|
|
133
123
|
if (typeof disposer === "function") disposer.call(shape);
|
|
@@ -138,7 +128,6 @@ function stem(file) {
|
|
|
138
128
|
return basename(file).replace(/\.brep\.ts$/, "").replace(/\.ts$/, "");
|
|
139
129
|
}
|
|
140
130
|
async function exportPart(modulePath, formats, outDir) {
|
|
141
|
-
const wantStl = Boolean(formats.stl);
|
|
142
131
|
const { shape, report, step, glb } = await runPart(modulePath, {
|
|
143
132
|
step: Boolean(formats.step),
|
|
144
133
|
glb: Boolean(formats.glb)
|
|
@@ -147,34 +136,38 @@ async function exportPart(modulePath, formats, outDir) {
|
|
|
147
136
|
const written = [];
|
|
148
137
|
if (!(reportOk(report) && shape !== null)) {
|
|
149
138
|
disposeShape(shape);
|
|
139
|
+
const failures = report.errorInfos.map((e) => e.message);
|
|
150
140
|
return {
|
|
151
141
|
ok: false,
|
|
152
142
|
report,
|
|
153
143
|
written,
|
|
154
|
-
errors: report.errors
|
|
144
|
+
errors: failures.length > 0 ? failures : report.errors
|
|
155
145
|
};
|
|
156
146
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} else errors.push("GLB export produced no data");
|
|
169
|
-
if (wantStl) {
|
|
170
|
-
const r = exportSTL(shape);
|
|
171
|
-
if (isOk(r)) {
|
|
172
|
-
const p = join(outDir, `${base}.stl`);
|
|
173
|
-
writeFileSync(p, Buffer.from(await r.value.arrayBuffer()));
|
|
147
|
+
try {
|
|
148
|
+
if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
|
|
149
|
+
const base = stem(modulePath);
|
|
150
|
+
if (formats.step) if (step) {
|
|
151
|
+
const p = join(outDir, `${base}.step`);
|
|
152
|
+
writeFileSync(p, Buffer.from(step));
|
|
153
|
+
written.push(p);
|
|
154
|
+
} else errors.push("STEP export produced no data");
|
|
155
|
+
if (formats.glb) if (glb) {
|
|
156
|
+
const p = join(outDir, `${base}.glb`);
|
|
157
|
+
writeFileSync(p, Buffer.from(glb));
|
|
174
158
|
written.push(p);
|
|
175
|
-
} else errors.push(
|
|
159
|
+
} else errors.push("GLB export produced no data");
|
|
160
|
+
if (formats.stl) {
|
|
161
|
+
const r = exportSTL(shape);
|
|
162
|
+
if (isOk(r)) {
|
|
163
|
+
const p = join(outDir, `${base}.stl`);
|
|
164
|
+
writeFileSync(p, Buffer.from(await r.value.arrayBuffer()));
|
|
165
|
+
written.push(p);
|
|
166
|
+
} else errors.push(`STL export: ${r.error.message}`);
|
|
167
|
+
}
|
|
168
|
+
} finally {
|
|
169
|
+
disposeShape(shape);
|
|
176
170
|
}
|
|
177
|
-
disposeShape(shape);
|
|
178
171
|
return {
|
|
179
172
|
ok: errors.length === 0,
|
|
180
173
|
report,
|
|
@@ -200,32 +193,37 @@ var program = new Command();
|
|
|
200
193
|
program.name("brepjs");
|
|
201
194
|
program.command("verify", { isDefault: true }).argument("<file>", "path to a .brep.ts module with a default-exported part function").option("--step <out>", "write the primary STEP artifact to this path").option("--glb <out>", "write a derived GLB preview to this path").option("--json <out>", "write the JSON report to this path").option("--snapshot <dir>", "render iso/front/top/right PNGs to this dir (requires built viewer)").option("--serve", "after verifying, start a preview server and print a ?dir=&file= deep link (stays running)").action(async (file, opts) => {
|
|
202
195
|
const wantStep = Boolean(opts.step) || Boolean(opts.snapshot) || Boolean(opts.serve);
|
|
203
|
-
const { report, step, glb } = await runPart(resolve(file), {
|
|
196
|
+
const { report, step, glb, shape } = await runPart(resolve(file), {
|
|
204
197
|
step: wantStep,
|
|
205
198
|
glb: Boolean(opts.glb)
|
|
206
199
|
});
|
|
207
|
-
const json = serializeReport(report);
|
|
208
|
-
if (opts.json) writeFileSync(opts.json, json);
|
|
209
|
-
if (opts.glb && glb) writeFileSync(opts.glb, Buffer.from(glb));
|
|
210
200
|
let stepPath = opts.step;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const shoot = await loadSnapshotShoot();
|
|
217
|
-
if (shoot) {
|
|
218
|
-
const { pngs } = await shoot({
|
|
219
|
-
file: stepPath,
|
|
220
|
-
outDir: opts.snapshot
|
|
221
|
-
});
|
|
222
|
-
for (const p of pngs) process.stderr.write(`snapshot: ${p}\n`);
|
|
201
|
+
try {
|
|
202
|
+
if (opts.glb && glb) writeFileSync(opts.glb, Buffer.from(glb));
|
|
203
|
+
if (wantStep && step) {
|
|
204
|
+
stepPath = opts.step ?? join(tmpdir(), `brepjs-cad-${basename(file)}.step`);
|
|
205
|
+
writeFileSync(stepPath, Buffer.from(step));
|
|
223
206
|
}
|
|
207
|
+
if (opts.snapshot && stepPath) {
|
|
208
|
+
const shoot = await loadSnapshotShoot();
|
|
209
|
+
if (shoot) {
|
|
210
|
+
const { pngs } = await shoot({
|
|
211
|
+
file: stepPath,
|
|
212
|
+
outDir: opts.snapshot
|
|
213
|
+
});
|
|
214
|
+
for (const p of pngs) process.stderr.write(`snapshot: ${p}\n`);
|
|
215
|
+
}
|
|
216
|
+
} else if (opts.snapshot) process.stderr.write("snapshot skipped: STEP export produced no artifact\n");
|
|
217
|
+
} catch (e) {
|
|
218
|
+
pushError(report, { message: `artifact write failed: ${e.message}` });
|
|
219
|
+
} finally {
|
|
220
|
+
disposeShape(shape);
|
|
224
221
|
}
|
|
222
|
+
const json = serializeReport(report);
|
|
223
|
+
if (opts.json) writeFileSync(opts.json, json);
|
|
225
224
|
process.stdout.write(json + "\n");
|
|
226
|
-
|
|
227
|
-
if (
|
|
228
|
-
if (opts.serve && stepPath) {
|
|
225
|
+
if (!reportOk(report)) process.exitCode = 1;
|
|
226
|
+
if (Boolean(opts.serve) && stepPath !== void 0 && reportOk(report) && stepPath) {
|
|
229
227
|
const { serve } = await import("../snapshot/serve.js");
|
|
230
228
|
const { url } = await serve({ file: stepPath });
|
|
231
229
|
process.stderr.write(`viewer: ${url}\n`);
|
|
@@ -311,6 +309,14 @@ program.command("export").argument("<file>", "path to a .brep.ts module").option
|
|
|
311
309
|
}, null, 2) + "\n");
|
|
312
310
|
if (!result.ok) process.exitCode = 1;
|
|
313
311
|
});
|
|
314
|
-
|
|
312
|
+
function isEntrypoint(argv1, moduleUrl) {
|
|
313
|
+
if (!argv1) return false;
|
|
314
|
+
try {
|
|
315
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
316
|
+
} catch {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (isEntrypoint(process.argv[1], import.meta.url)) program.parseAsync();
|
|
315
321
|
//#endregion
|
|
316
|
-
export { loadSnapshotShoot };
|
|
322
|
+
export { isEntrypoint, loadSnapshotShoot };
|
package/dist/cli/watch.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
export declare const DEFAULT_DEBOUNCE_MS = 150;
|
|
2
|
-
/**
|
|
3
|
-
* Wraps a handler so bursts of rapid calls collapse into a single trailing
|
|
4
|
-
* invocation after `delayMs` of quiet — fs.watch fires twice per save on many
|
|
5
|
-
* platforms, so the model is re-run once rather than per raw event.
|
|
6
|
-
*/
|
|
7
2
|
export declare function debounce(fn: () => void | Promise<void>, delayMs?: number): {
|
|
8
3
|
trigger: () => void;
|
|
9
4
|
cancel: () => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cut, exportGlb, exportSTEP, getBounds, init, isCompSolid, isCompound, isEdge, isFace, isOk, isShape3D, isShell, isSolid, isVertex, isWire, measureArea, measureDistance, measureLength, measureVolume, mesh, validSolid } from "brepjs";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
2
3
|
//#region src/verify/report.ts
|
|
3
4
|
function emptyReport() {
|
|
4
5
|
return {
|
|
@@ -10,7 +11,6 @@ function emptyReport() {
|
|
|
10
11
|
hints: []
|
|
11
12
|
};
|
|
12
13
|
}
|
|
13
|
-
/** Record a failure on the report, keeping the flat `errors` string list and structured `errorInfos` in sync. */
|
|
14
14
|
function pushError(r, info) {
|
|
15
15
|
r.errors.push(info.message);
|
|
16
16
|
r.errorInfos.push(info);
|
|
@@ -238,6 +238,15 @@ function runChecks(shape) {
|
|
|
238
238
|
}
|
|
239
239
|
//#endregion
|
|
240
240
|
//#region src/verify/runPart.ts
|
|
241
|
+
async function loadPart(modulePath) {
|
|
242
|
+
try {
|
|
243
|
+
return await import(pathToFileURL(modulePath).href);
|
|
244
|
+
} catch (e) {
|
|
245
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
246
|
+
if (/\.[mc]?tsx?$/.test(modulePath) && /import statement|file extension/i.test(msg)) throw new Error(`cannot load TypeScript part "${modulePath}": author parts in an ESM project (set "type": "module" in package.json) or rename the file to .mts. (${msg})`, { cause: e });
|
|
247
|
+
throw e;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
241
250
|
function isResult(v) {
|
|
242
251
|
return typeof v === "object" && v !== null && "ok" in v && typeof v.ok === "boolean";
|
|
243
252
|
}
|
|
@@ -246,7 +255,6 @@ function isBrepError(v) {
|
|
|
246
255
|
const rec = v;
|
|
247
256
|
return typeof rec["code"] === "string" && typeof rec["message"] === "string";
|
|
248
257
|
}
|
|
249
|
-
/** Pull structured `{ message, code, suggestion }` out of a `BrepError`, a thrown `Error`, or anything. */
|
|
250
258
|
function toErrorInfo(prefix, e) {
|
|
251
259
|
if (isBrepError(e)) return {
|
|
252
260
|
message: `${prefix}: ${e.message}`,
|
|
@@ -261,11 +269,19 @@ function finalize(result) {
|
|
|
261
269
|
return result;
|
|
262
270
|
}
|
|
263
271
|
async function runPart(modulePath, opts = {}) {
|
|
264
|
-
await init();
|
|
265
272
|
const report = emptyReport();
|
|
273
|
+
try {
|
|
274
|
+
await init();
|
|
275
|
+
} catch (e) {
|
|
276
|
+
pushError(report, toErrorInfo("kernel init failed", e));
|
|
277
|
+
return finalize({
|
|
278
|
+
shape: null,
|
|
279
|
+
report
|
|
280
|
+
});
|
|
281
|
+
}
|
|
266
282
|
let mod;
|
|
267
283
|
try {
|
|
268
|
-
mod = await
|
|
284
|
+
mod = await loadPart(modulePath);
|
|
269
285
|
} catch (e) {
|
|
270
286
|
pushError(report, toErrorInfo("import failed", e));
|
|
271
287
|
return finalize({
|
|
@@ -291,15 +307,16 @@ async function runPart(modulePath, opts = {}) {
|
|
|
291
307
|
});
|
|
292
308
|
}
|
|
293
309
|
let shape;
|
|
294
|
-
if (isResult(out))
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
if (isResult(out)) {
|
|
311
|
+
if (!isOk(out)) {
|
|
312
|
+
pushError(report, toErrorInfo("part returned Err", out.error));
|
|
313
|
+
return finalize({
|
|
314
|
+
shape: null,
|
|
315
|
+
report
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
shape = out.value;
|
|
319
|
+
} else shape = out;
|
|
303
320
|
if (!shape) {
|
|
304
321
|
pushError(report, { message: "part produced no shape" });
|
|
305
322
|
return finalize({
|
|
@@ -449,6 +466,30 @@ function areaOf(shape, errors) {
|
|
|
449
466
|
errors.push(`measureArea: ${a.error.message}`);
|
|
450
467
|
return 0;
|
|
451
468
|
}
|
|
469
|
+
function boundsDelta(a, b, errors) {
|
|
470
|
+
try {
|
|
471
|
+
const ba = getBounds(a);
|
|
472
|
+
const bb = getBounds(b);
|
|
473
|
+
return {
|
|
474
|
+
xMin: bb.xMin - ba.xMin,
|
|
475
|
+
xMax: bb.xMax - ba.xMax,
|
|
476
|
+
yMin: bb.yMin - ba.yMin,
|
|
477
|
+
yMax: bb.yMax - ba.yMax,
|
|
478
|
+
zMin: bb.zMin - ba.zMin,
|
|
479
|
+
zMax: bb.zMax - ba.zMax
|
|
480
|
+
};
|
|
481
|
+
} catch (e) {
|
|
482
|
+
errors.push(`getBounds: ${e.message}`);
|
|
483
|
+
return {
|
|
484
|
+
xMin: 0,
|
|
485
|
+
xMax: 0,
|
|
486
|
+
yMin: 0,
|
|
487
|
+
yMax: 0,
|
|
488
|
+
zMin: 0,
|
|
489
|
+
zMax: 0
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
}
|
|
452
493
|
function cutVolume(x, y, errors) {
|
|
453
494
|
try {
|
|
454
495
|
var _usingCtx$1 = _usingCtx();
|
|
@@ -470,21 +511,13 @@ async function runDiff(aPath, bPath) {
|
|
|
470
511
|
const errors = [];
|
|
471
512
|
const a = await runPart(aPath);
|
|
472
513
|
errors.push(...a.report.errors);
|
|
514
|
+
if (!a.shape) return emptyDiff(errors);
|
|
515
|
+
const sa = _usingCtx3.u(a.shape);
|
|
473
516
|
const b = await runPart(bPath);
|
|
474
517
|
errors.push(...b.report.errors);
|
|
475
|
-
if (!
|
|
476
|
-
const sa = _usingCtx3.u(a.shape);
|
|
518
|
+
if (!b.shape) return emptyDiff(errors);
|
|
477
519
|
const sb = _usingCtx3.u(b.shape);
|
|
478
|
-
const
|
|
479
|
-
const bb = getBounds(sb);
|
|
480
|
-
const bboxDelta = {
|
|
481
|
-
xMin: bb.xMin - ba.xMin,
|
|
482
|
-
xMax: bb.xMax - ba.xMax,
|
|
483
|
-
yMin: bb.yMin - ba.yMin,
|
|
484
|
-
yMax: bb.yMax - ba.yMax,
|
|
485
|
-
zMin: bb.zMin - ba.zMin,
|
|
486
|
-
zMax: bb.zMax - ba.zMax
|
|
487
|
-
};
|
|
520
|
+
const bboxDelta = boundsDelta(sa, sb, errors);
|
|
488
521
|
const areaDelta = areaOf(sb, errors) - areaOf(sa, errors);
|
|
489
522
|
let volumeDelta = 0;
|
|
490
523
|
let symmetricDifferenceVolume = 0;
|
|
@@ -506,4 +539,4 @@ async function runDiff(aPath, bPath) {
|
|
|
506
539
|
}
|
|
507
540
|
}
|
|
508
541
|
//#endregion
|
|
509
|
-
export { emptyReport as a, runChecks as i, runMeasure as n,
|
|
542
|
+
export { emptyReport as a, serializeReport as c, runChecks as i, runMeasure as n, pushError as o, runPart as r, reportOk as s, runDiff as t };
|
|
Binary file
|
package/dist/disposeShape.d.ts
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Release a live WASM-backed kernel shape handle returned by `runPart`.
|
|
3
|
-
* No-op for null/undefined or shapes without a disposer, so callers can pass
|
|
4
|
-
* `result.shape` unconditionally. WASM memory accumulates without this.
|
|
5
|
-
*/
|
|
6
1
|
export declare function disposeShape(shape: unknown): void;
|
|
@@ -31,7 +31,7 @@ async function acquireServer(opts = {}) {
|
|
|
31
31
|
server = await require_snapshot_static.startStaticServer({ port });
|
|
32
32
|
break;
|
|
33
33
|
} catch {}
|
|
34
|
-
if (!server) throw new Error(`no free port in ${ports[0]}..${ports
|
|
34
|
+
if (!server) throw new Error(`no free port in ${ports[0]}..${ports.at(-1)}`);
|
|
35
35
|
const timer = setTimeout(() => void server?.close(), opts.shutdownAfterMs ?? 432e5);
|
|
36
36
|
timer.unref();
|
|
37
37
|
const started = server;
|
|
@@ -30,7 +30,7 @@ async function acquireServer(opts = {}) {
|
|
|
30
30
|
server = await startStaticServer({ port });
|
|
31
31
|
break;
|
|
32
32
|
} catch {}
|
|
33
|
-
if (!server) throw new Error(`no free port in ${ports[0]}..${ports
|
|
33
|
+
if (!server) throw new Error(`no free port in ${ports[0]}..${ports.at(-1)}`);
|
|
34
34
|
const timer = setTimeout(() => void server?.close(), opts.shutdownAfterMs ?? 432e5);
|
|
35
35
|
timer.unref();
|
|
36
36
|
const started = server;
|
package/dist/snapshot/static.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let node_url = require("node:url");
|
|
2
3
|
let node_fs = require("node:fs");
|
|
3
4
|
let node_path = require("node:path");
|
|
4
|
-
let node_url = require("node:url");
|
|
5
5
|
let node_http = require("node:http");
|
|
6
6
|
let node_fs_promises = require("node:fs/promises");
|
|
7
7
|
//#region src/snapshot/static.ts
|
|
@@ -38,7 +38,8 @@ async function sendFile(res, absPath) {
|
|
|
38
38
|
}
|
|
39
39
|
function safeJoin(root, rel) {
|
|
40
40
|
const abs = (0, node_path.resolve)(root, (0, node_path.normalize)(decodeURIComponent(rel.replace(/^\/+/, ""))));
|
|
41
|
-
|
|
41
|
+
if (abs !== root && !abs.startsWith(root + node_path.sep)) return null;
|
|
42
|
+
return abs;
|
|
42
43
|
}
|
|
43
44
|
async function handle(req, res, port) {
|
|
44
45
|
const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
|
package/dist/snapshot/static.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
1
2
|
import { createReadStream } from "node:fs";
|
|
2
3
|
import { dirname, extname, join, normalize, resolve, sep } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { createServer } from "node:http";
|
|
5
5
|
import { stat } from "node:fs/promises";
|
|
6
6
|
//#region src/snapshot/static.ts
|
|
@@ -37,7 +37,8 @@ async function sendFile(res, absPath) {
|
|
|
37
37
|
}
|
|
38
38
|
function safeJoin(root, rel) {
|
|
39
39
|
const abs = resolve(root, normalize(decodeURIComponent(rel.replace(/^\/+/, ""))));
|
|
40
|
-
|
|
40
|
+
if (abs !== root && !abs.startsWith(root + sep)) return null;
|
|
41
|
+
return abs;
|
|
41
42
|
}
|
|
42
43
|
async function handle(req, res, port) {
|
|
43
44
|
const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
|
package/dist/verify/report.d.ts
CHANGED
|
@@ -53,7 +53,6 @@ export interface DiffReport {
|
|
|
53
53
|
errors: string[];
|
|
54
54
|
}
|
|
55
55
|
export declare function emptyReport(): VerifyReport;
|
|
56
|
-
/** Record a failure on the report, keeping the flat `errors` string list and structured `errorInfos` in sync. */
|
|
57
56
|
export declare function pushError(r: VerifyReport, info: ErrorInfo): void;
|
|
58
57
|
export declare function reportOk(r: VerifyReport): boolean;
|
|
59
58
|
/** Synthetic code attached to validity-check failures (validSolid returns a plain string error). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brepjs-cad",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Agent skill + verify/preview tooling for authoring parametric brepjs CAD code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"lint": "eslint src tests viewer bench",
|
|
46
46
|
"test": "vitest run",
|
|
47
47
|
"eval": "tsx bench/run.ts",
|
|
48
|
+
"smoke": "node dist/cli/main.js verify tests/fixtures/validBox.brep.ts | node -e \"const r=JSON.parse(require('fs').readFileSync(0,'utf8'));if(r.ok!==true||!(r.measurements.volume>0))process.exit(1)\"",
|
|
48
49
|
"prepack": "npm run build"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|