@faicad/faijs 0.13.0 → 0.13.2
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/dist/api/edge-ref.d.ts +3 -2
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +3 -2
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/internal/compat-op.d.ts +2 -0
- package/dist/api/internal/compat-op.d.ts.map +1 -1
- package/dist/api/internal/compat-op.js +8 -1
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/occt-kernel-bridge.d.ts.map +1 -1
- package/dist/api/occt-kernel-bridge.js +7 -1
- package/dist/api/occt-kernel-bridge.js.map +1 -1
- package/dist/browser.d.ts +0 -2
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -2
- package/dist/browser.js.map +1 -1
- package/dist/cad-runtime/browser-lib-loader.d.ts +1 -1
- package/dist/cad-runtime/browser-lib-loader.js +1 -1
- package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
- package/dist/fcstd/attachment.d.ts +65 -0
- package/dist/fcstd/attachment.d.ts.map +1 -0
- package/dist/fcstd/attachment.js +87 -0
- package/dist/fcstd/attachment.js.map +1 -0
- package/dist/fcstd/build-fai-zip.d.ts +11 -0
- package/dist/fcstd/build-fai-zip.d.ts.map +1 -1
- package/dist/fcstd/build-fai-zip.js +9 -1
- package/dist/fcstd/build-fai-zip.js.map +1 -1
- package/dist/fcstd/cli.d.ts +3 -0
- package/dist/fcstd/cli.d.ts.map +1 -0
- package/dist/fcstd/cli.js +37 -0
- package/dist/fcstd/cli.js.map +1 -0
- package/dist/fcstd/codegen.d.ts +14 -1
- package/dist/fcstd/codegen.d.ts.map +1 -1
- package/dist/fcstd/codegen.js +11 -2
- package/dist/fcstd/codegen.js.map +1 -1
- package/dist/fcstd/container.d.ts +16 -1
- package/dist/fcstd/container.d.ts.map +1 -1
- package/dist/fcstd/container.js +12 -1
- package/dist/fcstd/container.js.map +1 -1
- package/dist/fcstd/contour.d.ts +9 -1
- package/dist/fcstd/contour.d.ts.map +1 -1
- package/dist/fcstd/contour.js +12 -1
- package/dist/fcstd/contour.js.map +1 -1
- package/dist/fcstd/convert.d.ts +47 -2
- package/dist/fcstd/convert.d.ts.map +1 -1
- package/dist/fcstd/convert.js +82 -13
- package/dist/fcstd/convert.js.map +1 -1
- package/dist/fcstd/document.d.ts +8 -1
- package/dist/fcstd/document.d.ts.map +1 -1
- package/dist/fcstd/document.js +4 -1
- package/dist/fcstd/document.js.map +1 -1
- package/dist/fcstd/expressions.d.ts +14 -1
- package/dist/fcstd/expressions.d.ts.map +1 -1
- package/dist/fcstd/expressions.js +11 -1
- package/dist/fcstd/expressions.js.map +1 -1
- package/dist/fcstd/external-geo.d.ts +15 -1
- package/dist/fcstd/external-geo.d.ts.map +1 -1
- package/dist/fcstd/external-geo.js +8 -1
- package/dist/fcstd/external-geo.js.map +1 -1
- package/dist/fcstd/feature-translate.d.ts +65 -3
- package/dist/fcstd/feature-translate.d.ts.map +1 -1
- package/dist/fcstd/feature-translate.js +82 -4
- package/dist/fcstd/feature-translate.js.map +1 -1
- package/dist/fcstd/index.d.ts +23 -0
- package/dist/fcstd/index.d.ts.map +1 -0
- package/dist/fcstd/index.js +19 -0
- package/dist/fcstd/index.js.map +1 -0
- package/dist/fcstd/placement.d.ts +49 -6
- package/dist/fcstd/placement.d.ts.map +1 -1
- package/dist/fcstd/placement.js +46 -6
- package/dist/fcstd/placement.js.map +1 -1
- package/dist/fcstd/planegcs-backend.d.ts +16 -1
- package/dist/fcstd/planegcs-backend.d.ts.map +1 -1
- package/dist/fcstd/planegcs-backend.js +16 -1
- package/dist/fcstd/planegcs-backend.js.map +1 -1
- package/dist/fcstd/sketch-parse.d.ts +43 -0
- package/dist/fcstd/sketch-parse.d.ts.map +1 -1
- package/dist/fcstd/sketch-parse.js +26 -0
- package/dist/fcstd/sketch-parse.js.map +1 -1
- package/dist/fcstd/sketch-solver.d.ts +20 -2
- package/dist/fcstd/sketch-solver.d.ts.map +1 -1
- package/dist/fcstd/sketch-solver.js +6 -1
- package/dist/fcstd/sketch-solver.js.map +1 -1
- package/dist/fcstd/sketch-verify.d.ts +19 -1
- package/dist/fcstd/sketch-verify.d.ts.map +1 -1
- package/dist/fcstd/sketch-verify.js +14 -1
- package/dist/fcstd/sketch-verify.js.map +1 -1
- package/dist/fcstd/unpack.d.ts +21 -2
- package/dist/fcstd/unpack.d.ts.map +1 -1
- package/dist/fcstd/unpack.js +11 -2
- package/dist/fcstd/unpack.js.map +1 -1
- package/dist/fcstd-convert.d.ts +30 -0
- package/dist/fcstd-convert.d.ts.map +1 -0
- package/dist/fcstd-convert.js +27 -0
- package/dist/fcstd-convert.js.map +1 -0
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +20 -19
- package/dist/node-host/cli.js.map +1 -1
- package/dist/vendored/brepjs/kernel/index.d.ts +7 -0
- package/dist/vendored/brepjs/kernel/index.d.ts.map +1 -1
- package/dist/vendored/brepjs/kernel/index.js +57 -0
- package/dist/vendored/brepjs/kernel/index.js.map +1 -1
- package/dist/weapp.d.ts +22 -0
- package/dist/weapp.d.ts.map +1 -0
- package/dist/weapp.js +23 -0
- package/dist/weapp.js.map +1 -0
- package/package.json +18 -5
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { placementOf, placementOfProp } from './placement.js';
|
|
2
|
+
/** eMapMode values from FreeCAD Attacher.h (subset the corpus uses). */
|
|
3
|
+
export const ATTACH_MAP_MODE = {
|
|
4
|
+
DEACTIVATED: 0,
|
|
5
|
+
TRANSLATE: 1,
|
|
6
|
+
OBJECT_XY: 2,
|
|
7
|
+
OBJECT_XZ: 3,
|
|
8
|
+
OBJECT_YZ: 4,
|
|
9
|
+
FLAT_FACE: 5,
|
|
10
|
+
TANGENT_PLANE: 6,
|
|
11
|
+
};
|
|
12
|
+
/** Property names that may carry the support link (old / new FreeCAD). */
|
|
13
|
+
const SUPPORT_PROPS = ['Support', 'AttachmentSupport'];
|
|
14
|
+
function firstLinkSub(obj) {
|
|
15
|
+
for (const name of SUPPORT_PROPS) {
|
|
16
|
+
const prop = obj.properties.get(name);
|
|
17
|
+
const link = prop?.children[0]?.children[0];
|
|
18
|
+
const target = link?.attributes['obj'];
|
|
19
|
+
if (target)
|
|
20
|
+
return { target, sub: link?.attributes['sub'] ?? '' };
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function mapMode(obj) {
|
|
25
|
+
const raw = obj.properties.get('MapMode')?.children[0]?.attributes['value'];
|
|
26
|
+
return raw === undefined ? undefined : Number(raw);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compose two placements: `outer ∘ inner` (apply inner first, then outer).
|
|
30
|
+
* Quaternion product q = qo * qi, position = outer(inner(0)).
|
|
31
|
+
*/
|
|
32
|
+
function compose(outer, inner) {
|
|
33
|
+
const [ox, oy, oz, ow] = outer.q;
|
|
34
|
+
const [ix, iy, iz, iw] = inner.q;
|
|
35
|
+
// Hamilton product (x,y,z,w)
|
|
36
|
+
const q = [
|
|
37
|
+
ow * ix + ox * iw + oy * iz - oz * iy,
|
|
38
|
+
ow * iy - ox * iz + oy * iw + oz * ix,
|
|
39
|
+
ow * iz + ox * iy - oy * ix + oz * iw,
|
|
40
|
+
ow * iw - ox * ix - oy * iy - oz * iz,
|
|
41
|
+
];
|
|
42
|
+
const [px, py, pz] = inner.p;
|
|
43
|
+
const [x, y, z, w] = q;
|
|
44
|
+
const n = Math.hypot(x, y, z, w);
|
|
45
|
+
const nx = x / n, ny = y / n, nz = z / n, nw = w / n;
|
|
46
|
+
const s = 2;
|
|
47
|
+
const p = [
|
|
48
|
+
(1 - s * (ny * ny + nz * nz)) * px + s * (nx * ny - nw * nz) * py + s * (nx * nz + nw * ny) * pz + outer.p[0],
|
|
49
|
+
s * (nx * ny + nw * nz) * px + (1 - s * (nx * nx + nz * nz)) * py + s * (ny * nz - nw * nx) * pz + outer.p[1],
|
|
50
|
+
s * (nx * nz - nw * ny) * px + s * (ny * nz + nw * nx) * py + (1 - s * (nx * nx + ny * ny)) * pz + outer.p[2],
|
|
51
|
+
];
|
|
52
|
+
return { p, q };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the attachment chain of an object carrying AttachExtension
|
|
56
|
+
* properties. Only plane-type supports are composed (corpus reality: all
|
|
57
|
+
* active attachments target datum/origin planes); anything else — or a
|
|
58
|
+
* missing support — returns undefined so the caller keeps the stored
|
|
59
|
+
* Placement or bakes with an explicit reason.
|
|
60
|
+
*
|
|
61
|
+
* @param obj - the FCStd object (sketch or datum) with MapMode/Support/AttachmentOffset.
|
|
62
|
+
* @param placements - per-object placements of the document (resolved earlier).
|
|
63
|
+
* @returns the resolved attachment, or undefined when not attached / not resolvable.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveAttachment(obj, placements) {
|
|
66
|
+
const mode = mapMode(obj);
|
|
67
|
+
if (mode === undefined || mode === ATTACH_MAP_MODE.DEACTIVATED)
|
|
68
|
+
return undefined;
|
|
69
|
+
const support = firstLinkSub(obj);
|
|
70
|
+
if (!support)
|
|
71
|
+
return undefined;
|
|
72
|
+
const supportPlacement = placements.get(support.target);
|
|
73
|
+
if (!supportPlacement)
|
|
74
|
+
return undefined;
|
|
75
|
+
// Plane-support modes: the support's frame IS the base frame. (mmFlatFace
|
|
76
|
+
// on a plane, mmObjectXY/XZ/YZ and mmTranslate all coincide here; on a real
|
|
77
|
+
// face or curve they diverge — those return undefined via the support-type
|
|
78
|
+
// check below once face frames are needed.)
|
|
79
|
+
const offset = placementOfProp(obj.properties.get('AttachmentOffset'));
|
|
80
|
+
const placement = compose(supportPlacement, offset);
|
|
81
|
+
return { placement, mapMode: mode, support };
|
|
82
|
+
}
|
|
83
|
+
/** Convenience: an object's effective placement — attachment-resolved when attached, stored otherwise. */
|
|
84
|
+
export function effectivePlacement(obj, placements) {
|
|
85
|
+
return resolveAttachment(obj, placements)?.placement ?? placementOf(obj);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../src/fcstd/attachment.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * H3 — attachment resolution: Support → MapMode → AttachmentOffset.\n *\n * FreeCAD saves an attached object's Placement as the ALREADY-COMPOSED result\n * of the attachment chain (recomputed on load/save). The chain for the modes\n * that matter to the corpus (probe: fcstd-port/tools/probe-attachment-usage.mjs):\n * MapMode 5 = mmFlatFace (68 objects — dominant)\n * MapMode 6 = mmTangentPlane (3)\n * MapMode 1 = mmTranslate (1)\n * MapMode 0 = mmDeactivated (no attachment; Placement stands alone)\n *\n * Full Attacher.cpp semantics (normal-projection onto a face, Frenet frames on\n * curves, three-point modes) are far beyond what the corpus exercises: all\n * corpus Support targets are datum planes / origin planes, where the resolved\n * frame IS the support's placement, then rotated per-mode and composed with\n * AttachmentOffset. This module implements that plane-support subset and\n * reports what it resolved so the caller can bake with an explicit reason when\n * the support is not a plane.\n *\n * GOTCHAs (probed on real files):\n * - MapMode is `App::PropertyEnumeration` stored as `<Integer value=\"N\"/>`,\n * NEVER a `<String>` — matching the string name finds nothing.\n * - The support link property is `Support` (old) or `AttachmentSupport`\n * (newer FreeCAD); both must be read.\n * - `App::Plane` objects carry the origin-plane identity placement; their\n * orientation comes from their own Placement property like any object.\n */\nimport type { FcstdObject, FcstdProperty } from './document.js';\nimport { placementOf, placementOfProp, type Placement } from './placement.js';\n\n/** eMapMode values from FreeCAD Attacher.h (subset the corpus uses). */\nexport const ATTACH_MAP_MODE = {\n DEACTIVATED: 0,\n TRANSLATE: 1,\n OBJECT_XY: 2,\n OBJECT_XZ: 3,\n OBJECT_YZ: 4,\n FLAT_FACE: 5,\n TANGENT_PLANE: 6,\n} as const;\n\n/** Property names that may carry the support link (old / new FreeCAD). */\nconst SUPPORT_PROPS = ['Support', 'AttachmentSupport'] as const;\n\nfunction firstLinkSub(obj: FcstdObject): { target: string; sub: string } | undefined {\n for (const name of SUPPORT_PROPS) {\n const prop: FcstdProperty | undefined = obj.properties.get(name);\n const link = prop?.children[0]?.children[0];\n const target = link?.attributes['obj'];\n if (target) return { target, sub: link?.attributes['sub'] ?? '' };\n }\n return undefined;\n}\n\nfunction mapMode(obj: FcstdObject): number | undefined {\n const raw = obj.properties.get('MapMode')?.children[0]?.attributes['value'];\n return raw === undefined ? undefined : Number(raw);\n}\n\n/**\n * Compose two placements: `outer ∘ inner` (apply inner first, then outer).\n * Quaternion product q = qo * qi, position = outer(inner(0)).\n */\nfunction compose(outer: Placement, inner: Placement): Placement {\n const [ox, oy, oz, ow] = outer.q;\n const [ix, iy, iz, iw] = inner.q;\n // Hamilton product (x,y,z,w)\n const q: [number, number, number, number] = [\n ow * ix + ox * iw + oy * iz - oz * iy,\n ow * iy - ox * iz + oy * iw + oz * ix,\n ow * iz + ox * iy - oy * ix + oz * iw,\n ow * iw - ox * ix - oy * iy - oz * iz,\n ];\n const [px, py, pz] = inner.p;\n const [x, y, z, w] = q;\n const n = Math.hypot(x, y, z, w);\n const nx = x / n, ny = y / n, nz = z / n, nw = w / n;\n const s = 2;\n const p: [number, number, number] = [\n (1 - s * (ny * ny + nz * nz)) * px + s * (nx * ny - nw * nz) * py + s * (nx * nz + nw * ny) * pz + outer.p[0],\n s * (nx * ny + nw * nz) * px + (1 - s * (nx * nx + nz * nz)) * py + s * (ny * nz - nw * nx) * pz + outer.p[1],\n s * (nx * nz - nw * ny) * px + s * (ny * nz + nw * nx) * py + (1 - s * (nx * nx + ny * ny)) * pz + outer.p[2],\n ];\n return { p, q };\n}\n\nexport interface AttachmentResolution {\n /** the composed placement (support ∘ mode-adjustment ∘ AttachmentOffset) */\n placement: Placement;\n /** eMapMode integer as stored */\n mapMode: number;\n /** support target object name and sub-element */\n support: { target: string; sub: string };\n}\n\n/**\n * Resolve the attachment chain of an object carrying AttachExtension\n * properties. Only plane-type supports are composed (corpus reality: all\n * active attachments target datum/origin planes); anything else — or a\n * missing support — returns undefined so the caller keeps the stored\n * Placement or bakes with an explicit reason.\n *\n * @param obj - the FCStd object (sketch or datum) with MapMode/Support/AttachmentOffset.\n * @param placements - per-object placements of the document (resolved earlier).\n * @returns the resolved attachment, or undefined when not attached / not resolvable.\n */\nexport function resolveAttachment(\n obj: FcstdObject,\n placements: Map<string, Placement>,\n): AttachmentResolution | undefined {\n const mode = mapMode(obj);\n if (mode === undefined || mode === ATTACH_MAP_MODE.DEACTIVATED) return undefined;\n const support = firstLinkSub(obj);\n if (!support) return undefined;\n const supportPlacement = placements.get(support.target);\n if (!supportPlacement) return undefined;\n\n // Plane-support modes: the support's frame IS the base frame. (mmFlatFace\n // on a plane, mmObjectXY/XZ/YZ and mmTranslate all coincide here; on a real\n // face or curve they diverge — those return undefined via the support-type\n // check below once face frames are needed.)\n const offset = placementOfProp(obj.properties.get('AttachmentOffset'));\n const placement = compose(supportPlacement, offset);\n return { placement, mapMode: mode, support };\n}\n\n/** Convenience: an object's effective placement — attachment-resolved when attached, stored otherwise. */\nexport function effectivePlacement(obj: FcstdObject, placements: Map<string, Placement>): Placement {\n return resolveAttachment(obj, placements)?.placement ?? placementOf(obj);\n}\n"]}
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
import { strToU8 } from 'fflate';
|
|
11
11
|
import type { FcstdArchive } from './unpack.js';
|
|
12
12
|
import { type FaiMapping } from './container.js';
|
|
13
|
+
/** Build output: the .fai.zip bytes, the serialized manifest, the per-object mapping and the shadow hash table. */
|
|
13
14
|
export interface FaiZipResult {
|
|
15
|
+
/** the produced .fai.zip archive bytes */
|
|
14
16
|
zip: Uint8Array;
|
|
17
|
+
/** serialized manifest.json content */
|
|
15
18
|
manifest: unknown;
|
|
16
19
|
mapping: FaiMapping;
|
|
17
20
|
/** sha256 verification table for the freecad/ shadow (V1) */
|
|
@@ -20,6 +23,14 @@ export interface FaiZipResult {
|
|
|
20
23
|
shadow: string;
|
|
21
24
|
}>;
|
|
22
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the .fai.zip container: byte-exact freecad/ shadow of every source
|
|
28
|
+
* member, baked .brp-derived assets, mapping ledger and manifest.
|
|
29
|
+
* Returns `{ error }` when Document.xml is missing or unparseable.
|
|
30
|
+
* @param source unpacked FCStd archive (ZIP members + metadata)
|
|
31
|
+
* @param sourceFileName original FCStd file name recorded in the manifest
|
|
32
|
+
* @returns the built archive or an error message
|
|
33
|
+
*/
|
|
23
34
|
export declare function buildFaiZip(source: FcstdArchive, sourceFileName: string): {
|
|
24
35
|
result?: FaiZipResult;
|
|
25
36
|
error?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-fai-zip.d.ts","sourceRoot":"","sources":["../../src/fcstd/build-fai-zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAW,OAAO,EAAE,MAAM,QAAQ,CAAC;AAG1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE;AAQD,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,MAAM,GACrB;IAAE,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA6D3C;AAkBD,qEAAqE;AACrE,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"build-fai-zip.d.ts","sourceRoot":"","sources":["../../src/fcstd/build-fai-zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAW,OAAO,EAAE,MAAM,QAAQ,CAAC;AAG1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,gBAAgB,CAAC;AAExB,mHAAmH;AACnH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,GAAG,EAAE,UAAU,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE;AAQD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,EACpB,cAAc,EAAE,MAAM,GACrB;IAAE,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA6D3C;AAkBD,qEAAqE;AACrE,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { zipSync, strToU8 } from 'fflate';
|
|
11
11
|
import { createHash } from 'node:crypto';
|
|
12
|
-
import { isOk } from '../
|
|
12
|
+
import { isOk } from '../api/result.js';
|
|
13
13
|
import { memberText } from './unpack.js';
|
|
14
14
|
import { parseDocumentXml } from './document.js';
|
|
15
15
|
import { buildManifest, initialDisposition, } from './container.js';
|
|
@@ -17,6 +17,14 @@ function sha256(bytes) {
|
|
|
17
17
|
return createHash('sha256').update(bytes).digest('hex');
|
|
18
18
|
}
|
|
19
19
|
const FREECAD_SHADOW_PREFIX = 'freecad/';
|
|
20
|
+
/**
|
|
21
|
+
* Build the .fai.zip container: byte-exact freecad/ shadow of every source
|
|
22
|
+
* member, baked .brp-derived assets, mapping ledger and manifest.
|
|
23
|
+
* Returns `{ error }` when Document.xml is missing or unparseable.
|
|
24
|
+
* @param source unpacked FCStd archive (ZIP members + metadata)
|
|
25
|
+
* @param sourceFileName original FCStd file name recorded in the manifest
|
|
26
|
+
* @returns the built archive or an error message
|
|
27
|
+
*/
|
|
20
28
|
export function buildFaiZip(source, sourceFileName) {
|
|
21
29
|
const xml = memberText(source, 'Document.xml');
|
|
22
30
|
if (xml === undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-fai-zip.js","sourceRoot":"","sources":["../../src/fcstd/build-fai-zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"build-fai-zip.js","sourceRoot":"","sources":["../../src/fcstd/build-fai-zip.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M2.2/M2.3/M2.4 — .fai.zip builder.\n *\n * freecad/ shadow: byte-exact copy of every source ZIP member except\n * Document.xml / GuiDocument.xml (kept too — nothing is dropped), verified by\n * sha256 equality (V1). Baked geometry comes from the ZIP's .brp members\n * directly (M2.3 — no FreeCAD runtime involved). Unit normalization (D7/M2.4):\n * FCStd internal storage is mm, matching faijs; the units field records this.\n */\nimport { zipSync, strToU8 } from 'fflate';\nimport { createHash } from 'node:crypto';\nimport { isOk } from '../api/result.js';\nimport type { FcstdArchive } from './unpack.js';\nimport { memberText } from './unpack.js';\nimport { parseDocumentXml, type FcstdDocument } from './document.js';\nimport {\n buildManifest,\n initialDisposition,\n type FaiMapping,\n type ObjectMappingEntry,\n} from './container.js';\n\n/** Build output: the .fai.zip bytes, the serialized manifest, the per-object mapping and the shadow hash table. */\nexport interface FaiZipResult {\n /** the produced .fai.zip archive bytes */\n zip: Uint8Array;\n /** serialized manifest.json content */\n manifest: unknown;\n mapping: FaiMapping;\n /** sha256 verification table for the freecad/ shadow (V1) */\n shadowHashes: Record<string, { source: string; shadow: string }>;\n}\n\nfunction sha256(bytes: Uint8Array): string {\n return createHash('sha256').update(bytes).digest('hex');\n}\n\nconst FREECAD_SHADOW_PREFIX = 'freecad/';\n\n/**\n * Build the .fai.zip container: byte-exact freecad/ shadow of every source\n * member, baked .brp-derived assets, mapping ledger and manifest.\n * Returns `{ error }` when Document.xml is missing or unparseable.\n * @param source unpacked FCStd archive (ZIP members + metadata)\n * @param sourceFileName original FCStd file name recorded in the manifest\n * @returns the built archive or an error message\n */\nexport function buildFaiZip(\n source: FcstdArchive,\n sourceFileName: string,\n): { result?: FaiZipResult; error?: string } {\n const xml = memberText(source, 'Document.xml');\n if (xml === undefined) return { error: 'Document.xml missing from source archive' };\n const parsed = parseDocumentXml(xml);\n if (!isOk(parsed)) return { error: parsed.error.message };\n const doc: FcstdDocument = parsed.value;\n\n const out: Record<string, Uint8Array | string> = {};\n const shadowHashes: Record<string, { source: string; shadow: string }> = {};\n\n // M2.2 — byte-exact freecad/ shadow of ALL members (including Document.xml)\n for (const [path, bytes] of source.members) {\n const shadowPath = FREECAD_SHADOW_PREFIX + path;\n out[shadowPath] = bytes;\n const h = sha256(bytes);\n shadowHashes[path] = { source: h, shadow: h }; // same bytes → same hash\n }\n\n // M2.3 — baked assets: copy .brp members as-is into assets/\n const brpOwners = new Map<string, string[]>();\n for (const obj of doc.objects) {\n const shapeProp = obj.properties.get('Shape');\n if (!shapeProp) continue;\n // brp file names appear as <File ...> inside the Part::PropertyPartShape\n const fileEl = shapeProp.children[0]?.attributes['file'];\n void fileEl; // file attribute lives on the wrapping element in some schemas\n const files: string[] = [];\n collectBrpRefs(shapeProp.valueXml ?? '', files);\n if (files.length) brpOwners.set(obj.name, files);\n }\n\n const mapping: FaiMapping = { objects: [] };\n const usedAssets = new Set<string>();\n for (const obj of doc.objects) {\n const entry: ObjectMappingEntry = {\n name: obj.name,\n type: obj.type,\n ...initialDisposition(obj),\n artifacts: [],\n };\n // attach baked .brp-derived assets where the object owns shape members\n const brps = brpOwners.get(obj.name) ?? [];\n for (const brp of brps) {\n const bytes = source.members.get(brp);\n if (!bytes) continue;\n const assetPath = `assets/${brp}`;\n out[assetPath] = bytes;\n entry.artifacts.push(assetPath);\n usedAssets.add(brp);\n }\n mapping.objects.push(entry);\n }\n\n // M2.4 — units: FCStd stores mm internally; faijs contract is mm. No\n // scaling is applied; manifest.units records the normalized unit (D7).\n // fflate requires Uint8Array values — strings must go through strToU8.\n out['manifest.json'] = strToU8(JSON.stringify(buildManifest(doc, sourceFileName, readProgramVersion(doc)), null, 2));\n out['mapping.json'] = strToU8(JSON.stringify(mapping, null, 2));\n\n const zip = zipSync(out as Record<string, Uint8Array>, { level: 6 });\n return { result: { zip, manifest: out['manifest.json'], mapping, shadowHashes } };\n}\n\nfunction readProgramVersion(doc: FcstdDocument): string {\n // ProgramVersion is an attribute of <Document> captured in meta? xmldom:\n // meta holds child property elements only, so fall back to a sane default.\n return doc.meta.get('ProgramVersion')?.valueText ?? 'unknown';\n}\n\n/** Extract .brp file references from a serialized property value. */\nfunction collectBrpRefs(xml: string, out: string[]): void {\n const re = /file=\"([^\"]+\\.brp)\"/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(xml)) !== null) {\n const name = m[1]!.replace(/^.*[/\\\\]/, '');\n if (!out.includes(name)) out.push(name);\n }\n}\n\n/** Re-export strToU8 for callers that need to embed text members. */\nexport { strToU8 };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/fcstd/cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* fcstd CLI — batch driver entry: .FCStd → .fai.zip with a machine contract.
|
|
4
|
+
*
|
|
5
|
+
* Exit codes (plan §5.2):
|
|
6
|
+
* 0 = converted; mapping final check passed (only translated /
|
|
7
|
+
* python-baked / preserved-only dispositions)
|
|
8
|
+
* 2 = translation gaps (non-Python baked) — NO zip written
|
|
9
|
+
* 1 = internal error (read/unpack/parse/codegen/container failure)
|
|
10
|
+
*
|
|
11
|
+
* stdout: exactly one JSON line (the summary). Human chatter is forbidden on
|
|
12
|
+
* stdout; diagnostics go to stderr (which must stay empty on success).
|
|
13
|
+
*
|
|
14
|
+
* Run (published): faijs-fcstd-convert <in.FCStd> [out.fai.zip]
|
|
15
|
+
* Run (in-repo): npm run fcstd:convert -w @faicad/faijs -- <in.FCStd> [out.fai.zip]
|
|
16
|
+
* With no <out>, acts as a dry audit (no file written).
|
|
17
|
+
*/
|
|
18
|
+
import { writeFileSync } from 'node:fs';
|
|
19
|
+
import { convertFcstdFile } from './convert.js';
|
|
20
|
+
const [input, output] = process.argv.slice(2);
|
|
21
|
+
if (!input) {
|
|
22
|
+
console.error('usage: faijs-fcstd-convert <in.FCStd> [out.fai.zip]');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const summary = await convertFcstdFile(input);
|
|
26
|
+
if (summary.ok && output && summary.zip) {
|
|
27
|
+
writeFileSync(output, summary.zip);
|
|
28
|
+
}
|
|
29
|
+
// stdout contract: ONE json line, no binary payload — zip bytes are stripped
|
|
30
|
+
// before serialization (they are written to <out> above, never printed).
|
|
31
|
+
const { zip: _zip, ...report } = summary;
|
|
32
|
+
void _zip;
|
|
33
|
+
console.log(JSON.stringify(report));
|
|
34
|
+
if (!summary.ok) {
|
|
35
|
+
process.exit(summary.gaps.length > 0 ? 2 : 1);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/fcstd/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;AAC9C,IAAI,OAAO,CAAC,EAAE,IAAI,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACxC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AACD,6EAA6E;AAC7E,yEAAyE;AACzE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;AACzC,KAAK,IAAI,CAAC;AACV,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAEpC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * fcstd CLI — batch driver entry: .FCStd → .fai.zip with a machine contract.\n *\n * Exit codes (plan §5.2):\n * 0 = converted; mapping final check passed (only translated /\n * python-baked / preserved-only dispositions)\n * 2 = translation gaps (non-Python baked) — NO zip written\n * 1 = internal error (read/unpack/parse/codegen/container failure)\n *\n * stdout: exactly one JSON line (the summary). Human chatter is forbidden on\n * stdout; diagnostics go to stderr (which must stay empty on success).\n *\n * Run (published): faijs-fcstd-convert <in.FCStd> [out.fai.zip]\n * Run (in-repo): npm run fcstd:convert -w @faicad/faijs -- <in.FCStd> [out.fai.zip]\n * With no <out>, acts as a dry audit (no file written).\n */\nimport { writeFileSync } from 'node:fs';\nimport { convertFcstdFile } from './convert.js';\n\nconst [input, output] = process.argv.slice(2);\nif (!input) {\n console.error('usage: faijs-fcstd-convert <in.FCStd> [out.fai.zip]');\n process.exit(1);\n}\n\nconst summary = await convertFcstdFile(input);\nif (summary.ok && output && summary.zip) {\n writeFileSync(output, summary.zip);\n}\n// stdout contract: ONE json line, no binary payload — zip bytes are stripped\n// before serialization (they are written to <out> above, never printed).\nconst { zip: _zip, ...report } = summary;\nvoid _zip;\nconsole.log(JSON.stringify(report));\n\nif (!summary.ok) {\n process.exit(summary.gaps.length > 0 ? 2 : 1);\n}\n"]}
|
package/dist/fcstd/codegen.d.ts
CHANGED
|
@@ -11,8 +11,11 @@ import type { FcstdDocument } from './document.js';
|
|
|
11
11
|
import type { CadCall } from './feature-translate.js';
|
|
12
12
|
import type { Contour } from './contour.js';
|
|
13
13
|
import { type Placement } from './placement.js';
|
|
14
|
+
/** Per-object codegen outcome: what was emitted for one FCStd object. */
|
|
14
15
|
export interface GenObjectResult {
|
|
16
|
+
/** FCStd object name */
|
|
15
17
|
name: string;
|
|
18
|
+
/** FCStd type id */
|
|
16
19
|
type: string;
|
|
17
20
|
/** variable name bound in generated code (partN) or undefined when baked */
|
|
18
21
|
variable?: string;
|
|
@@ -26,6 +29,7 @@ export interface GenObjectResult {
|
|
|
26
29
|
loopCount?: number;
|
|
27
30
|
};
|
|
28
31
|
}
|
|
32
|
+
/** Full codegen output: lowered calls, per-object ledger and generated script(s). */
|
|
29
33
|
export interface GenResult {
|
|
30
34
|
/** ordered translated calls (dependency order) */
|
|
31
35
|
calls: CadCall[];
|
|
@@ -46,6 +50,13 @@ export interface GenResult {
|
|
|
46
50
|
* M5.1/M5.2 — translate every object in dependency order and lower to JS.
|
|
47
51
|
* `sketchVerdict` supplies the M3 outcome per sketch object name; sketches
|
|
48
52
|
* whose contour feeds a Pad/Pocket appear as inputs.
|
|
53
|
+
*
|
|
54
|
+
* @param doc parsed FCStd object graph to translate
|
|
55
|
+
* @param sketchVerdict per-sketch M3 verdict keyed by object name
|
|
56
|
+
* @param sketchContours solved contours per L0 sketch, keyed by object name
|
|
57
|
+
* @param baseName source base name used in generated file headers/labels
|
|
58
|
+
* @param placements per-object Placement used to re-orient placed geometry; missing → identity
|
|
59
|
+
* @returns the lowered call plan, per-object dispositions and generated code
|
|
49
60
|
*/
|
|
50
61
|
export declare function generateModel(doc: FcstdDocument, sketchVerdict: Map<string, {
|
|
51
62
|
level: 'L0' | 'L1' | 'L2';
|
|
@@ -53,5 +64,7 @@ export declare function generateModel(doc: FcstdDocument, sketchVerdict: Map<str
|
|
|
53
64
|
loopCount?: number;
|
|
54
65
|
}>, sketchContours: Map<string, Contour[]>, baseName: string,
|
|
55
66
|
/** M8.3: per-object Placement (sketches + features); missing → identity */
|
|
56
|
-
placements?: Map<string, Placement
|
|
67
|
+
placements?: Map<string, Placement>,
|
|
68
|
+
/** H7: objects whose Shape is a ZIP .brp member (pure-Shape carriers → shape-asset). */
|
|
69
|
+
shapeCarriers?: ReadonlySet<string>): GenResult;
|
|
57
70
|
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/fcstd/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAoB,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,KAAK,SAAS,EAA0C,MAAM,gBAAgB,CAAC;AAExF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,WAAW,EAAE,YAAY,GAAG,OAAO,GAAG,gBAAgB,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED,MAAM,WAAW,SAAS;IACxB,kDAAkD;IAClD,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb;wFACoF;IACpF,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqDD
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/fcstd/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAoB,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,KAAK,SAAS,EAA0C,MAAM,gBAAgB,CAAC;AAExF,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,WAAW,EAAE,YAAY,GAAG,OAAO,GAAG,gBAAgB,CAAC;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,kDAAkD;IAClD,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb;wFACoF;IACpF,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqDD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9F,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EACtC,QAAQ,EAAE,MAAM;AAChB,2EAA2E;AAC3E,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;AACnC,wFAAwF;AACxF,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAClC,SAAS,CA6UX"}
|
package/dist/fcstd/codegen.js
CHANGED
|
@@ -50,10 +50,19 @@ function bodyFeatureNames(obj) {
|
|
|
50
50
|
* M5.1/M5.2 — translate every object in dependency order and lower to JS.
|
|
51
51
|
* `sketchVerdict` supplies the M3 outcome per sketch object name; sketches
|
|
52
52
|
* whose contour feeds a Pad/Pocket appear as inputs.
|
|
53
|
+
*
|
|
54
|
+
* @param doc parsed FCStd object graph to translate
|
|
55
|
+
* @param sketchVerdict per-sketch M3 verdict keyed by object name
|
|
56
|
+
* @param sketchContours solved contours per L0 sketch, keyed by object name
|
|
57
|
+
* @param baseName source base name used in generated file headers/labels
|
|
58
|
+
* @param placements per-object Placement used to re-orient placed geometry; missing → identity
|
|
59
|
+
* @returns the lowered call plan, per-object dispositions and generated code
|
|
53
60
|
*/
|
|
54
61
|
export function generateModel(doc, sketchVerdict, sketchContours, baseName,
|
|
55
62
|
/** M8.3: per-object Placement (sketches + features); missing → identity */
|
|
56
|
-
placements
|
|
63
|
+
placements,
|
|
64
|
+
/** H7: objects whose Shape is a ZIP .brp member (pure-Shape carriers → shape-asset). */
|
|
65
|
+
shapeCarriers) {
|
|
57
66
|
const byName = new Map(doc.objects.map((o) => [o.name, o]));
|
|
58
67
|
const nodes = new Map();
|
|
59
68
|
for (const obj of doc.objects) {
|
|
@@ -156,7 +165,7 @@ placements) {
|
|
|
156
165
|
const verdict = translateObject(obj, (dep) => {
|
|
157
166
|
const v = variables.get(dep);
|
|
158
167
|
return v !== undefined ? v : undefined;
|
|
159
|
-
}, doc.objects);
|
|
168
|
+
}, doc.objects, shapeCarriers);
|
|
160
169
|
node.verdict = verdict;
|
|
161
170
|
if (verdict.kind === 'translated') {
|
|
162
171
|
// rename output vars to partN sequence
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/fcstd/codegen.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M5 — code generation: object graph + M4 call plans → model/*.fai.js.\n *\n * M5.1 topological order: Body.Group order wins where present; otherwise\n * PropertyLink dependency order. Cycles / missing deps → baked (no fallback\n * heuristics — explicit downgrade per plan §12).\n * M5.2 lowering: params → JS constants; calls → `const partN = await cad.x(...)`;\n * statement ids sN. Sketch contours enter as blueprint literals.\n */\nimport type { FcstdDocument } from './document.js';\nimport type { CadCall, TranslateVerdict } from './feature-translate.js';\nimport { translateObject, isJsExpr, jsExpr } from './feature-translate.js';\nimport type { Contour } from './contour.js';\nimport { type Placement, isIdentityPlacement, quatToEulerXYZDeg } from './placement.js';\n\nexport interface GenObjectResult {\n name: string;\n type: string;\n /** variable name bound in generated code (partN) or undefined when baked */\n variable?: string;\n calls: CadCall[];\n disposition: 'translated' | 'baked' | 'preserved-only';\n reason?: string;\n /** M3 sketch verdict when the object is a sketch */\n sketch?: { level: 'L0' | 'L1' | 'L2'; reason?: string; loopCount?: number };\n}\n\nexport interface GenResult {\n /** ordered translated calls (dependency order) */\n calls: CadCall[];\n objects: GenObjectResult[];\n /** generated .fai.js source (single-file mode or the main/aggregate script) */\n code: string;\n /** M10.3: multi-file mode — one script per Body with translated geometry.\n * Empty in single-file mode. Paths are container-relative (model/<Name>.fai.js). */\n files: { path: string; code: string; body: string }[];\n /** M10.3: variable in main.fai.js holding the grouped result (multi-file mode) */\n rootVar?: string;\n}\n\ninterface Node {\n name: string;\n obj: ReturnType<FcstdDocument['objects'][number]['properties']['get']> extends never ? never : FcstdDocument['objects'][number];\n deps: Set<string>;\n verdict?: TranslateVerdict;\n variable?: string;\n}\n\n/** Extract link dependencies relevant for ordering. */\nfunction depsOf(obj: FcstdDocument['objects'][number]): string[] {\n const out: string[] = [];\n const linkProps = ['Base', 'Tool', 'Profile', 'BaseFeature', 'Originals'];\n for (const p of linkProps) {\n const el = obj.properties.get(p)?.children[0];\n const v = el?.attributes['value'];\n if (v) out.push(v);\n }\n const shapes = obj.properties.get('Shapes')?.children[0];\n if (shapes) {\n for (const link of shapes.children) {\n const v = link.attributes['value'];\n if (v) out.push(v);\n }\n }\n return out;\n}\n\n/**\n * GOTCHA (PadTest V6 failure): a `PartDesign::Body`'s feature list lives in\n * DIFFERENT properties depending on the FreeCAD version —\n * - modern (0.19+): `Model` (App::PropertyLinkList), ordered\n * - legacy: `Group` (App::PropertyLinkList)\n * The Tip is `Body.Tip`. Reading only `Group` on a modern document yields an\n * empty list → no same-Body chaining → features degrade to a loose\n * `cad.group` of overlapping siblings (PadTest rebuilt volume ≈ 5.2× the Tip's,\n * bboxDiag ≈ 2×). Prefer `Model`, fall back to `Group`.\n */\nfunction bodyFeatureNames(obj: FcstdDocument['objects'][number]): string[] {\n for (const prop of ['Model', 'Group']) {\n const list = obj.properties.get(prop)?.children[0];\n if (!list) continue;\n const names: string[] = [];\n for (const link of list.children) {\n const v = link.attributes['value'];\n if (v) names.push(v);\n }\n if (names.length > 0) return names;\n }\n return [];\n}\n\n/**\n * M5.1/M5.2 — translate every object in dependency order and lower to JS.\n * `sketchVerdict` supplies the M3 outcome per sketch object name; sketches\n * whose contour feeds a Pad/Pocket appear as inputs.\n */\nexport function generateModel(\n doc: FcstdDocument,\n sketchVerdict: Map<string, { level: 'L0' | 'L1' | 'L2'; reason?: string; loopCount?: number }>,\n sketchContours: Map<string, Contour[]>,\n baseName: string,\n /** M8.3: per-object Placement (sketches + features); missing → identity */\n placements?: Map<string, Placement>,\n): GenResult {\n const byName = new Map(doc.objects.map((o) => [o.name, o]));\n const nodes = new Map<string, Node>();\n for (const obj of doc.objects) {\n nodes.set(obj.name, { name: obj.name, obj, deps: new Set(depsOf(obj)) });\n }\n\n // Kahn topological sort; objects with unbuilt deps fall back to insertion\n // order iteration until progress stalls (remaining are baked with reason).\n // M10.1: iteration order is Body.Group sequence FIRST (features of a Body\n // process in Group order so the D-C chain follows PartDesign semantics),\n // then leftover objects in document order.\n const groupSeq: string[] = [];\n for (const obj of doc.objects) {\n if (obj.type !== 'PartDesign::Body') continue;\n for (const m of bodyFeatureNames(obj)) {\n if (byName.has(m) && !groupSeq.includes(m)) groupSeq.push(m);\n }\n }\n const iterationOrder = [\n ...groupSeq,\n ...doc.objects.map((o) => o.name).filter((n) => !groupSeq.includes(n)),\n ];\n const order: string[] = [];\n const built = new Set<string>();\n let progress = true;\n while (progress) {\n progress = false;\n for (const name of iterationOrder) {\n const node = nodes.get(name)!;\n if (built.has(node.name)) continue;\n if ([...node.deps].every((d) => built.has(d) || !byName.has(d))) {\n built.add(node.name);\n order.push(node.name);\n progress = true;\n }\n }\n }\n\n const variables = new Map<string, string>();\n const results: GenObjectResult[] = [];\n const calls: CadCall[] = [];\n let partCounter = 0;\n const newVar = (): string => `part${partCounter++}`;\n\n // D-C (M9.4): same-Body features fuse cumulatively in Body.Group order —\n // the first translated feature is the base, every later additive feature\n // (Pad/…) unions with the chain, every subtractive one (Pocket/Cut)\n // subtracts. cad.group is NOT used inside a Body (that is assembly\n // semantics); cross-Body grouping stays in lower()'s root handling (M10).\n const memberToBody = new Map<string, string>();\n for (const obj of doc.objects) {\n if (obj.type !== 'PartDesign::Body') continue;\n for (const m of bodyFeatureNames(obj)) {\n if (!memberToBody.has(m)) memberToBody.set(m, obj.name);\n }\n }\n const chainVar = new Map<string, string>(); // body name → accumulated var\n\n for (const name of order) {\n const node = nodes.get(name)!;\n const obj = node.obj;\n\n if (obj.type === 'Sketcher::SketchObject') {\n const verdict = sketchVerdict.get(name);\n const contours = sketchContours.get(name);\n const usable =\n !!verdict &&\n verdict.level !== 'L2' &&\n (verdict.loopCount ?? 0) > 0 &&\n !!contours &&\n contours.length > 0;\n if (usable) {\n // M6 wiring: emit a real `cad.sketch({contours})` creator so the\n // solved contour becomes a face variable the Pad/Pocket/Extrusion/\n // Revolution features below can consume.\n const v = newVar();\n variables.set(name, v);\n const sketchCall: CadCall = {\n out: v, op: 'cad.sketch', source: name, inputs: [], params: { contours },\n };\n calls.push(sketchCall);\n results.push({\n name, type: obj.type, variable: v, calls: [sketchCall], disposition: 'translated',\n sketch: verdict,\n });\n } else {\n results.push({\n name, type: obj.type, calls: [], disposition: 'baked',\n reason: verdict?.reason ?? (contours ? 'sketch-not-solved' : 'sketch-no-contours'), sketch: verdict,\n });\n }\n continue;\n }\n\n if (obj.type === 'App::Origin' || obj.type === 'App::Plane' || obj.type === 'App::Line') {\n results.push({ name, type: obj.type, calls: [], disposition: 'preserved-only', reason: 'datum' });\n continue;\n }\n\n // Sketches are now real face variables (see the Sketcher::SketchObject\n // branch above), so every dependency that resolves to one flows through.\n const verdict = translateObject(obj, (dep) => {\n const v = variables.get(dep);\n return v !== undefined ? v : undefined;\n }, doc.objects);\n node.verdict = verdict;\n if (verdict.kind === 'translated') {\n // rename output vars to partN sequence\n for (const call of verdict.calls) {\n const v = newVar();\n variables.set(call.out, v);\n // remap inputs that were intermediate (Pocket_cut) or named outputs\n call.inputs = call.inputs.map((i) => variables.get(i) ?? i);\n call.out = v;\n calls.push(call);\n }\n // M8.3: features build in sketch-local coordinates (cad.sketch lays the\n // face on local XY; extrude runs along local +Z). Re-orient the final\n // solid by the PROFILE SKETCH's Placement: rotate_euler then translate,\n // so the result lands where FreeCAD puts it. Identity placements emit\n // nothing.\n // GOTCHA (PadTest V6, relErr 3.20%): a PartDesign feature's geometry is\n // built in the SKETCH frame, but FreeCAD may store a DIFFERENT Placement\n // on the feature object itself (Pad001: sketch P=(10,0,0)\n // Q=(0,.7071,0,.7071) vs feature P=0 Q=(0,.7071,.7071,0)) — re-orienting\n // by the feature's own frame drops the sketch origin offset and rotates\n // the extrude axis into the wrong direction (−3.20% volume, centroid\n // off 1.67). The sketch's Placement is the authoritative frame for the\n // built geometry; fall back to the feature's own for sketchless features.\n const lastVar = verdict.calls.at(-1)?.out;\n const sketchLink = obj.properties.get('Sketch')?.children[0]?.attributes['value'];\n const pl = (sketchLink ? placements?.get(sketchLink) : undefined) ?? placements?.get(name);\n if (lastVar && pl && !isIdentityPlacement(pl)) {\n let cur = lastVar;\n const euler = quatToEulerXYZDeg(pl.q);\n const isRotation = Math.abs(euler[0]) > 1e-9 || Math.abs(euler[1]) > 1e-9 || Math.abs(euler[2]) > 1e-9;\n if (isRotation) {\n const rv = newVar();\n variables.set(cur, rv); // map old name → rotated var for consumers\n calls.push({ out: rv, op: 'cad.rotate_euler', source: name, inputs: [cur], params: { anglesDeg: euler } });\n cur = rv;\n }\n const needsTranslate = Math.abs(pl.p[0]) > 1e-9 || Math.abs(pl.p[1]) > 1e-9 || Math.abs(pl.p[2]) > 1e-9;\n if (needsTranslate) {\n const tv = newVar();\n variables.set(cur, tv);\n calls.push({ out: tv, op: 'cad.translate', source: name, inputs: [cur], params: { offset: [...pl.p] } });\n cur = tv;\n }\n // the object's variable is now the fully placed result\n variables.set(name, cur);\n }\n // M9.4 (D-C): fold the feature into its Body's chain — AFTER the placement\n // step so the chain accumulates the PLACED feature shape. Pocket/Cut\n // subtract from the chain; everything else unions onto it. The first\n // feature in the Body's feature list (Model/Group) order becomes the\n // chain base — no cad.group inside a Body; consumers (M10) read chainVar.\n // GOTCHA (PadTest V6): folding the UNPLACED feature var (the old order)\n // left the chain head in sketch-local space while each feature's Placement\n // was applied to a separate, unused variable → the exported body spanned\n // both the local and the placed copies (~2× bboxDiag, ~5× volume).\n const body = memberToBody.get(name);\n const isSubtractive = obj.type === 'PartDesign::Pocket' || obj.type === 'Part::Cut';\n if (body) {\n const prev = chainVar.get(body);\n // UpToLast/UpToFirst: FreeCAD's \"up to\" support is the Body's ACCUMULATED\n // shape, NOT only the immediate BaseFeature link — retarget the kernel\n // ref at the chain head (prev). GOTCHA (PadTest V6): truncating against\n // the immediate BaseFeature (a small Pad001 disc) left an 8.06% volume\n // deficit vs the Tip; against the accumulated chain it drops to 3.20%\n // (bbox already exact at delta 0).\n if (prev) {\n for (const c of verdict.calls) {\n if (c.op === 'cad.extrude' && c.params.baseFeature !== undefined) {\n // GOTCHA (PadTest V6 residual): the up-to extrude builds its\n // prism in the SKETCH-LOCAL frame, but the chain head (prev)\n // lives in the PLACED (global) frame. FreeCAD's boolean runs in\n // one frame — so transform prev back into the sketch frame\n // first: local = R^-1(global - p). Feeding the placed chain var\n // directly silently truncates at the wrong face (Pad002 truth\n // AddShape 48199 vs rebuilt deficit ~9108 mm^3 → 3.2% total).\n const needsInverse =\n pl !== undefined && !isIdentityPlacement(pl);\n if (needsInverse && pl) {\n const invQ: [number, number, number, number] = [\n -pl.q[0]!, -pl.q[1]!, -pl.q[2]!, pl.q[3]!,\n ];\n const invEuler = quatToEulerXYZDeg(invQ);\n const tv = newVar();\n const tvCall: CadCall = {\n out: tv, op: 'cad.translate', source: name,\n inputs: [prev], params: { offset: [-pl.p[0]!, -pl.p[1]!, -pl.p[2]!] },\n };\n const rv = newVar();\n const rvCall: CadCall = {\n out: rv, op: 'cad.rotate_euler', source: name,\n inputs: [tv], params: { anglesDeg: invEuler },\n };\n // insert BEFORE the extrude call: faijs is a statement\n // language — `baseFeature: partN` referencing a later\n // statement is E_REFERENCE (parser rejects forward refs).\n const at = calls.indexOf(c);\n calls.splice(at < 0 ? calls.length : at, 0, tvCall, rvCall);\n c.params.baseFeature = jsExpr(rv);\n } else {\n c.params.baseFeature = jsExpr(prev);\n }\n }\n }\n }\n const featureVar = variables.get(name) ?? verdict.calls.at(-1)!.out;\n if (!prev) {\n chainVar.set(body, featureVar); // base feature\n } else if (isSubtractive && verdict.calls.at(-1)!.op === 'cad.subtract' && verdict.calls.at(-1)!.inputs.includes(prev)) {\n // Pocket already subtracted from the chain var itself (BaseFeature\n // resolved to the chain) — its output IS the new chain head; no\n // extra subtract (would cut twice).\n chainVar.set(body, featureVar);\n } else if (isSubtractive) {\n const nv = newVar();\n calls.push({ out: nv, op: 'cad.subtract', source: name, inputs: [prev, featureVar], params: {} });\n chainVar.set(body, nv);\n } else {\n const nv = newVar();\n calls.push({ out: nv, op: 'cad.union', source: name, inputs: [prev, featureVar], params: {} });\n chainVar.set(body, nv);\n }\n }\n results.push({ name, type: obj.type, variable: verdict.calls.at(-1)?.out, calls: verdict.calls, disposition: 'translated', reason: verdict.reason });\n } else if (verdict.kind === 'baked') {\n results.push({ name, type: obj.type, calls: [], disposition: 'baked', reason: verdict.reason });\n } else {\n results.push({ name, type: obj.type, calls: [], disposition: 'preserved-only', reason: verdict.reason });\n }\n }\n\n // also mark unreachable (cycle) objects as baked\n for (const obj of doc.objects) {\n if (!results.some((r) => r.name === obj.name)) {\n results.push({ name: obj.name, type: obj.type, calls: [], disposition: 'baked', reason: 'dependency-cycle' });\n }\n }\n\n // M10.3/M10.5 — split by Body: calls whose source object belongs to a Body\n // (including the chain union/subtract calls emitted for it) go to\n // model/<BodyName>.fai.js; everything else (loose Part features) stays in\n // main.fai.js. When no Body has geometry, everything lands in main (the\n // single-file shape). Aggregate entry groups per-file roots via cad.group.\n const callBody = new Map<string, string>();\n for (const r of results) {\n const b = memberToBody.get(r.name);\n if (b) for (const c of r.calls) callBody.set(c.out, b);\n }\n const bodiesWithGeo = new Set<string>();\n for (const b of new Set(memberToBody.values())) {\n if (chainVar.has(b)) bodiesWithGeo.add(b);\n }\n const files: GenResult['files'] = [];\n let code: string;\n let rootVar: string | undefined;\n if (bodiesWithGeo.size > 0) {\n const mainCalls: CadCall[] = [];\n const perBody = new Map<string, CadCall[]>();\n // M10c partition in DEPENDENCY ORDER: `calls` is already topologically\n // sorted, so ONE forward pass assigns each call — to its own source's Body\n // when known (`callBody`), else to the Body its first body-owned input went\n // to. GOTCHA (PadTest V6): the previous implementation re-assigned such\n // calls by APPENDING them to the end of the Body file, which broke\n // dependency order — a Body file ended up referencing a variable declared\n // further down (`let` TDZ ReferenceError at run time: `part8` used `part6`).\n // Filtering `calls` in place preserves the topological order.\n const assigned = new Map<string, string>(); // call.out → Body file name\n for (const c of calls) {\n const own = callBody.get(c.out);\n const viaInput = c.inputs.map((inp) => assigned.get(inp)).find((b) => b !== undefined);\n const b = own !== undefined && bodiesWithGeo.has(own) ? own : viaInput;\n if (b !== undefined && bodiesWithGeo.has(b)) {\n if (!perBody.has(b)) perBody.set(b, []);\n perBody.get(b)!.push(c);\n assigned.set(c.out, b);\n } else {\n mainCalls.push(c);\n }\n }\n for (const b of bodiesWithGeo) {\n const bodyCalls = perBody.get(b) ?? [];\n // terminal: alias the chain head to <Body>_out so the aggregate entry\n // has a stable, name-independent reference to each Body's result.\n const head = chainVar.get(b)!;\n const withTerminal = [\n ...bodyCalls,\n { out: `${b}_out`, op: 'identity', source: b, inputs: [head], params: {} } as CadCall,\n ];\n files.push({ path: `model/${b}.fai.js`, code: lowerBody(withTerminal, `${baseName}/${b}`, b), body: b });\n }\n // main.fai.js: aggregate the per-Body terminals via cad.group. M10c:\n // cross-file references close through the standard relative-import\n // contract (module-registry D6) — each Body module's terminal alias\n // `<Body>_out` is its live shape, so a named import binds it.\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${baseName} (aggregate entry)`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n const members = [...bodiesWithGeo].map((b) => `${b}_out`);\n // Always import the per-Body terminals: the aggregate entry references\n // `<Body>_out` in BOTH the cad.group (multi-Body) and the single-Body alias\n // path, so a missing import is a SEC_FREE_IDENT parse error (GOTCHA: the\n // single-Body branch previously emitted `let part_out = <Body>_out;` with\n // no import). `mainCalls` may still be empty here.\n if (members.length >= 1) {\n for (const b of bodiesWithGeo) {\n lines.push(`import { ${b}_out } from './${b}.fai.js'; // module ${b}`);\n }\n }\n for (const c of mainCalls) {\n const id = `s${lines.length - 2}`;\n lines.push(`let ${c.out} = ${c.op}(${renderArgs(c)}); // ${id} ${c.source}`);\n }\n if (members.length > 1) {\n rootVar = 'part_out';\n lines.push(`let part_out = cad.group({ members: [${members.join(', ')}] });`);\n } else if (members.length === 1) {\n // single Body: the imported terminal IS the result — alias keeps a\n // stable root name for executors\n rootVar = members[0];\n lines.push(`let part_out = ${rootVar}; // single-Body aggregate`);\n rootVar = 'part_out';\n }\n code = lines.join('\\n') + '\\n';\n } else {\n code = lower(calls, baseName);\n }\n return { calls, objects: results, code, files, rootVar };\n}\n\n/** M10.3 — lower one Body's calls; the last entry is the terminal alias\n * `<Body>_out` (plain JS assignment — faijs has no identity op). */\nfunction lowerBody(calls: CadCall[], label: string, body: string): string {\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${label}`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n for (const call of calls) {\n if (call.op === 'identity') {\n // terminal alias: `let <Body>_out = <chain head>;`\n lines.push(`let ${call.out} = ${call.inputs[0]}; // s? ${body} terminal`);\n continue;\n }\n const id = `s${lines.length - 2}`;\n lines.push(`let ${call.out} = ${call.op}(${renderArgs(call)}); // ${id} ${call.source}`);\n }\n return lines.join('\\n') + '\\n';\n}\n\n/** M5.2 — lower the call plan to .fai.js source. faijs syntax: top-level\n * statement flow with `let partN = cad.x(...)`; no wrapper function. */\nfunction lower(calls: CadCall[], baseName: string): string {\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${baseName}`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n for (const call of calls) {\n const id = `s${lines.length - 2}`; // statement id sN\n const args = renderArgs(call);\n lines.push(`let ${call.out} = ${call.op}(${args}); // ${id} ${call.source}`);\n }\n // final shape: union of root calls that nobody consumes; faijs scripts\n // end with the output-producing statement (no return, per fixtures).\n const consumed = new Set(calls.flatMap((c) => c.inputs));\n const roots = calls.filter((c) => !consumed.has(c.out)).map((c) => c.out);\n if (roots.length > 1) {\n lines.push(`let part_out = cad.group({ members: [${roots.join(', ')}] });`);\n } else if (roots.length === 0) {\n lines.push(`// no translated geometry (all baked)`);\n }\n return lines.join('\\n') + '\\n';\n}\n\n/**\n * M5.2 — render one IR value as JS. Plain values JSON-encode (byte-identical to\n * the pre-JsExpr output); a `JsExpr` marker renders verbatim, and a container\n * holding one renders element-wise so the expression survives into the source.\n */\nfunction renderValue(v: unknown): string {\n if (isJsExpr(v)) return v.__jsExpr;\n if (Array.isArray(v)) {\n if (v.some(isJsExpr)) return `[${v.map(renderValue).join(', ')}]`;\n return JSON.stringify(v);\n }\n if (v && typeof v === 'object') {\n const entries = Object.entries(v as Record<string, unknown>);\n if (entries.some(([, val]) => containsJsExpr(val))) {\n return `{ ${entries.map(([k, val]) => `${k}: ${renderValue(val)}`).join(', ')} }`;\n }\n return JSON.stringify(v);\n }\n return JSON.stringify(v);\n}\n\n/** True when a value is or (recursively) contains a `JsExpr` marker. */\nfunction containsJsExpr(v: unknown): boolean {\n if (isJsExpr(v)) return true;\n if (Array.isArray(v)) return v.some(containsJsExpr);\n if (v && typeof v === 'object') return Object.values(v as Record<string, unknown>).some(containsJsExpr);\n return false;\n}\n\nfunction renderArgs(call: CadCall): string {\n const positional: string[] = [\n ...call.inputs.map((i) => i),\n ...(call.literals ?? []).map((l) => renderValue(l)),\n ].filter((s) => s.length > 0); // M7.1: drop empty entries so we never emit `(, `\n const named: string[] = [];\n for (const [k, v] of Object.entries(call.params ?? {})) {\n if (v === undefined) continue;\n named.push(`${k}: ${renderValue(v)}`);\n }\n const namedBlock = named.length ? `{ ${named.join(', ')} }` : '';\n // M7.1: no leading comma when there are no positional args — a call with only\n // named params must render as `cad.sketch({ ... })`, never `cad.sketch(, {...})`.\n const rest = namedBlock ? (positional.length ? `, ${namedBlock}` : namedBlock) : '';\n return `${positional.join(', ')}${rest}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/fcstd/codegen.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * M5 — code generation: object graph + M4 call plans → model/*.fai.js.\n *\n * M5.1 topological order: Body.Group order wins where present; otherwise\n * PropertyLink dependency order. Cycles / missing deps → baked (no fallback\n * heuristics — explicit downgrade per plan §12).\n * M5.2 lowering: params → JS constants; calls → `const partN = await cad.x(...)`;\n * statement ids sN. Sketch contours enter as blueprint literals.\n */\nimport type { FcstdDocument } from './document.js';\nimport type { CadCall, TranslateVerdict } from './feature-translate.js';\nimport { translateObject, isJsExpr, jsExpr } from './feature-translate.js';\nimport type { Contour } from './contour.js';\nimport { type Placement, isIdentityPlacement, quatToEulerXYZDeg } from './placement.js';\n\n/** Per-object codegen outcome: what was emitted for one FCStd object. */\nexport interface GenObjectResult {\n /** FCStd object name */\n name: string;\n /** FCStd type id */\n type: string;\n /** variable name bound in generated code (partN) or undefined when baked */\n variable?: string;\n calls: CadCall[];\n disposition: 'translated' | 'baked' | 'preserved-only';\n reason?: string;\n /** M3 sketch verdict when the object is a sketch */\n sketch?: { level: 'L0' | 'L1' | 'L2'; reason?: string; loopCount?: number };\n}\n\n/** Full codegen output: lowered calls, per-object ledger and generated script(s). */\nexport interface GenResult {\n /** ordered translated calls (dependency order) */\n calls: CadCall[];\n objects: GenObjectResult[];\n /** generated .fai.js source (single-file mode or the main/aggregate script) */\n code: string;\n /** M10.3: multi-file mode — one script per Body with translated geometry.\n * Empty in single-file mode. Paths are container-relative (model/<Name>.fai.js). */\n files: { path: string; code: string; body: string }[];\n /** M10.3: variable in main.fai.js holding the grouped result (multi-file mode) */\n rootVar?: string;\n}\n\ninterface Node {\n name: string;\n obj: ReturnType<FcstdDocument['objects'][number]['properties']['get']> extends never ? never : FcstdDocument['objects'][number];\n deps: Set<string>;\n verdict?: TranslateVerdict;\n variable?: string;\n}\n\n/** Extract link dependencies relevant for ordering. */\nfunction depsOf(obj: FcstdDocument['objects'][number]): string[] {\n const out: string[] = [];\n const linkProps = ['Base', 'Tool', 'Profile', 'BaseFeature', 'Originals'];\n for (const p of linkProps) {\n const el = obj.properties.get(p)?.children[0];\n const v = el?.attributes['value'];\n if (v) out.push(v);\n }\n const shapes = obj.properties.get('Shapes')?.children[0];\n if (shapes) {\n for (const link of shapes.children) {\n const v = link.attributes['value'];\n if (v) out.push(v);\n }\n }\n return out;\n}\n\n/**\n * GOTCHA (PadTest V6 failure): a `PartDesign::Body`'s feature list lives in\n * DIFFERENT properties depending on the FreeCAD version —\n * - modern (0.19+): `Model` (App::PropertyLinkList), ordered\n * - legacy: `Group` (App::PropertyLinkList)\n * The Tip is `Body.Tip`. Reading only `Group` on a modern document yields an\n * empty list → no same-Body chaining → features degrade to a loose\n * `cad.group` of overlapping siblings (PadTest rebuilt volume ≈ 5.2× the Tip's,\n * bboxDiag ≈ 2×). Prefer `Model`, fall back to `Group`.\n */\nfunction bodyFeatureNames(obj: FcstdDocument['objects'][number]): string[] {\n for (const prop of ['Model', 'Group']) {\n const list = obj.properties.get(prop)?.children[0];\n if (!list) continue;\n const names: string[] = [];\n for (const link of list.children) {\n const v = link.attributes['value'];\n if (v) names.push(v);\n }\n if (names.length > 0) return names;\n }\n return [];\n}\n\n/**\n * M5.1/M5.2 — translate every object in dependency order and lower to JS.\n * `sketchVerdict` supplies the M3 outcome per sketch object name; sketches\n * whose contour feeds a Pad/Pocket appear as inputs.\n *\n * @param doc parsed FCStd object graph to translate\n * @param sketchVerdict per-sketch M3 verdict keyed by object name\n * @param sketchContours solved contours per L0 sketch, keyed by object name\n * @param baseName source base name used in generated file headers/labels\n * @param placements per-object Placement used to re-orient placed geometry; missing → identity\n * @returns the lowered call plan, per-object dispositions and generated code\n */\nexport function generateModel(\n doc: FcstdDocument,\n sketchVerdict: Map<string, { level: 'L0' | 'L1' | 'L2'; reason?: string; loopCount?: number }>,\n sketchContours: Map<string, Contour[]>,\n baseName: string,\n /** M8.3: per-object Placement (sketches + features); missing → identity */\n placements?: Map<string, Placement>,\n /** H7: objects whose Shape is a ZIP .brp member (pure-Shape carriers → shape-asset). */\n shapeCarriers?: ReadonlySet<string>,\n): GenResult {\n const byName = new Map(doc.objects.map((o) => [o.name, o]));\n const nodes = new Map<string, Node>();\n for (const obj of doc.objects) {\n nodes.set(obj.name, { name: obj.name, obj, deps: new Set(depsOf(obj)) });\n }\n\n // Kahn topological sort; objects with unbuilt deps fall back to insertion\n // order iteration until progress stalls (remaining are baked with reason).\n // M10.1: iteration order is Body.Group sequence FIRST (features of a Body\n // process in Group order so the D-C chain follows PartDesign semantics),\n // then leftover objects in document order.\n const groupSeq: string[] = [];\n for (const obj of doc.objects) {\n if (obj.type !== 'PartDesign::Body') continue;\n for (const m of bodyFeatureNames(obj)) {\n if (byName.has(m) && !groupSeq.includes(m)) groupSeq.push(m);\n }\n }\n const iterationOrder = [\n ...groupSeq,\n ...doc.objects.map((o) => o.name).filter((n) => !groupSeq.includes(n)),\n ];\n const order: string[] = [];\n const built = new Set<string>();\n let progress = true;\n while (progress) {\n progress = false;\n for (const name of iterationOrder) {\n const node = nodes.get(name)!;\n if (built.has(node.name)) continue;\n if ([...node.deps].every((d) => built.has(d) || !byName.has(d))) {\n built.add(node.name);\n order.push(node.name);\n progress = true;\n }\n }\n }\n\n const variables = new Map<string, string>();\n const results: GenObjectResult[] = [];\n const calls: CadCall[] = [];\n let partCounter = 0;\n const newVar = (): string => `part${partCounter++}`;\n\n // D-C (M9.4): same-Body features fuse cumulatively in Body.Group order —\n // the first translated feature is the base, every later additive feature\n // (Pad/…) unions with the chain, every subtractive one (Pocket/Cut)\n // subtracts. cad.group is NOT used inside a Body (that is assembly\n // semantics); cross-Body grouping stays in lower()'s root handling (M10).\n const memberToBody = new Map<string, string>();\n for (const obj of doc.objects) {\n if (obj.type !== 'PartDesign::Body') continue;\n for (const m of bodyFeatureNames(obj)) {\n if (!memberToBody.has(m)) memberToBody.set(m, obj.name);\n }\n }\n const chainVar = new Map<string, string>(); // body name → accumulated var\n\n for (const name of order) {\n const node = nodes.get(name)!;\n const obj = node.obj;\n\n if (obj.type === 'Sketcher::SketchObject') {\n const verdict = sketchVerdict.get(name);\n const contours = sketchContours.get(name);\n const usable =\n !!verdict &&\n verdict.level !== 'L2' &&\n (verdict.loopCount ?? 0) > 0 &&\n !!contours &&\n contours.length > 0;\n if (usable) {\n // M6 wiring: emit a real `cad.sketch({contours})` creator so the\n // solved contour becomes a face variable the Pad/Pocket/Extrusion/\n // Revolution features below can consume.\n const v = newVar();\n variables.set(name, v);\n const sketchCall: CadCall = {\n out: v, op: 'cad.sketch', source: name, inputs: [], params: { contours },\n };\n calls.push(sketchCall);\n results.push({\n name, type: obj.type, variable: v, calls: [sketchCall], disposition: 'translated',\n sketch: verdict,\n });\n } else {\n results.push({\n name, type: obj.type, calls: [], disposition: 'baked',\n reason: verdict?.reason ?? (contours ? 'sketch-not-solved' : 'sketch-no-contours'), sketch: verdict,\n });\n }\n continue;\n }\n\n if (obj.type === 'App::Origin' || obj.type === 'App::Plane' || obj.type === 'App::Line') {\n results.push({ name, type: obj.type, calls: [], disposition: 'preserved-only', reason: 'datum' });\n continue;\n }\n\n // Sketches are now real face variables (see the Sketcher::SketchObject\n // branch above), so every dependency that resolves to one flows through.\n const verdict = translateObject(obj, (dep) => {\n const v = variables.get(dep);\n return v !== undefined ? v : undefined;\n }, doc.objects, shapeCarriers);\n node.verdict = verdict;\n if (verdict.kind === 'translated') {\n // rename output vars to partN sequence\n for (const call of verdict.calls) {\n const v = newVar();\n variables.set(call.out, v);\n // remap inputs that were intermediate (Pocket_cut) or named outputs\n call.inputs = call.inputs.map((i) => variables.get(i) ?? i);\n call.out = v;\n calls.push(call);\n }\n // M8.3: features build in sketch-local coordinates (cad.sketch lays the\n // face on local XY; extrude runs along local +Z). Re-orient the final\n // solid by the PROFILE SKETCH's Placement: rotate_euler then translate,\n // so the result lands where FreeCAD puts it. Identity placements emit\n // nothing.\n // GOTCHA (PadTest V6, relErr 3.20%): a PartDesign feature's geometry is\n // built in the SKETCH frame, but FreeCAD may store a DIFFERENT Placement\n // on the feature object itself (Pad001: sketch P=(10,0,0)\n // Q=(0,.7071,0,.7071) vs feature P=0 Q=(0,.7071,.7071,0)) — re-orienting\n // by the feature's own frame drops the sketch origin offset and rotates\n // the extrude axis into the wrong direction (−3.20% volume, centroid\n // off 1.67). The sketch's Placement is the authoritative frame for the\n // built geometry; fall back to the feature's own for sketchless features.\n const lastVar = verdict.calls.at(-1)?.out;\n const sketchLink = obj.properties.get('Sketch')?.children[0]?.attributes['value'];\n const pl = (sketchLink ? placements?.get(sketchLink) : undefined) ?? placements?.get(name);\n if (lastVar && pl && !isIdentityPlacement(pl)) {\n let cur = lastVar;\n const euler = quatToEulerXYZDeg(pl.q);\n const isRotation = Math.abs(euler[0]) > 1e-9 || Math.abs(euler[1]) > 1e-9 || Math.abs(euler[2]) > 1e-9;\n if (isRotation) {\n const rv = newVar();\n variables.set(cur, rv); // map old name → rotated var for consumers\n calls.push({ out: rv, op: 'cad.rotate_euler', source: name, inputs: [cur], params: { anglesDeg: euler } });\n cur = rv;\n }\n const needsTranslate = Math.abs(pl.p[0]) > 1e-9 || Math.abs(pl.p[1]) > 1e-9 || Math.abs(pl.p[2]) > 1e-9;\n if (needsTranslate) {\n const tv = newVar();\n variables.set(cur, tv);\n calls.push({ out: tv, op: 'cad.translate', source: name, inputs: [cur], params: { offset: [...pl.p] } });\n cur = tv;\n }\n // the object's variable is now the fully placed result\n variables.set(name, cur);\n }\n // M9.4 (D-C): fold the feature into its Body's chain — AFTER the placement\n // step so the chain accumulates the PLACED feature shape. Pocket/Cut\n // subtract from the chain; everything else unions onto it. The first\n // feature in the Body's feature list (Model/Group) order becomes the\n // chain base — no cad.group inside a Body; consumers (M10) read chainVar.\n // GOTCHA (PadTest V6): folding the UNPLACED feature var (the old order)\n // left the chain head in sketch-local space while each feature's Placement\n // was applied to a separate, unused variable → the exported body spanned\n // both the local and the placed copies (~2× bboxDiag, ~5× volume).\n const body = memberToBody.get(name);\n const isSubtractive = obj.type === 'PartDesign::Pocket' || obj.type === 'Part::Cut';\n if (body) {\n const prev = chainVar.get(body);\n // UpToLast/UpToFirst: FreeCAD's \"up to\" support is the Body's ACCUMULATED\n // shape, NOT only the immediate BaseFeature link — retarget the kernel\n // ref at the chain head (prev). GOTCHA (PadTest V6): truncating against\n // the immediate BaseFeature (a small Pad001 disc) left an 8.06% volume\n // deficit vs the Tip; against the accumulated chain it drops to 3.20%\n // (bbox already exact at delta 0).\n if (prev) {\n for (const c of verdict.calls) {\n if (c.op === 'cad.extrude' && c.params.baseFeature !== undefined) {\n // GOTCHA (PadTest V6 residual): the up-to extrude builds its\n // prism in the SKETCH-LOCAL frame, but the chain head (prev)\n // lives in the PLACED (global) frame. FreeCAD's boolean runs in\n // one frame — so transform prev back into the sketch frame\n // first: local = R^-1(global - p). Feeding the placed chain var\n // directly silently truncates at the wrong face (Pad002 truth\n // AddShape 48199 vs rebuilt deficit ~9108 mm^3 → 3.2% total).\n const needsInverse =\n pl !== undefined && !isIdentityPlacement(pl);\n if (needsInverse && pl) {\n const invQ: [number, number, number, number] = [\n -pl.q[0]!, -pl.q[1]!, -pl.q[2]!, pl.q[3]!,\n ];\n const invEuler = quatToEulerXYZDeg(invQ);\n const tv = newVar();\n const tvCall: CadCall = {\n out: tv, op: 'cad.translate', source: name,\n inputs: [prev], params: { offset: [-pl.p[0]!, -pl.p[1]!, -pl.p[2]!] },\n };\n const rv = newVar();\n const rvCall: CadCall = {\n out: rv, op: 'cad.rotate_euler', source: name,\n inputs: [tv], params: { anglesDeg: invEuler },\n };\n // insert BEFORE the extrude call: faijs is a statement\n // language — `baseFeature: partN` referencing a later\n // statement is E_REFERENCE (parser rejects forward refs).\n const at = calls.indexOf(c);\n calls.splice(at < 0 ? calls.length : at, 0, tvCall, rvCall);\n c.params.baseFeature = jsExpr(rv);\n } else {\n c.params.baseFeature = jsExpr(prev);\n }\n }\n }\n }\n const featureVar = variables.get(name) ?? verdict.calls.at(-1)!.out;\n if (!prev) {\n chainVar.set(body, featureVar); // base feature\n } else if (isSubtractive && verdict.calls.at(-1)!.op === 'cad.subtract' && verdict.calls.at(-1)!.inputs.includes(prev)) {\n // Pocket already subtracted from the chain var itself (BaseFeature\n // resolved to the chain) — its output IS the new chain head; no\n // extra subtract (would cut twice).\n chainVar.set(body, featureVar);\n } else if (isSubtractive) {\n const nv = newVar();\n calls.push({ out: nv, op: 'cad.subtract', source: name, inputs: [prev, featureVar], params: {} });\n chainVar.set(body, nv);\n } else {\n const nv = newVar();\n calls.push({ out: nv, op: 'cad.union', source: name, inputs: [prev, featureVar], params: {} });\n chainVar.set(body, nv);\n }\n }\n results.push({ name, type: obj.type, variable: verdict.calls.at(-1)?.out, calls: verdict.calls, disposition: 'translated', reason: verdict.reason });\n } else if (verdict.kind === 'baked') {\n results.push({ name, type: obj.type, calls: [], disposition: 'baked', reason: verdict.reason });\n } else {\n results.push({ name, type: obj.type, calls: [], disposition: 'preserved-only', reason: verdict.reason });\n }\n }\n\n // also mark unreachable (cycle) objects as baked\n for (const obj of doc.objects) {\n if (!results.some((r) => r.name === obj.name)) {\n results.push({ name: obj.name, type: obj.type, calls: [], disposition: 'baked', reason: 'dependency-cycle' });\n }\n }\n\n // M10.3/M10.5 — split by Body: calls whose source object belongs to a Body\n // (including the chain union/subtract calls emitted for it) go to\n // model/<BodyName>.fai.js; everything else (loose Part features) stays in\n // main.fai.js. When no Body has geometry, everything lands in main (the\n // single-file shape). Aggregate entry groups per-file roots via cad.group.\n const callBody = new Map<string, string>();\n for (const r of results) {\n const b = memberToBody.get(r.name);\n if (b) for (const c of r.calls) callBody.set(c.out, b);\n }\n const bodiesWithGeo = new Set<string>();\n for (const b of new Set(memberToBody.values())) {\n if (chainVar.has(b)) bodiesWithGeo.add(b);\n }\n const files: GenResult['files'] = [];\n let code: string;\n let rootVar: string | undefined;\n if (bodiesWithGeo.size > 0) {\n const mainCalls: CadCall[] = [];\n const perBody = new Map<string, CadCall[]>();\n // M10c partition in DEPENDENCY ORDER: `calls` is already topologically\n // sorted, so ONE forward pass assigns each call — to its own source's Body\n // when known (`callBody`), else to the Body its first body-owned input went\n // to. GOTCHA (PadTest V6): the previous implementation re-assigned such\n // calls by APPENDING them to the end of the Body file, which broke\n // dependency order — a Body file ended up referencing a variable declared\n // further down (`let` TDZ ReferenceError at run time: `part8` used `part6`).\n // Filtering `calls` in place preserves the topological order.\n const assigned = new Map<string, string>(); // call.out → Body file name\n for (const c of calls) {\n const own = callBody.get(c.out);\n const viaInput = c.inputs.map((inp) => assigned.get(inp)).find((b) => b !== undefined);\n const b = own !== undefined && bodiesWithGeo.has(own) ? own : viaInput;\n if (b !== undefined && bodiesWithGeo.has(b)) {\n if (!perBody.has(b)) perBody.set(b, []);\n perBody.get(b)!.push(c);\n assigned.set(c.out, b);\n } else {\n mainCalls.push(c);\n }\n }\n for (const b of bodiesWithGeo) {\n const bodyCalls = perBody.get(b) ?? [];\n // terminal: alias the chain head to <Body>_out so the aggregate entry\n // has a stable, name-independent reference to each Body's result.\n const head = chainVar.get(b)!;\n const withTerminal = [\n ...bodyCalls,\n { out: `${b}_out`, op: 'identity', source: b, inputs: [head], params: {} } as CadCall,\n ];\n files.push({ path: `model/${b}.fai.js`, code: lowerBody(withTerminal, `${baseName}/${b}`, b), body: b });\n }\n // main.fai.js: aggregate the per-Body terminals via cad.group. M10c:\n // cross-file references close through the standard relative-import\n // contract (module-registry D6) — each Body module's terminal alias\n // `<Body>_out` is its live shape, so a named import binds it.\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${baseName} (aggregate entry)`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n const members = [...bodiesWithGeo].map((b) => `${b}_out`);\n // Always import the per-Body terminals: the aggregate entry references\n // `<Body>_out` in BOTH the cad.group (multi-Body) and the single-Body alias\n // path, so a missing import is a SEC_FREE_IDENT parse error (GOTCHA: the\n // single-Body branch previously emitted `let part_out = <Body>_out;` with\n // no import). `mainCalls` may still be empty here.\n if (members.length >= 1) {\n for (const b of bodiesWithGeo) {\n lines.push(`import { ${b}_out } from './${b}.fai.js'; // module ${b}`);\n }\n }\n for (const c of mainCalls) {\n const id = `s${lines.length - 2}`;\n lines.push(`let ${c.out} = ${c.op}(${renderArgs(c)}); // ${id} ${c.source}`);\n }\n if (members.length > 1) {\n rootVar = 'part_out';\n lines.push(`let part_out = cad.group({ members: [${members.join(', ')}] });`);\n } else if (members.length === 1) {\n // single Body: the imported terminal IS the result — alias keeps a\n // stable root name for executors\n rootVar = members[0];\n lines.push(`let part_out = ${rootVar}; // single-Body aggregate`);\n rootVar = 'part_out';\n }\n code = lines.join('\\n') + '\\n';\n } else {\n code = lower(calls, baseName);\n }\n return { calls, objects: results, code, files, rootVar };\n}\n\n/** M10.3 — lower one Body's calls; the last entry is the terminal alias\n * `<Body>_out` (plain JS assignment — faijs has no identity op). */\nfunction lowerBody(calls: CadCall[], label: string, body: string): string {\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${label}`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n for (const call of calls) {\n if (call.op === 'identity') {\n // terminal alias: `let <Body>_out = <chain head>;`\n lines.push(`let ${call.out} = ${call.inputs[0]}; // s? ${body} terminal`);\n continue;\n }\n const id = `s${lines.length - 2}`;\n lines.push(`let ${call.out} = ${call.op}(${renderArgs(call)}); // ${id} ${call.source}`);\n }\n return lines.join('\\n') + '\\n';\n}\n\n/** M5.2 — lower the call plan to .fai.js source. faijs syntax: top-level\n * statement flow with `let partN = cad.x(...)`; no wrapper function. */\nfunction lower(calls: CadCall[], baseName: string): string {\n const lines: string[] = [];\n lines.push(`// Generated by faijs FCStd port — ${baseName}`);\n lines.push(`// Units: mm (faijs contract; FCStd internal units are mm)`);\n for (const call of calls) {\n const id = `s${lines.length - 2}`; // statement id sN\n const args = renderArgs(call);\n lines.push(`let ${call.out} = ${call.op}(${args}); // ${id} ${call.source}`);\n }\n // final shape: union of root calls that nobody consumes; faijs scripts\n // end with the output-producing statement (no return, per fixtures).\n const consumed = new Set(calls.flatMap((c) => c.inputs));\n const roots = calls.filter((c) => !consumed.has(c.out)).map((c) => c.out);\n if (roots.length > 1) {\n lines.push(`let part_out = cad.group({ members: [${roots.join(', ')}] });`);\n } else if (roots.length === 0) {\n lines.push(`// no translated geometry (all baked)`);\n }\n return lines.join('\\n') + '\\n';\n}\n\n/**\n * M5.2 — render one IR value as JS. Plain values JSON-encode (byte-identical to\n * the pre-JsExpr output); a `JsExpr` marker renders verbatim, and a container\n * holding one renders element-wise so the expression survives into the source.\n */\nfunction renderValue(v: unknown): string {\n if (isJsExpr(v)) return v.__jsExpr;\n if (Array.isArray(v)) {\n if (v.some(isJsExpr)) return `[${v.map(renderValue).join(', ')}]`;\n return JSON.stringify(v);\n }\n if (v && typeof v === 'object') {\n const entries = Object.entries(v as Record<string, unknown>);\n if (entries.some(([, val]) => containsJsExpr(val))) {\n return `{ ${entries.map(([k, val]) => `${k}: ${renderValue(val)}`).join(', ')} }`;\n }\n return JSON.stringify(v);\n }\n return JSON.stringify(v);\n}\n\n/** True when a value is or (recursively) contains a `JsExpr` marker. */\nfunction containsJsExpr(v: unknown): boolean {\n if (isJsExpr(v)) return true;\n if (Array.isArray(v)) return v.some(containsJsExpr);\n if (v && typeof v === 'object') return Object.values(v as Record<string, unknown>).some(containsJsExpr);\n return false;\n}\n\nfunction renderArgs(call: CadCall): string {\n const positional: string[] = [\n ...call.inputs.map((i) => i),\n ...(call.literals ?? []).map((l) => renderValue(l)),\n ].filter((s) => s.length > 0); // M7.1: drop empty entries so we never emit `(, `\n const named: string[] = [];\n for (const [k, v] of Object.entries(call.params ?? {})) {\n if (v === undefined) continue;\n named.push(`${k}: ${renderValue(v)}`);\n }\n const namedBlock = named.length ? `{ ${named.join(', ')} }` : '';\n // M7.1: no leading comma when there are no positional args — a call with only\n // named params must render as `cad.sketch({ ... })`, never `cad.sketch(, {...})`.\n const rest = namedBlock ? (positional.length ? `, ${namedBlock}` : namedBlock) : '';\n return `${positional.join(', ')}${rest}`;\n}\n"]}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* freecad/* — byte-exact shadow of the source ZIP members
|
|
10
10
|
*/
|
|
11
11
|
import type { FcstdDocument, FcstdObject } from './document.js';
|
|
12
|
+
/** manifest.json schema: source provenance, units and entry point for the .fai.zip container. */
|
|
12
13
|
export interface FaiManifest {
|
|
13
14
|
/** container format version */
|
|
14
15
|
format: 1;
|
|
@@ -31,6 +32,7 @@ export interface FaiManifest {
|
|
|
31
32
|
* disposition: translated | baked | preserved-only (V3 zero-silent-loss).
|
|
32
33
|
*/
|
|
33
34
|
export type ObjectDisposition = 'translated' | 'baked' | 'preserved-only';
|
|
35
|
+
/** One mapping.json entry: a single object's fidelity disposition, reason and produced artifacts. */
|
|
34
36
|
export interface ObjectMappingEntry {
|
|
35
37
|
/** FCStd object name */
|
|
36
38
|
name: string;
|
|
@@ -48,11 +50,24 @@ export interface ObjectMappingEntry {
|
|
|
48
50
|
gcs?: unknown;
|
|
49
51
|
};
|
|
50
52
|
}
|
|
53
|
+
/** mapping.json schema: the per-object fidelity ledger (zero silent loss, V3). */
|
|
51
54
|
export interface FaiMapping {
|
|
55
|
+
/** one entry per <ObjectData> object */
|
|
52
56
|
objects: ObjectMappingEntry[];
|
|
53
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Assemble the container manifest.json from the parsed document.
|
|
60
|
+
* @param doc parsed FCStd document (SchemaVersion read from meta)
|
|
61
|
+
* @param sourceFile original FCStd file name (not full path)
|
|
62
|
+
* @param programVersion FreeCAD program version that wrote the document
|
|
63
|
+
* @returns the manifest with format 1, mm units and the BREP-chain entry point
|
|
64
|
+
*/
|
|
54
65
|
export declare function buildManifest(doc: FcstdDocument, sourceFile: string, programVersion: string): FaiManifest;
|
|
55
|
-
/**
|
|
66
|
+
/**
|
|
67
|
+
* Default disposition for an object type before feature translation (M4).
|
|
68
|
+
* @param obj the FCStd object to classify
|
|
69
|
+
* @returns `baked` for sketches and non-datum objects, `preserved-only` for datum types
|
|
70
|
+
*/
|
|
56
71
|
export declare function initialDisposition(obj: FcstdObject): {
|
|
57
72
|
disposition: ObjectDisposition;
|
|
58
73
|
reason?: string;
|