@tomvandig/mosaic 0.1.0 → 0.2.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/README.md +6 -6
- package/dist/mosaic.cjs +195 -121
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,9 @@ incremental collaboration on geometric, structured data.
|
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
7
|
npx @tomvandig/mosaic help
|
|
8
|
+
|
|
9
|
+
# convert a glTF model, straight from a URL
|
|
10
|
+
npx @tomvandig/mosaic pack https://tomvandig.github.io/mosaic/dist/docs/models/DamagedHelmet.glb
|
|
8
11
|
```
|
|
9
12
|
|
|
10
13
|
Or install it, and the command is `mosaic`:
|
|
@@ -20,12 +23,9 @@ Needs Node.js 24 or later.
|
|
|
20
23
|
|
|
21
24
|
| Command | |
|
|
22
25
|
| --- | --- |
|
|
23
|
-
| `mosaic pack <input
|
|
24
|
-
| `mosaic gltf <input.gltf\|.glb> [output.mosaic.json] [--stable-ids]` | Convert glTF into
|
|
25
|
-
| `mosaic
|
|
26
|
-
| `mosaic ifc <input.ifc> [output.mosaic.json]` | Convert an IFC model into a source document |
|
|
27
|
-
| `mosaic ifc-pack <input.ifc> [output.tsr]` | Convert an IFC model straight into an archive |
|
|
28
|
-
| `mosaic svg-pack <input.svg> [output.tsr]` | Pack an SVG into an archive of one node |
|
|
26
|
+
| `mosaic pack <input> [output.tsr] [flags]` | Pack into a `.tsr` archive, by extension: a source document (`.json`), glTF (`.gltf`, `.glb`, or a URL), IFC (`.ifc`) or SVG (`.svg`) |
|
|
27
|
+
| `mosaic gltf <input.gltf\|.glb\|url> [output.mosaic.json] [--stable-ids]` | Convert glTF into an editable source document |
|
|
28
|
+
| `mosaic ifc <input.ifc> [output.mosaic.json] [--center] [--no-geometry] [--seed=<text>]` | Convert an IFC model into an editable source document |
|
|
29
29
|
| `mosaic compose <input.tsr\|.duckdb> [output.glb]` | Compose an archive and its imports into a `.glb` |
|
|
30
30
|
| `mosaic serve <database.duckdb> [--port <n>] [--host <name>]` | Serve the Mosaic API, and a viewer, over a database |
|
|
31
31
|
| `mosaic codegen <input_dir> <output_dir> <ts\|cs>` | Generate typed classes from component schemas |
|
package/dist/mosaic.cjs
CHANGED
|
@@ -16242,14 +16242,14 @@ var require_parser = __commonJS({
|
|
|
16242
16242
|
case "scalar":
|
|
16243
16243
|
case "single-quoted-scalar":
|
|
16244
16244
|
case "double-quoted-scalar": {
|
|
16245
|
-
const
|
|
16245
|
+
const fs10 = this.flowScalar(this.type);
|
|
16246
16246
|
if (atNextItem || it.value) {
|
|
16247
|
-
map.items.push({ start, key:
|
|
16247
|
+
map.items.push({ start, key: fs10, sep: [] });
|
|
16248
16248
|
this.onKeyLine = true;
|
|
16249
16249
|
} else if (it.sep) {
|
|
16250
|
-
this.stack.push(
|
|
16250
|
+
this.stack.push(fs10);
|
|
16251
16251
|
} else {
|
|
16252
|
-
Object.assign(it, { key:
|
|
16252
|
+
Object.assign(it, { key: fs10, sep: [] });
|
|
16253
16253
|
this.onKeyLine = true;
|
|
16254
16254
|
}
|
|
16255
16255
|
return;
|
|
@@ -16377,13 +16377,13 @@ var require_parser = __commonJS({
|
|
|
16377
16377
|
case "scalar":
|
|
16378
16378
|
case "single-quoted-scalar":
|
|
16379
16379
|
case "double-quoted-scalar": {
|
|
16380
|
-
const
|
|
16380
|
+
const fs10 = this.flowScalar(this.type);
|
|
16381
16381
|
if (!it || it.value)
|
|
16382
|
-
fc.items.push({ start: [], key:
|
|
16382
|
+
fc.items.push({ start: [], key: fs10, sep: [] });
|
|
16383
16383
|
else if (it.sep)
|
|
16384
|
-
this.stack.push(
|
|
16384
|
+
this.stack.push(fs10);
|
|
16385
16385
|
else
|
|
16386
|
-
Object.assign(it, { key:
|
|
16386
|
+
Object.assign(it, { key: fs10, sep: [] });
|
|
16387
16387
|
return;
|
|
16388
16388
|
}
|
|
16389
16389
|
case "flow-map-end":
|
|
@@ -66259,11 +66259,11 @@ var require_dist4 = __commonJS({
|
|
|
66259
66259
|
// node_modules/is-url/index.js
|
|
66260
66260
|
var require_is_url = __commonJS({
|
|
66261
66261
|
"node_modules/is-url/index.js"(exports2, module2) {
|
|
66262
|
-
module2.exports =
|
|
66262
|
+
module2.exports = isUrl2;
|
|
66263
66263
|
var protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
|
|
66264
66264
|
var localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
|
|
66265
66265
|
var nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;
|
|
66266
|
-
function
|
|
66266
|
+
function isUrl2(string) {
|
|
66267
66267
|
if (typeof string !== "string") {
|
|
66268
66268
|
return false;
|
|
66269
66269
|
}
|
|
@@ -69046,12 +69046,12 @@ var require_lib2 = __commonJS({
|
|
|
69046
69046
|
const dest = new URL$1(destination).protocol;
|
|
69047
69047
|
return orig === dest;
|
|
69048
69048
|
};
|
|
69049
|
-
function
|
|
69050
|
-
if (!
|
|
69049
|
+
function fetch2(url, opts) {
|
|
69050
|
+
if (!fetch2.Promise) {
|
|
69051
69051
|
throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
|
|
69052
69052
|
}
|
|
69053
|
-
Body.Promise =
|
|
69054
|
-
return new
|
|
69053
|
+
Body.Promise = fetch2.Promise;
|
|
69054
|
+
return new fetch2.Promise(function(resolve, reject) {
|
|
69055
69055
|
const request = new Request(url, opts);
|
|
69056
69056
|
const options = getNodeRequestOptions(request);
|
|
69057
69057
|
const send2 = (options.protocol === "https:" ? https : http2).request;
|
|
@@ -69122,7 +69122,7 @@ var require_lib2 = __commonJS({
|
|
|
69122
69122
|
req.on("response", function(res) {
|
|
69123
69123
|
clearTimeout(reqTimeout);
|
|
69124
69124
|
const headers = createHeadersLenient(res.headers);
|
|
69125
|
-
if (
|
|
69125
|
+
if (fetch2.isRedirect(res.statusCode)) {
|
|
69126
69126
|
const location2 = headers.get("Location");
|
|
69127
69127
|
let locationURL = null;
|
|
69128
69128
|
try {
|
|
@@ -69184,7 +69184,7 @@ var require_lib2 = __commonJS({
|
|
|
69184
69184
|
requestOpts.body = void 0;
|
|
69185
69185
|
requestOpts.headers.delete("content-length");
|
|
69186
69186
|
}
|
|
69187
|
-
resolve(
|
|
69187
|
+
resolve(fetch2(new Request(locationURL, requestOpts)));
|
|
69188
69188
|
finalize();
|
|
69189
69189
|
return;
|
|
69190
69190
|
}
|
|
@@ -69276,11 +69276,11 @@ var require_lib2 = __commonJS({
|
|
|
69276
69276
|
stream.end();
|
|
69277
69277
|
}
|
|
69278
69278
|
}
|
|
69279
|
-
|
|
69279
|
+
fetch2.isRedirect = function(code) {
|
|
69280
69280
|
return code === 301 || code === 302 || code === 303 || code === 307 || code === 308;
|
|
69281
69281
|
};
|
|
69282
|
-
|
|
69283
|
-
module2.exports = exports2 =
|
|
69282
|
+
fetch2.Promise = global.Promise;
|
|
69283
|
+
module2.exports = exports2 = fetch2;
|
|
69284
69284
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
69285
69285
|
exports2.default = exports2;
|
|
69286
69286
|
exports2.Headers = Headers;
|
|
@@ -69296,19 +69296,19 @@ var require_node_ponyfill = __commonJS({
|
|
|
69296
69296
|
"node_modules/cross-fetch/dist/node-ponyfill.js"(exports2, module2) {
|
|
69297
69297
|
var nodeFetch = require_lib2();
|
|
69298
69298
|
var realFetch = nodeFetch.default || nodeFetch;
|
|
69299
|
-
var
|
|
69299
|
+
var fetch2 = function(url, options) {
|
|
69300
69300
|
if (/^\/\//.test(url)) {
|
|
69301
69301
|
url = "https:" + url;
|
|
69302
69302
|
}
|
|
69303
69303
|
return realFetch.call(this, url, options);
|
|
69304
69304
|
};
|
|
69305
|
-
|
|
69306
|
-
module2.exports = exports2 =
|
|
69307
|
-
exports2.fetch =
|
|
69305
|
+
fetch2.ponyfill = true;
|
|
69306
|
+
module2.exports = exports2 = fetch2;
|
|
69307
|
+
exports2.fetch = fetch2;
|
|
69308
69308
|
exports2.Headers = nodeFetch.Headers;
|
|
69309
69309
|
exports2.Request = nodeFetch.Request;
|
|
69310
69310
|
exports2.Response = nodeFetch.Response;
|
|
69311
|
-
exports2.default =
|
|
69311
|
+
exports2.default = fetch2;
|
|
69312
69312
|
}
|
|
69313
69313
|
});
|
|
69314
69314
|
|
|
@@ -69319,11 +69319,11 @@ var require_fetch = __commonJS({
|
|
|
69319
69319
|
var _a;
|
|
69320
69320
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
69321
69321
|
exports2.fetch = void 0;
|
|
69322
|
-
var
|
|
69322
|
+
var fetch2;
|
|
69323
69323
|
try {
|
|
69324
|
-
exports2.fetch =
|
|
69324
|
+
exports2.fetch = fetch2 = (_a = global.fetch) !== null && _a !== void 0 ? _a : require_node_ponyfill().default;
|
|
69325
69325
|
} catch (_b) {
|
|
69326
|
-
exports2.fetch =
|
|
69326
|
+
exports2.fetch = fetch2 = require_node_ponyfill().default;
|
|
69327
69327
|
}
|
|
69328
69328
|
}
|
|
69329
69329
|
});
|
|
@@ -69446,7 +69446,7 @@ var require_NodeIO = __commonJS({
|
|
|
69446
69446
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
69447
69447
|
exports2.readableFromFileOrURL = readableFromFileOrURL;
|
|
69448
69448
|
exports2.readFromFileOrURL = readFromFileOrURL;
|
|
69449
|
-
var
|
|
69449
|
+
var fs10 = __importStar(require("fs"));
|
|
69450
69450
|
var path17 = __importStar(require("path"));
|
|
69451
69451
|
var ts_necessities_1 = require_dist3();
|
|
69452
69452
|
var browser_or_node_1 = require_dist4();
|
|
@@ -69496,10 +69496,10 @@ var require_NodeIO = __commonJS({
|
|
|
69496
69496
|
return body;
|
|
69497
69497
|
}
|
|
69498
69498
|
function resolveSymbolicLink(filePath) {
|
|
69499
|
-
if (!
|
|
69499
|
+
if (!fs10.lstatSync(filePath).isSymbolicLink()) {
|
|
69500
69500
|
return filePath;
|
|
69501
69501
|
}
|
|
69502
|
-
const linkPath =
|
|
69502
|
+
const linkPath = fs10.readlinkSync(filePath);
|
|
69503
69503
|
if (path17.isAbsolute(linkPath)) {
|
|
69504
69504
|
return linkPath;
|
|
69505
69505
|
}
|
|
@@ -69519,8 +69519,8 @@ var require_NodeIO = __commonJS({
|
|
|
69519
69519
|
return process.stdin;
|
|
69520
69520
|
}
|
|
69521
69521
|
const filePath = resolveSymbolicLink(fileOrURL);
|
|
69522
|
-
if (
|
|
69523
|
-
return
|
|
69522
|
+
if (fs10.existsSync(filePath)) {
|
|
69523
|
+
return fs10.createReadStream(filePath, "utf8");
|
|
69524
69524
|
}
|
|
69525
69525
|
}
|
|
69526
69526
|
} catch (e) {
|
|
@@ -81589,8 +81589,8 @@ var init_ComposeFs = __esm({
|
|
|
81589
81589
|
var require_duckdb_binding = __commonJS({
|
|
81590
81590
|
"src/duckdb-binding.cjs"(exports2, module2) {
|
|
81591
81591
|
"use strict";
|
|
81592
|
-
var
|
|
81593
|
-
var
|
|
81592
|
+
var fs10 = require("node:fs");
|
|
81593
|
+
var os2 = require("node:os");
|
|
81594
81594
|
var path17 = require("node:path");
|
|
81595
81595
|
var zlib2 = require("node:zlib");
|
|
81596
81596
|
var { createRequire: createRequire3 } = require("node:module");
|
|
@@ -81599,36 +81599,36 @@ var require_duckdb_binding = __commonJS({
|
|
|
81599
81599
|
function cacheRoot() {
|
|
81600
81600
|
const asked = process.env.MOSAIC_DUCKDB_CACHE;
|
|
81601
81601
|
if (asked) return asked;
|
|
81602
|
-
const home =
|
|
81602
|
+
const home = os2.homedir();
|
|
81603
81603
|
if (process.platform === "win32") {
|
|
81604
|
-
return process.env.LOCALAPPDATA || (home ? path17.join(home, "AppData", "Local") :
|
|
81604
|
+
return process.env.LOCALAPPDATA || (home ? path17.join(home, "AppData", "Local") : os2.tmpdir());
|
|
81605
81605
|
}
|
|
81606
81606
|
if (process.platform === "darwin") {
|
|
81607
|
-
return home ? path17.join(home, "Library", "Caches") :
|
|
81607
|
+
return home ? path17.join(home, "Library", "Caches") : os2.tmpdir();
|
|
81608
81608
|
}
|
|
81609
|
-
return process.env.XDG_CACHE_HOME || (home ? path17.join(home, ".cache") :
|
|
81609
|
+
return process.env.XDG_CACHE_HOME || (home ? path17.join(home, ".cache") : os2.tmpdir());
|
|
81610
81610
|
}
|
|
81611
81611
|
function unpack(sea) {
|
|
81612
81612
|
const into = path17.join(cacheRoot(), "mosaic", "duckdb-" + VERSION2);
|
|
81613
81613
|
const keys = sea.getAssetKeys().filter((key) => key.startsWith(PREFIX));
|
|
81614
81614
|
if (keys.length === 0) return void 0;
|
|
81615
|
-
|
|
81615
|
+
fs10.mkdirSync(into, { recursive: true });
|
|
81616
81616
|
for (const key of keys) {
|
|
81617
81617
|
const name = path17.basename(key).replace(/\.br$/, "");
|
|
81618
81618
|
const target = path17.join(into, name);
|
|
81619
81619
|
try {
|
|
81620
|
-
if (
|
|
81620
|
+
if (fs10.statSync(target).size > 0) continue;
|
|
81621
81621
|
} catch {
|
|
81622
81622
|
}
|
|
81623
81623
|
const packed = Buffer.from(sea.getRawAsset(key));
|
|
81624
81624
|
const bytes = key.endsWith(".br") ? zlib2.brotliDecompressSync(packed) : packed;
|
|
81625
81625
|
const partial = target + "." + process.pid + ".part";
|
|
81626
|
-
|
|
81626
|
+
fs10.writeFileSync(partial, bytes);
|
|
81627
81627
|
try {
|
|
81628
|
-
|
|
81628
|
+
fs10.renameSync(partial, target);
|
|
81629
81629
|
} catch (error) {
|
|
81630
|
-
|
|
81631
|
-
if (!
|
|
81630
|
+
fs10.rmSync(partial, { force: true });
|
|
81631
|
+
if (!fs10.existsSync(target)) throw error;
|
|
81632
81632
|
}
|
|
81633
81633
|
}
|
|
81634
81634
|
return into;
|
|
@@ -92030,11 +92030,11 @@ async function exportArchivesToDatabase(archivePaths, databasePath) {
|
|
|
92030
92030
|
for (const archivePath of archivePaths) inserted.push(await database.insertArchive(archivePath));
|
|
92031
92031
|
return { database, inserted };
|
|
92032
92032
|
}
|
|
92033
|
-
var
|
|
92033
|
+
var import_node_fs8, import_node_path13, FIXED_SCHEMA, BATCH_ROWS, FROM_JSON_ROWS, MosaicDatabase;
|
|
92034
92034
|
var init_Export = __esm({
|
|
92035
92035
|
"../ts/src/duckdb/Export.ts"() {
|
|
92036
92036
|
"use strict";
|
|
92037
|
-
|
|
92037
|
+
import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
92038
92038
|
import_node_path13 = __toESM(require("node:path"), 1);
|
|
92039
92039
|
init_runtime();
|
|
92040
92040
|
init_MosaicFile();
|
|
@@ -92110,7 +92110,7 @@ var init_Export = __esm({
|
|
|
92110
92110
|
* so the same call makes a new database or adds to an existing one.
|
|
92111
92111
|
*/
|
|
92112
92112
|
static async open(databasePath) {
|
|
92113
|
-
if (databasePath !== ":memory:")
|
|
92113
|
+
if (databasePath !== ":memory:") import_node_fs8.default.mkdirSync(import_node_path13.default.dirname(import_node_path13.default.resolve(databasePath)), { recursive: true });
|
|
92114
92114
|
const { DuckDBInstance } = await duckdb();
|
|
92115
92115
|
const instance = await DuckDBInstance.create(databasePath);
|
|
92116
92116
|
const connection = await instance.connect();
|
|
@@ -92156,9 +92156,9 @@ var init_Export = __esm({
|
|
|
92156
92156
|
}
|
|
92157
92157
|
/** Reads an archive and appends it. Nothing already in the database is touched. */
|
|
92158
92158
|
async insertArchive(archivePath, options = {}) {
|
|
92159
|
-
if (!
|
|
92159
|
+
if (!import_node_fs8.default.existsSync(archivePath)) throw new Error(`File ${archivePath} does not exist`);
|
|
92160
92160
|
const source = import_node_path13.default.resolve(archivePath);
|
|
92161
|
-
const file = await LoadMosaicFile(
|
|
92161
|
+
const file = await LoadMosaicFile(import_node_fs8.default.readFileSync(source));
|
|
92162
92162
|
return await this.insertFile(file, options.fileId ?? import_node_path13.default.basename(source).split(".")[0], source);
|
|
92163
92163
|
}
|
|
92164
92164
|
/** Appends an already-loaded file. */
|
|
@@ -92789,7 +92789,7 @@ function glbOutputPathForDatabase(databasePath) {
|
|
|
92789
92789
|
return import_node_path14.default.join(import_node_path14.default.dirname(databasePath), `${stem}${GLB_EXTENSION}`);
|
|
92790
92790
|
}
|
|
92791
92791
|
async function composeDatabaseToGlb(databasePath, outputPath, options = {}) {
|
|
92792
|
-
if (!
|
|
92792
|
+
if (!import_node_fs9.default.existsSync(databasePath)) throw new Error(`File ${databasePath} does not exist`);
|
|
92793
92793
|
const database = await MosaicDatabase.open(databasePath);
|
|
92794
92794
|
try {
|
|
92795
92795
|
const wanted = options.files;
|
|
@@ -92798,8 +92798,8 @@ async function composeDatabaseToGlb(databasePath, outputPath, options = {}) {
|
|
|
92798
92798
|
const composed = mosaicToGltf(file);
|
|
92799
92799
|
const target = import_node_path14.default.resolve(outputPath ?? glbOutputPathForDatabase(import_node_path14.default.resolve(databasePath)));
|
|
92800
92800
|
const bytes = writeGlb(composed.document, composed.binary);
|
|
92801
|
-
|
|
92802
|
-
|
|
92801
|
+
import_node_fs9.default.mkdirSync(import_node_path14.default.dirname(target), { recursive: true });
|
|
92802
|
+
import_node_fs9.default.writeFileSync(target, bytes);
|
|
92803
92803
|
return {
|
|
92804
92804
|
outputPath: target,
|
|
92805
92805
|
byteLength: bytes.byteLength,
|
|
@@ -92813,11 +92813,11 @@ async function composeDatabaseToGlb(databasePath, outputPath, options = {}) {
|
|
|
92813
92813
|
await database.close();
|
|
92814
92814
|
}
|
|
92815
92815
|
}
|
|
92816
|
-
var
|
|
92816
|
+
var import_node_fs9, import_node_path14;
|
|
92817
92817
|
var init_Compose = __esm({
|
|
92818
92818
|
"../ts/src/duckdb/Compose.ts"() {
|
|
92819
92819
|
"use strict";
|
|
92820
|
-
|
|
92820
|
+
import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
92821
92821
|
import_node_path14 = __toESM(require("node:path"), 1);
|
|
92822
92822
|
init_MosaicToGltf();
|
|
92823
92823
|
init_GlbWriter();
|
|
@@ -95354,7 +95354,7 @@ async function runCodegen(argv) {
|
|
|
95354
95354
|
}
|
|
95355
95355
|
|
|
95356
95356
|
// src/commands/pack.ts
|
|
95357
|
-
var
|
|
95357
|
+
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
95358
95358
|
|
|
95359
95359
|
// ../ts/src/index.ts
|
|
95360
95360
|
init_MosaicFile();
|
|
@@ -95989,7 +95989,7 @@ function svgToMosaic(svg, options = {}) {
|
|
|
95989
95989
|
dataVersion: options.provenance?.dataVersion ?? "1.0.0",
|
|
95990
95990
|
author: options.provenance?.author ?? "",
|
|
95991
95991
|
timestamp: options.provenance?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
95992
|
-
application: options.provenance?.application ?? "mosaic
|
|
95992
|
+
application: options.provenance?.application ?? "mosaic pack"
|
|
95993
95993
|
},
|
|
95994
95994
|
nodes: [{
|
|
95995
95995
|
id: nodeId,
|
|
@@ -96043,27 +96043,49 @@ init_ComposeFs();
|
|
|
96043
96043
|
// ../ts/src/index.ts
|
|
96044
96044
|
init_MosaicIndexFile();
|
|
96045
96045
|
|
|
96046
|
-
// src/commands/pack.ts
|
|
96047
|
-
var PACK_USAGE = `mosaic pack <input.json> [output${MOSAIC_ARCHIVE_EXTENSION}]`;
|
|
96048
|
-
async function runPack(argv) {
|
|
96049
|
-
const [input_path, output_path] = argv;
|
|
96050
|
-
if (input_path === void 0) {
|
|
96051
|
-
throw new Error(`Usage: ${PACK_USAGE}`);
|
|
96052
|
-
}
|
|
96053
|
-
const result = await packMosaicSourceFile(input_path, output_path);
|
|
96054
|
-
console.log(`Packed: ${import_node_path6.default.resolve(input_path)} -> ${result.outputPath}`);
|
|
96055
|
-
console.log();
|
|
96056
|
-
console.log(`Component tables (${result.componentCount} rows):`);
|
|
96057
|
-
result.tables.forEach((table) => console.log(` - ${table}`));
|
|
96058
|
-
console.log();
|
|
96059
|
-
console.log(`Wrote ${result.byteLength} bytes.`);
|
|
96060
|
-
}
|
|
96061
|
-
|
|
96062
96046
|
// src/commands/gltf.ts
|
|
96063
|
-
var
|
|
96047
|
+
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
96048
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
96049
|
+
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
96064
96050
|
var STABLE_IDS = "--stable-ids";
|
|
96065
|
-
var GLTF_USAGE = `mosaic gltf <input.gltf|input.glb> [output${MOSAIC_SOURCE_EXTENSION}] [${STABLE_IDS}]`;
|
|
96066
|
-
var GLTF_PACK_USAGE = `mosaic
|
|
96051
|
+
var GLTF_USAGE = `mosaic gltf <input.gltf|input.glb|url> [output${MOSAIC_SOURCE_EXTENSION}] [${STABLE_IDS}]`;
|
|
96052
|
+
var GLTF_PACK_USAGE = `mosaic pack <input.gltf|input.glb|url> [output.tsr] [${STABLE_IDS}]`;
|
|
96053
|
+
var isUrl = (input) => /^https?:\/\//i.test(input);
|
|
96054
|
+
var isRelative = (uri) => typeof uri === "string" && uri.length > 0 && !/^[a-z][a-z0-9+.-]*:/i.test(uri);
|
|
96055
|
+
async function download(url, target) {
|
|
96056
|
+
const response = await fetch(url);
|
|
96057
|
+
if (!response.ok) throw new Error(`Could not download ${url}: ${response.status} ${response.statusText}`);
|
|
96058
|
+
import_node_fs6.default.mkdirSync(import_node_path6.default.dirname(target), { recursive: true });
|
|
96059
|
+
import_node_fs6.default.writeFileSync(target, new Uint8Array(await response.arrayBuffer()));
|
|
96060
|
+
}
|
|
96061
|
+
async function localInput(input) {
|
|
96062
|
+
if (!isUrl(input)) return { file: input, done() {
|
|
96063
|
+
} };
|
|
96064
|
+
const url = new URL(input);
|
|
96065
|
+
const name = decodeURIComponent(import_node_path6.default.posix.basename(url.pathname)) || "model.glb";
|
|
96066
|
+
const folder = import_node_fs6.default.mkdtempSync(import_node_path6.default.join(import_node_os.default.tmpdir(), "mosaic-gltf-"));
|
|
96067
|
+
const file = import_node_path6.default.join(folder, name);
|
|
96068
|
+
console.log(`Downloading ${url}`);
|
|
96069
|
+
await download(url, file);
|
|
96070
|
+
if (name.toLowerCase().endsWith(".gltf")) {
|
|
96071
|
+
const document = JSON.parse(import_node_fs6.default.readFileSync(file, "utf-8"));
|
|
96072
|
+
const beside = [...document.buffers ?? [], ...document.images ?? []].map((entry) => entry.uri).filter(isRelative);
|
|
96073
|
+
for (const uri of new Set(beside)) {
|
|
96074
|
+
const target = import_node_path6.default.resolve(folder, decodeURIComponent(uri));
|
|
96075
|
+
if (!target.startsWith(folder + import_node_path6.default.sep)) throw new Error(`${name} refers to ${uri}, outside its own folder`);
|
|
96076
|
+
await download(new URL(uri, url), target);
|
|
96077
|
+
}
|
|
96078
|
+
}
|
|
96079
|
+
return {
|
|
96080
|
+
file,
|
|
96081
|
+
defaultDirectory: process.cwd(),
|
|
96082
|
+
done: () => import_node_fs6.default.rmSync(folder, { recursive: true, force: true })
|
|
96083
|
+
};
|
|
96084
|
+
}
|
|
96085
|
+
function defaultOutput(file, directory, extension) {
|
|
96086
|
+
if (directory === void 0) return void 0;
|
|
96087
|
+
return import_node_path6.default.join(directory, import_node_path6.default.basename(file).split(".")[0] + extension);
|
|
96088
|
+
}
|
|
96067
96089
|
function readArgs(argv) {
|
|
96068
96090
|
return {
|
|
96069
96091
|
positional: argv.filter((arg) => !arg.startsWith("--")),
|
|
@@ -96071,7 +96093,7 @@ function readArgs(argv) {
|
|
|
96071
96093
|
};
|
|
96072
96094
|
}
|
|
96073
96095
|
function report(inputPath, result, stable = false) {
|
|
96074
|
-
console.log(`Converted: ${
|
|
96096
|
+
console.log(`Converted: ${isUrl(inputPath) ? inputPath : import_node_path6.default.resolve(inputPath)} -> ${result.outputPath}`);
|
|
96075
96097
|
console.log();
|
|
96076
96098
|
console.log(`Nodes: ${result.nodeCount}`);
|
|
96077
96099
|
if (stable) console.log(`Ids: derived from the file name, so this conversion repeats exactly`);
|
|
@@ -96091,17 +96113,29 @@ async function runGltf(argv) {
|
|
|
96091
96113
|
const { positional, stableIds: stableIds2 } = readArgs(argv);
|
|
96092
96114
|
const [input_path, output_path] = positional;
|
|
96093
96115
|
if (input_path === void 0) throw new Error(`Usage: ${GLTF_USAGE}`);
|
|
96094
|
-
|
|
96116
|
+
const input = await localInput(input_path);
|
|
96117
|
+
try {
|
|
96118
|
+
const output = output_path ?? defaultOutput(input.file, input.defaultDirectory, MOSAIC_SOURCE_EXTENSION);
|
|
96119
|
+
report(input_path, convertGltfToSourceFile(input.file, output, { stableIds: stableIds2 }), stableIds2);
|
|
96120
|
+
} finally {
|
|
96121
|
+
input.done();
|
|
96122
|
+
}
|
|
96095
96123
|
}
|
|
96096
96124
|
async function runGltfPack(argv) {
|
|
96097
96125
|
const { positional, stableIds: stableIds2 } = readArgs(argv);
|
|
96098
96126
|
const [input_path, output_path] = positional;
|
|
96099
96127
|
if (input_path === void 0) throw new Error(`Usage: ${GLTF_PACK_USAGE}`);
|
|
96100
|
-
|
|
96128
|
+
const input = await localInput(input_path);
|
|
96129
|
+
try {
|
|
96130
|
+
const output = output_path ?? defaultOutput(input.file, input.defaultDirectory, ".tsr");
|
|
96131
|
+
report(input_path, await convertGltfToArchiveFile(input.file, output, { stableIds: stableIds2 }), stableIds2);
|
|
96132
|
+
} finally {
|
|
96133
|
+
input.done();
|
|
96134
|
+
}
|
|
96101
96135
|
}
|
|
96102
96136
|
|
|
96103
96137
|
// src/commands/ifc.ts
|
|
96104
|
-
var
|
|
96138
|
+
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
96105
96139
|
|
|
96106
96140
|
// ../ifc4/src/schemas/entity.schema.json
|
|
96107
96141
|
var entity_schema_default = {
|
|
@@ -97092,12 +97126,12 @@ function ifc4ToMosaic(api, modelID, options = {}) {
|
|
|
97092
97126
|
}
|
|
97093
97127
|
|
|
97094
97128
|
// ../ifc4/src/Ifc4ConvertFs.ts
|
|
97095
|
-
var
|
|
97096
|
-
var
|
|
97129
|
+
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
97130
|
+
var import_node_path8 = __toESM(require("node:path"), 1);
|
|
97097
97131
|
|
|
97098
97132
|
// ../ifc4/src/runtime.ts
|
|
97099
97133
|
var import_node_module = require("node:module");
|
|
97100
|
-
var
|
|
97134
|
+
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
97101
97135
|
var loaded;
|
|
97102
97136
|
async function webIfc() {
|
|
97103
97137
|
if (loaded) return loaded;
|
|
@@ -97111,13 +97145,13 @@ async function webIfc() {
|
|
|
97111
97145
|
const roots = [
|
|
97112
97146
|
process.env.MOSAIC_WEBIFC,
|
|
97113
97147
|
// Beside the bundle itself, which is where an npm install of the CLI puts it.
|
|
97114
|
-
process.argv[1] === void 0 ? void 0 :
|
|
97148
|
+
process.argv[1] === void 0 ? void 0 : import_node_path7.default.dirname(process.argv[1]),
|
|
97115
97149
|
process.cwd(),
|
|
97116
|
-
|
|
97117
|
-
].filter((root) => typeof root === "string" && root.length > 0).map((root) =>
|
|
97150
|
+
import_node_path7.default.dirname(process.execPath)
|
|
97151
|
+
].filter((root) => typeof root === "string" && root.length > 0).map((root) => import_node_path7.default.join(root, "index.js"));
|
|
97118
97152
|
for (const root of roots) {
|
|
97119
97153
|
try {
|
|
97120
|
-
const require2 = (0, import_node_module.createRequire)(
|
|
97154
|
+
const require2 = (0, import_node_module.createRequire)(import_node_path7.default.resolve(root));
|
|
97121
97155
|
loaded = require2("web-ifc");
|
|
97122
97156
|
return loaded;
|
|
97123
97157
|
} catch (error) {
|
|
@@ -97138,15 +97172,15 @@ function message(error) {
|
|
|
97138
97172
|
// ../ifc4/src/Ifc4ConvertFs.ts
|
|
97139
97173
|
var MOSAIC_SOURCE_EXTENSION2 = ".mosaic.json";
|
|
97140
97174
|
function stemOf(inputPath) {
|
|
97141
|
-
const base =
|
|
97175
|
+
const base = import_node_path8.default.basename(inputPath);
|
|
97142
97176
|
const dot = base.lastIndexOf(".");
|
|
97143
97177
|
return dot > 0 ? base.slice(0, dot) : base;
|
|
97144
97178
|
}
|
|
97145
97179
|
function sourceOutputPath2(inputPath) {
|
|
97146
|
-
return
|
|
97180
|
+
return import_node_path8.default.join(import_node_path8.default.dirname(inputPath), `${stemOf(inputPath)}${MOSAIC_SOURCE_EXTENSION2}`);
|
|
97147
97181
|
}
|
|
97148
97182
|
function archiveOutputPath3(inputPath) {
|
|
97149
|
-
return
|
|
97183
|
+
return import_node_path8.default.join(import_node_path8.default.dirname(inputPath), `${stemOf(inputPath)}${MOSAIC_ARCHIVE_EXTENSION}`);
|
|
97150
97184
|
}
|
|
97151
97185
|
async function openIfcModel(bytes, options = {}) {
|
|
97152
97186
|
const module2 = await webIfc();
|
|
@@ -97160,18 +97194,18 @@ async function openIfcModel(bytes, options = {}) {
|
|
|
97160
97194
|
};
|
|
97161
97195
|
}
|
|
97162
97196
|
async function convertIfcFile(inputPath, options = {}) {
|
|
97163
|
-
if (!
|
|
97164
|
-
const source =
|
|
97165
|
-
const model = await openIfcModel(new Uint8Array(
|
|
97197
|
+
if (!import_node_fs7.default.existsSync(inputPath)) throw new Error(`File ${inputPath} does not exist`);
|
|
97198
|
+
const source = import_node_path8.default.resolve(inputPath);
|
|
97199
|
+
const model = await openIfcModel(new Uint8Array(import_node_fs7.default.readFileSync(source)), options);
|
|
97166
97200
|
try {
|
|
97167
97201
|
return ifc4ToMosaic(model.api, model.modelID, {
|
|
97168
97202
|
// Entities that have no GlobalId are keyed within the file they came from, and
|
|
97169
97203
|
// the file name is the only name that file has.
|
|
97170
|
-
seed:
|
|
97204
|
+
seed: import_node_path8.default.basename(source),
|
|
97171
97205
|
...options,
|
|
97172
97206
|
provenance: {
|
|
97173
|
-
id:
|
|
97174
|
-
message: `Imported from ${
|
|
97207
|
+
id: import_node_path8.default.basename(source),
|
|
97208
|
+
message: `Imported from ${import_node_path8.default.basename(source)}`,
|
|
97175
97209
|
...options.provenance
|
|
97176
97210
|
}
|
|
97177
97211
|
});
|
|
@@ -97180,13 +97214,13 @@ async function convertIfcFile(inputPath, options = {}) {
|
|
|
97180
97214
|
}
|
|
97181
97215
|
}
|
|
97182
97216
|
function write2(target, data) {
|
|
97183
|
-
|
|
97184
|
-
|
|
97217
|
+
import_node_fs7.default.mkdirSync(import_node_path8.default.dirname(target), { recursive: true });
|
|
97218
|
+
import_node_fs7.default.writeFileSync(target, data);
|
|
97185
97219
|
return typeof data === "string" ? Buffer.byteLength(data) : data.byteLength;
|
|
97186
97220
|
}
|
|
97187
97221
|
async function convertIfcToSourceFile(inputPath, outputPath, options) {
|
|
97188
97222
|
const result = await convertIfcFile(inputPath, options);
|
|
97189
|
-
const target =
|
|
97223
|
+
const target = import_node_path8.default.resolve(outputPath ?? sourceOutputPath2(import_node_path8.default.resolve(inputPath)));
|
|
97190
97224
|
return {
|
|
97191
97225
|
outputPath: target,
|
|
97192
97226
|
byteLength: write2(target, `${JSON.stringify(result.document, null, 2)}
|
|
@@ -97197,7 +97231,7 @@ async function convertIfcToSourceFile(inputPath, outputPath, options) {
|
|
|
97197
97231
|
}
|
|
97198
97232
|
async function convertIfcToArchiveFile(inputPath, outputPath, options) {
|
|
97199
97233
|
const result = await convertIfcFile(inputPath, options);
|
|
97200
|
-
const target =
|
|
97234
|
+
const target = import_node_path8.default.resolve(outputPath ?? archiveOutputPath3(import_node_path8.default.resolve(inputPath)));
|
|
97201
97235
|
return {
|
|
97202
97236
|
outputPath: target,
|
|
97203
97237
|
byteLength: write2(target, await packMosaicSource(result.document)),
|
|
@@ -97212,7 +97246,7 @@ var NO_GEOMETRY = "--no-geometry";
|
|
|
97212
97246
|
var SEED = "--seed=";
|
|
97213
97247
|
var FLAGS = `[${CENTER}] [${NO_GEOMETRY}] [${SEED}<text>]`;
|
|
97214
97248
|
var IFC_USAGE = `mosaic ifc <input.ifc> [output${MOSAIC_SOURCE_EXTENSION2}] ${FLAGS}`;
|
|
97215
|
-
var IFC_PACK_USAGE = `mosaic
|
|
97249
|
+
var IFC_PACK_USAGE = `mosaic pack <input.ifc> [output.tsr] ${FLAGS}`;
|
|
97216
97250
|
function readArgs2(argv) {
|
|
97217
97251
|
const seed = argv.find((arg) => arg.startsWith(SEED))?.slice(SEED.length);
|
|
97218
97252
|
return {
|
|
@@ -97226,7 +97260,7 @@ function readArgs2(argv) {
|
|
|
97226
97260
|
}
|
|
97227
97261
|
function report2(inputPath, result) {
|
|
97228
97262
|
const { stats } = result;
|
|
97229
|
-
console.log(`Converted: ${
|
|
97263
|
+
console.log(`Converted: ${import_node_path9.default.resolve(inputPath)} -> ${result.outputPath}`);
|
|
97230
97264
|
console.log();
|
|
97231
97265
|
console.log(`Schema: ${stats.schema}`);
|
|
97232
97266
|
console.log(`Nodes: ${stats.nodes} (${stats.entities} from IFC entities)`);
|
|
@@ -97264,13 +97298,13 @@ async function runIfcPack(argv) {
|
|
|
97264
97298
|
}
|
|
97265
97299
|
|
|
97266
97300
|
// src/commands/svg.ts
|
|
97267
|
-
var
|
|
97268
|
-
var SVG_PACK_USAGE = `mosaic
|
|
97301
|
+
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
97302
|
+
var SVG_PACK_USAGE = `mosaic pack <input.svg> [output.tsr]`;
|
|
97269
97303
|
async function runSvgPack(argv) {
|
|
97270
97304
|
const [input_path, output_path] = argv.filter((arg) => !arg.startsWith("--"));
|
|
97271
97305
|
if (input_path === void 0) throw new Error(`Usage: ${SVG_PACK_USAGE}`);
|
|
97272
97306
|
const result = await convertSvgToArchiveFile(input_path, output_path);
|
|
97273
|
-
console.log(`Packed: ${
|
|
97307
|
+
console.log(`Packed: ${import_node_path10.default.resolve(input_path)} -> ${result.outputPath}`);
|
|
97274
97308
|
console.log();
|
|
97275
97309
|
console.log(`Node: ${result.nodeId}`);
|
|
97276
97310
|
console.log(`Name: ${result.name}`);
|
|
@@ -97282,6 +97316,59 @@ async function runSvgPack(argv) {
|
|
|
97282
97316
|
console.log(`Wrote ${result.byteLength} bytes.`);
|
|
97283
97317
|
}
|
|
97284
97318
|
|
|
97319
|
+
// src/commands/pack.ts
|
|
97320
|
+
var PACK_USAGE = `mosaic pack <input.json|.gltf|.glb|.ifc|.svg|url> [output${MOSAIC_ARCHIVE_EXTENSION}] [flags]`;
|
|
97321
|
+
var PACK_DETAILS = [
|
|
97322
|
+
`.json, .mosaic.json a Mosaic source document`,
|
|
97323
|
+
`.gltf, .glb a glTF model, or an http(s) URL to one [--stable-ids]`,
|
|
97324
|
+
`.ifc an IFC4 / IFC2X3 model [--center] [--no-geometry] [--seed=<text>]`,
|
|
97325
|
+
`.svg a drawing, as one node`
|
|
97326
|
+
];
|
|
97327
|
+
function extensionOf(input) {
|
|
97328
|
+
const name = /^https?:\/\//i.test(input) ? new URL(input).pathname : input;
|
|
97329
|
+
return import_node_path11.default.extname(name).toLowerCase();
|
|
97330
|
+
}
|
|
97331
|
+
async function packSource(argv) {
|
|
97332
|
+
const [input_path, output_path] = argv.filter((arg) => !arg.startsWith("--"));
|
|
97333
|
+
if (input_path === void 0) throw new Error(`Usage: ${PACK_USAGE}`);
|
|
97334
|
+
const result = await packMosaicSourceFile(input_path, output_path);
|
|
97335
|
+
console.log(`Packed: ${import_node_path11.default.resolve(input_path)} -> ${result.outputPath}`);
|
|
97336
|
+
console.log();
|
|
97337
|
+
console.log(`Component tables (${result.componentCount} rows):`);
|
|
97338
|
+
result.tables.forEach((table) => console.log(` - ${table}`));
|
|
97339
|
+
console.log();
|
|
97340
|
+
console.log(`Wrote ${result.byteLength} bytes.`);
|
|
97341
|
+
}
|
|
97342
|
+
async function runPack(argv) {
|
|
97343
|
+
const input = argv.find((arg) => !arg.startsWith("--"));
|
|
97344
|
+
if (input === void 0) throw new Error(`Usage: ${PACK_USAGE}
|
|
97345
|
+
|
|
97346
|
+
${PACK_DETAILS.join("\n ")}`);
|
|
97347
|
+
const isUrl2 = /^https?:\/\//i.test(input);
|
|
97348
|
+
const extension = extensionOf(input);
|
|
97349
|
+
switch (extension) {
|
|
97350
|
+
case ".gltf":
|
|
97351
|
+
case ".glb":
|
|
97352
|
+
return runGltfPack(argv);
|
|
97353
|
+
case ".json":
|
|
97354
|
+
if (isUrl2) break;
|
|
97355
|
+
return packSource(argv);
|
|
97356
|
+
case ".ifc":
|
|
97357
|
+
if (isUrl2) break;
|
|
97358
|
+
return runIfcPack(argv);
|
|
97359
|
+
case ".svg":
|
|
97360
|
+
if (isUrl2) break;
|
|
97361
|
+
return runSvgPack(argv);
|
|
97362
|
+
default:
|
|
97363
|
+
throw new Error(
|
|
97364
|
+
`Cannot pack ${input}: ${extension ? `"${extension}" is not` : "no extension says what it is, and it is not"} a format mosaic reads.
|
|
97365
|
+
|
|
97366
|
+
${PACK_DETAILS.join("\n ")}`
|
|
97367
|
+
);
|
|
97368
|
+
}
|
|
97369
|
+
throw new Error(`Cannot pack ${input}: only glTF (.gltf, .glb) can be packed from a URL. Download it first and pack the file.`);
|
|
97370
|
+
}
|
|
97371
|
+
|
|
97285
97372
|
// src/commands/compose.ts
|
|
97286
97373
|
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
97287
97374
|
var DATABASE_EXTENSIONS = [".duckdb", ".db", ".ddb"];
|
|
@@ -97409,7 +97496,7 @@ async function runServe(argv) {
|
|
|
97409
97496
|
}
|
|
97410
97497
|
|
|
97411
97498
|
// src/mosaic.ts
|
|
97412
|
-
var VERSION = true ? "0.
|
|
97499
|
+
var VERSION = true ? "0.2.0" : "dev";
|
|
97413
97500
|
var COMMANDS = {
|
|
97414
97501
|
codegen: {
|
|
97415
97502
|
usage: CODEGEN_USAGE,
|
|
@@ -97418,7 +97505,8 @@ var COMMANDS = {
|
|
|
97418
97505
|
},
|
|
97419
97506
|
pack: {
|
|
97420
97507
|
usage: PACK_USAGE,
|
|
97421
|
-
|
|
97508
|
+
details: PACK_DETAILS,
|
|
97509
|
+
summary: "Pack a source document, glTF, IFC or SVG into a .tsr archive",
|
|
97422
97510
|
run: runPack
|
|
97423
97511
|
},
|
|
97424
97512
|
gltf: {
|
|
@@ -97426,26 +97514,11 @@ var COMMANDS = {
|
|
|
97426
97514
|
summary: "Convert a glTF or GLB file into a Mosaic source document",
|
|
97427
97515
|
run: runGltf
|
|
97428
97516
|
},
|
|
97429
|
-
"gltf-pack": {
|
|
97430
|
-
usage: GLTF_PACK_USAGE,
|
|
97431
|
-
summary: "Convert a glTF or GLB file straight into a .tsr archive",
|
|
97432
|
-
run: runGltfPack
|
|
97433
|
-
},
|
|
97434
97517
|
ifc: {
|
|
97435
97518
|
usage: IFC_USAGE,
|
|
97436
97519
|
summary: "Convert an IFC model into a Mosaic source document",
|
|
97437
97520
|
run: runIfc
|
|
97438
97521
|
},
|
|
97439
|
-
"ifc-pack": {
|
|
97440
|
-
usage: IFC_PACK_USAGE,
|
|
97441
|
-
summary: "Convert an IFC model straight into a .tsr archive",
|
|
97442
|
-
run: runIfcPack
|
|
97443
|
-
},
|
|
97444
|
-
"svg-pack": {
|
|
97445
|
-
usage: SVG_PACK_USAGE,
|
|
97446
|
-
summary: "Pack an SVG into a .tsr archive of one node",
|
|
97447
|
-
run: runSvgPack
|
|
97448
|
-
},
|
|
97449
97522
|
compose: {
|
|
97450
97523
|
usage: COMPOSE_USAGE,
|
|
97451
97524
|
summary: "Compose an archive and its imports into a renderable .glb",
|
|
@@ -97466,6 +97539,7 @@ function printUsage() {
|
|
|
97466
97539
|
for (const [name, command] of Object.entries(COMMANDS)) {
|
|
97467
97540
|
console.log(` ${name.padEnd(10)} ${command.summary}`);
|
|
97468
97541
|
console.log(` ${" ".repeat(10)} ${command.usage}`);
|
|
97542
|
+
for (const line of command.details ?? []) console.log(` ${" ".repeat(12)} ${line}`);
|
|
97469
97543
|
}
|
|
97470
97544
|
console.log();
|
|
97471
97545
|
console.log(` help Show this message`);
|