create-brepjs 0.1.0
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/bin/create-brepjs.mjs +67 -0
- package/package.json +31 -0
- package/templates/README.md +13 -0
- package/templates/gitignore +3 -0
- package/templates/package.json.tpl +18 -0
- package/templates/src/main.ts +40 -0
- package/templates/tsconfig.json +12 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* create-brepjs — scaffold a brepjs + brepjs-families project.
|
|
4
|
+
*
|
|
5
|
+
* npm create brepjs@latest my-project
|
|
6
|
+
*
|
|
7
|
+
* Copies the template (package.json, tsconfig, a working src/main.ts) into
|
|
8
|
+
* the target directory and prints the copy-in next steps (`npx brepjs add`).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { cp, mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { join, dirname, resolve } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import process from 'node:process';
|
|
15
|
+
|
|
16
|
+
const TEMPLATES = join(dirname(fileURLToPath(import.meta.url)), '../templates');
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
const name = process.argv[2] ?? 'brepjs-app';
|
|
20
|
+
// A relative path is allowed; its basename becomes the package name. No
|
|
21
|
+
// traversal, no absolute paths, no scopes (a scope is not a directory).
|
|
22
|
+
const segments = name.split('/');
|
|
23
|
+
const base = segments[segments.length - 1] ?? '';
|
|
24
|
+
const valid =
|
|
25
|
+
!name.startsWith('/') &&
|
|
26
|
+
!name.endsWith('/') &&
|
|
27
|
+
segments.every((s) => /^[a-z0-9][a-z0-9-_.]*$/.test(s) && s !== '.' && s !== '..');
|
|
28
|
+
if (!valid) {
|
|
29
|
+
console.error(
|
|
30
|
+
`create-brepjs: invalid project name '${name}' (relative path ending in a lowercase package name; no '..', no scopes)`
|
|
31
|
+
);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const target = resolve(name);
|
|
36
|
+
const existing = await readdir(target).catch(() => null);
|
|
37
|
+
if (existing !== null && existing.length > 0) {
|
|
38
|
+
console.error(`create-brepjs: target directory is not empty: ${target}`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await mkdir(target, { recursive: true });
|
|
44
|
+
await cp(TEMPLATES, target, { recursive: true });
|
|
45
|
+
// npm mangles nested package.json files in published packages; the template
|
|
46
|
+
// ships under a neutral name and is renamed on scaffold.
|
|
47
|
+
await rename(join(target, 'package.json.tpl'), join(target, 'package.json'));
|
|
48
|
+
// npm drops .gitignore from published tarballs; ship under a neutral name.
|
|
49
|
+
await rename(join(target, 'gitignore'), join(target, '.gitignore'));
|
|
50
|
+
const pkgPath = join(target, 'package.json');
|
|
51
|
+
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
|
|
52
|
+
pkg.name = base;
|
|
53
|
+
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
54
|
+
|
|
55
|
+
console.warn(`Scaffolded ${target}`);
|
|
56
|
+
console.warn('');
|
|
57
|
+
console.warn('Next steps:');
|
|
58
|
+
console.warn(` cd ${name}`);
|
|
59
|
+
console.warn(' npm install');
|
|
60
|
+
console.warn(' npx brepjs add room storey slab # copy in starter families');
|
|
61
|
+
console.warn(' npx tsx src/main.ts');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
main().catch((err) => {
|
|
65
|
+
console.error(`create-brepjs: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-brepjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold a brepjs + brepjs-families project (npm create brepjs)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cad",
|
|
7
|
+
"bim",
|
|
8
|
+
"create",
|
|
9
|
+
"scaffold"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/andymai/brepjs.git",
|
|
16
|
+
"directory": "packages/create-brepjs"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"create-brepjs": "bin/create-brepjs.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin",
|
|
26
|
+
"templates"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# brepjs-app
|
|
2
|
+
|
|
3
|
+
A [brepjs](https://github.com/andymai/brepjs) + brepjs-families project.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install
|
|
7
|
+
npm start # evaluate src/main.ts and print mesh stats
|
|
8
|
+
npx brepjs add room storey slab # copy starter families into src/families/
|
|
9
|
+
npx brepjs diff room # compare a copied family against the registry
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Families copied in by `brepjs add` are yours: edit them freely. `brepjs diff`
|
|
13
|
+
compares your copies against the registry when you want to see upstream drift.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "brepjs-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "tsx src/main.ts",
|
|
7
|
+
"typecheck": "tsc --noEmit"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"brepjs": "^18.0.0",
|
|
11
|
+
"brepjs-families": "^0.1.0",
|
|
12
|
+
"zod": "^4.0.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"tsx": "^4.0.0",
|
|
16
|
+
"typescript": "^5.0.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal brepjs-families model: a wall with a doorway, resolved to an
|
|
3
|
+
* element tree and materialized as a mesh. Run with `npm start`.
|
|
4
|
+
*
|
|
5
|
+
* Copy in richer starter families with `npx brepjs add room storey slab` —
|
|
6
|
+
* they land in src/families/ as code you own.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import 'brepjs/quick';
|
|
10
|
+
import { csg } from 'brepjs';
|
|
11
|
+
import { family, el, resolve, evaluateModel, tTranslate } from 'brepjs-families';
|
|
12
|
+
|
|
13
|
+
const Doorway = family<{ readonly width: number; readonly height: number; readonly at: number }>(
|
|
14
|
+
'Doorway',
|
|
15
|
+
(p) =>
|
|
16
|
+
el('Box', {
|
|
17
|
+
size: [p.width, 300, p.height],
|
|
18
|
+
transform: [tTranslate([p.at, 0, 0])],
|
|
19
|
+
}),
|
|
20
|
+
{ role: 'fill' }
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const Wall = family<{ readonly length: number; readonly height: number }>('Wall', (p) =>
|
|
24
|
+
el('Box', {
|
|
25
|
+
size: [p.length, 200, p.height],
|
|
26
|
+
voids: [Doorway({ key: 'door', width: 1000, height: 2100, at: 1500 })],
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
using evaluator = new csg.Evaluator();
|
|
31
|
+
const model = evaluateModel(resolve(Wall({ key: 'wall-1', length: 4000, height: 2700 })), evaluator);
|
|
32
|
+
|
|
33
|
+
for (const [keyPath, node] of model.byKeyPath) {
|
|
34
|
+
if (node.mesh.ok) {
|
|
35
|
+
const triangles = node.mesh.value.triangles.length / 3;
|
|
36
|
+
console.log(`${keyPath}: ${triangles} triangles`);
|
|
37
|
+
} else {
|
|
38
|
+
console.error(`${keyPath}: ${node.mesh.error.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|