@faicad/faijs 0.18.3 → 0.22.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/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +4 -1
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/brep-mirror/joinery-brep.d.ts +1 -1
- package/dist/api/brep-mirror/joinery-brep.d.ts.map +1 -1
- package/dist/api/brep-mirror/joinery-brep.js +22 -20
- package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
- package/dist/api/generated/script-face-manifest.d.ts +4 -0
- package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +3 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/knurl.d.ts.map +1 -1
- package/dist/api/knurl.js +1 -0
- package/dist/api/knurl.js.map +1 -1
- package/dist/api/primitives.d.ts +4 -3
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +9 -3
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/profile.d.ts +34 -5
- package/dist/api/profile.d.ts.map +1 -1
- package/dist/api/profile.js +168 -186
- package/dist/api/profile.js.map +1 -1
- package/dist/api/punch-hole.d.ts +77 -0
- package/dist/api/punch-hole.d.ts.map +1 -0
- package/dist/api/punch-hole.js +207 -0
- package/dist/api/punch-hole.js.map +1 -0
- package/dist/api/sketch-on-face.d.ts +85 -0
- package/dist/api/sketch-on-face.d.ts.map +1 -0
- package/dist/api/sketch-on-face.js +136 -0
- package/dist/api/sketch-on-face.js.map +1 -0
- package/dist/api/sketch-on-plane.d.ts +87 -0
- package/dist/api/sketch-on-plane.d.ts.map +1 -0
- package/dist/api/sketch-on-plane.js +106 -0
- package/dist/api/sketch-on-plane.js.map +1 -0
- package/dist/api/surface/arg-spec.d.ts +8 -0
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/transform.d.ts +5 -5
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +12 -10
- package/dist/api/transform.js.map +1 -1
- package/dist/api/xml-dom.d.ts +27 -0
- package/dist/api/xml-dom.d.ts.map +1 -0
- package/dist/api/xml-dom.js +45 -0
- package/dist/api/xml-dom.js.map +1 -0
- package/dist/boolean/csg-backend.d.ts +6 -6
- package/dist/boolean/csg-backend.d.ts.map +1 -1
- package/dist/boolean/csg-backend.js +9 -9
- package/dist/boolean/csg-backend.js.map +1 -1
- package/dist/boolean/csg-core.d.ts +10 -10
- package/dist/boolean/csg-core.d.ts.map +1 -1
- package/dist/boolean/csg-core.js +24 -24
- package/dist/boolean/csg-core.js.map +1 -1
- package/dist/boolean/extrude-helpers.d.ts +8 -8
- package/dist/boolean/extrude-helpers.d.ts.map +1 -1
- package/dist/boolean/extrude-helpers.js +13 -13
- package/dist/boolean/extrude-helpers.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +24 -10
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +46 -18
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.d.ts.map +1 -1
- package/dist/brep/brep-topology.js +3 -1
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/export/export-model.d.ts +79 -0
- package/dist/brep/export/export-model.d.ts.map +1 -0
- package/dist/brep/export/export-model.js +335 -0
- package/dist/brep/export/export-model.js.map +1 -0
- package/dist/brep/primitives-brep.d.ts.map +1 -1
- package/dist/brep/primitives-brep.js +3 -1
- package/dist/brep/primitives-brep.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +4 -2
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/browser-host/csg-worker-protocol.d.ts +3 -3
- package/dist/browser-host/csg-worker-protocol.d.ts.map +1 -1
- package/dist/browser-host/csg-worker-protocol.js.map +1 -1
- package/dist/browser-host/csg-worker.js +3 -3
- package/dist/browser-host/csg-worker.js.map +1 -1
- package/dist/browser-host/inline-csg-backend.d.ts +3 -3
- package/dist/browser-host/inline-csg-backend.d.ts.map +1 -1
- package/dist/browser-host/inline-csg-backend.js +3 -3
- package/dist/browser-host/inline-csg-backend.js.map +1 -1
- package/dist/browser-host/worker-csg-backend.d.ts +3 -3
- package/dist/browser-host/worker-csg-backend.d.ts.map +1 -1
- package/dist/browser-host/worker-csg-backend.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts +4 -0
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +17 -1
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/ports.d.ts +3 -3
- package/dist/cad-runtime/ports.d.ts.map +1 -1
- package/dist/cad-runtime/ports.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +24 -1
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +53 -3
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +22 -0
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +15 -0
- package/dist/define-op.js.map +1 -1
- package/dist/env-agnostic.d.ts +7 -7
- package/dist/env-agnostic.d.ts.map +1 -1
- package/dist/env-agnostic.js +3 -3
- package/dist/env-agnostic.js.map +1 -1
- package/dist/geometry2d/adapt.d.ts +46 -0
- package/dist/geometry2d/adapt.d.ts.map +1 -0
- package/dist/geometry2d/adapt.js +41 -0
- package/dist/geometry2d/adapt.js.map +1 -0
- package/dist/geometry2d/bbox2d.d.ts +82 -0
- package/dist/geometry2d/bbox2d.d.ts.map +1 -0
- package/dist/geometry2d/bbox2d.js +123 -0
- package/dist/geometry2d/bbox2d.js.map +1 -0
- package/dist/geometry2d/blueprint-sketcher.d.ts +27 -0
- package/dist/geometry2d/blueprint-sketcher.d.ts.map +1 -0
- package/dist/geometry2d/blueprint-sketcher.js +29 -0
- package/dist/geometry2d/blueprint-sketcher.js.map +1 -0
- package/dist/geometry2d/blueprint.d.ts +102 -0
- package/dist/geometry2d/blueprint.d.ts.map +1 -0
- package/dist/geometry2d/blueprint.js +225 -0
- package/dist/geometry2d/blueprint.js.map +1 -0
- package/dist/geometry2d/blueprints.d.ts +58 -0
- package/dist/geometry2d/blueprints.d.ts.map +1 -0
- package/dist/geometry2d/blueprints.js +72 -0
- package/dist/geometry2d/blueprints.js.map +1 -0
- package/dist/geometry2d/bridge/lift-on-plane.d.ts +50 -0
- package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -0
- package/dist/geometry2d/bridge/lift-on-plane.js +78 -0
- package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -0
- package/dist/geometry2d/bridge/on-surface.d.ts +98 -0
- package/dist/geometry2d/bridge/on-surface.d.ts.map +1 -0
- package/dist/geometry2d/bridge/on-surface.js +94 -0
- package/dist/geometry2d/bridge/on-surface.js.map +1 -0
- package/dist/geometry2d/bridge/plane.d.ts +69 -0
- package/dist/geometry2d/bridge/plane.d.ts.map +1 -0
- package/dist/geometry2d/bridge/plane.js +96 -0
- package/dist/geometry2d/bridge/plane.js.map +1 -0
- package/dist/geometry2d/canned-blueprints.d.ts +44 -0
- package/dist/geometry2d/canned-blueprints.d.ts.map +1 -0
- package/dist/geometry2d/canned-blueprints.js +94 -0
- package/dist/geometry2d/canned-blueprints.js.map +1 -0
- package/dist/geometry2d/compound-blueprint.d.ts +72 -0
- package/dist/geometry2d/compound-blueprint.d.ts.map +1 -0
- package/dist/geometry2d/compound-blueprint.js +95 -0
- package/dist/geometry2d/compound-blueprint.js.map +1 -0
- package/dist/geometry2d/curve2d.d.ts +298 -0
- package/dist/geometry2d/curve2d.d.ts.map +1 -0
- package/dist/geometry2d/curve2d.js +1110 -0
- package/dist/geometry2d/curve2d.js.map +1 -0
- package/dist/geometry2d/index.d.ts +22 -0
- package/dist/geometry2d/index.d.ts.map +1 -0
- package/dist/geometry2d/index.js +21 -0
- package/dist/geometry2d/index.js.map +1 -0
- package/dist/geometry2d/organise.d.ts +28 -0
- package/dist/geometry2d/organise.d.ts.map +1 -0
- package/dist/geometry2d/organise.js +108 -0
- package/dist/geometry2d/organise.js.map +1 -0
- package/dist/geometry2d/pen-sketcher.d.ts +365 -0
- package/dist/geometry2d/pen-sketcher.d.ts.map +1 -0
- package/dist/geometry2d/pen-sketcher.js +520 -0
- package/dist/geometry2d/pen-sketcher.js.map +1 -0
- package/dist/geometry2d/point.d.ts +44 -0
- package/dist/geometry2d/point.d.ts.map +1 -0
- package/dist/geometry2d/point.js +57 -0
- package/dist/geometry2d/point.js.map +1 -0
- package/dist/geometry2d/svg-ellipse.d.ts +74 -0
- package/dist/geometry2d/svg-ellipse.d.ts.map +1 -0
- package/dist/geometry2d/svg-ellipse.js +163 -0
- package/dist/geometry2d/svg-ellipse.js.map +1 -0
- package/dist/lang/code-to-args.d.ts +29 -3
- package/dist/lang/code-to-args.d.ts.map +1 -1
- package/dist/lang/code-to-args.js +41 -2
- package/dist/lang/code-to-args.js.map +1 -1
- package/dist/lang/codegen.d.ts +45 -1
- package/dist/lang/codegen.d.ts.map +1 -1
- package/dist/lang/codegen.js +135 -6
- package/dist/lang/codegen.js.map +1 -1
- package/dist/lang/host-arg.d.ts +6 -0
- package/dist/lang/host-arg.d.ts.map +1 -1
- package/dist/lang/host-arg.js.map +1 -1
- package/dist/lang/metadata-extractor.d.ts +25 -0
- package/dist/lang/metadata-extractor.d.ts.map +1 -1
- package/dist/lang/metadata-extractor.js +289 -25
- package/dist/lang/metadata-extractor.js.map +1 -1
- package/dist/lang/parse-error.d.ts +7 -1
- package/dist/lang/parse-error.d.ts.map +1 -1
- package/dist/lang/parse-error.js.map +1 -1
- package/dist/lang/security-scanner.d.ts +9 -1
- package/dist/lang/security-scanner.d.ts.map +1 -1
- package/dist/lang/security-scanner.js +38 -1
- package/dist/lang/security-scanner.js.map +1 -1
- package/dist/lang/symbol-table.generated.d.ts +3 -0
- package/dist/lang/symbol-table.generated.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.js +3 -0
- package/dist/lang/symbol-table.generated.js.map +1 -1
- package/dist/mesh/io.d.ts +62 -9
- package/dist/mesh/io.d.ts.map +1 -1
- package/dist/mesh/io.js +124 -17
- package/dist/mesh/io.js.map +1 -1
- package/dist/mesh/threemf-loader.d.ts +15 -0
- package/dist/mesh/threemf-loader.d.ts.map +1 -0
- package/dist/mesh/threemf-loader.js +163 -0
- package/dist/mesh/threemf-loader.js.map +1 -0
- package/dist/mesh/transform.d.ts +2 -2
- package/dist/mesh/transform.d.ts.map +1 -1
- package/dist/mesh/transform.js +3 -3
- package/dist/mesh/transform.js.map +1 -1
- package/dist/mesh/types.d.ts +2 -2
- package/dist/mesh/types.d.ts.map +1 -1
- package/dist/mesh/types.js.map +1 -1
- package/dist/node-host/cli.d.ts.map +1 -1
- package/dist/node-host/cli.js +53 -26
- package/dist/node-host/cli.js.map +1 -1
- package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
- package/dist/occt-kernel/occtKernel.js +4 -2
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
- package/dist/occt-kernel/topologyExt.js +4 -1
- package/dist/occt-kernel/topologyExt.js.map +1 -1
- package/dist/runtime-state.d.ts +18 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +23 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/sdk.d.ts +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +1 -1
- package/dist/sdk.js.map +1 -1
- package/dist/tolerance.d.ts +38 -0
- package/dist/tolerance.d.ts.map +1 -0
- package/dist/tolerance.js +40 -0
- package/dist/tolerance.js.map +1 -0
- package/dist/topology/naming/score.js +3 -3
- package/dist/topology/naming/score.js.map +1 -1
- package/dist/units.d.ts +248 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +397 -0
- package/dist/units.js.map +1 -0
- package/package.json +19 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geometry2d — small 2D point / vector helpers shared by the sketcher pens and
|
|
3
|
+
* the draw package. Pure TS, zero dependency.
|
|
4
|
+
*
|
|
5
|
+
* Ported from brepjs `2d/lib`-style utilities (Apache-2.0).
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Euclidean distance between two 2D points.
|
|
11
|
+
* @param a - first point.
|
|
12
|
+
* @param b - second point.
|
|
13
|
+
* @returns the distance.
|
|
14
|
+
*/
|
|
15
|
+
export function distance2d(a, b) {
|
|
16
|
+
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* True when two 2D points coincide within `eps`.
|
|
20
|
+
* @param a - first point.
|
|
21
|
+
* @param b - second point.
|
|
22
|
+
* @param eps - coincidence tolerance (default 1e-9).
|
|
23
|
+
* @returns whether `a` and `b` are the same point.
|
|
24
|
+
*/
|
|
25
|
+
export function samePoint(a, b, eps = 1e-9) {
|
|
26
|
+
return distance2d(a, b) <= eps;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Convert polar `[r, theta]` (radians) to Cartesian `[x, y]`.
|
|
30
|
+
* @param r - radial distance.
|
|
31
|
+
* @param theta - angle in radians.
|
|
32
|
+
* @returns the Cartesian point.
|
|
33
|
+
*/
|
|
34
|
+
export function polarToCartesian(r, theta) {
|
|
35
|
+
return [r * Math.cos(theta), r * Math.sin(theta)];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Normalize a 2D vector to unit length.
|
|
39
|
+
* @param v - the input vector.
|
|
40
|
+
* @returns the unit vector (the zero vector normalizes to `[1,0]`).
|
|
41
|
+
*/
|
|
42
|
+
export function normalize2d(v) {
|
|
43
|
+
const len = Math.hypot(v[0], v[1]);
|
|
44
|
+
if (len < 1e-12)
|
|
45
|
+
return [1, 0];
|
|
46
|
+
return [v[0] / len, v[1] / len];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Absolute polar angle of `b` relative to `a`.
|
|
50
|
+
* @param a - the reference point.
|
|
51
|
+
* @param b - the target point.
|
|
52
|
+
* @returns the angle in radians, in `[0, 2π)`.
|
|
53
|
+
*/
|
|
54
|
+
export function polarAngle2d(a, b) {
|
|
55
|
+
return Math.atan2(b[1] - a[1], b[0] - a[0]);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=point.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point.js","sourceRoot":"","sources":["../../src/geometry2d/point.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,CAA4B,EAAE,CAA4B;IACnF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,CAA4B,EAAE,CAA4B,EAAE,GAAG,GAAG,IAAI;IAC9F,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAA;AAChC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAS,EAAE,KAAa;IACvD,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAA;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,CAA4B;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAClC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,CAA4B,EAAE,CAA4B;IACrF,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7C,CAAC","sourcesContent":["/**\n * geometry2d — small 2D point / vector helpers shared by the sketcher pens and\n * the draw package. Pure TS, zero dependency.\n *\n * Ported from brepjs `2d/lib`-style utilities (Apache-2.0).\n *\n * @module\n */\n\n/**\n * Euclidean distance between two 2D points.\n * @param a - first point.\n * @param b - second point.\n * @returns the distance.\n */\nexport function distance2d(a: readonly [number, number], b: readonly [number, number]): number {\n return Math.hypot(b[0] - a[0], b[1] - a[1])\n}\n\n/**\n * True when two 2D points coincide within `eps`.\n * @param a - first point.\n * @param b - second point.\n * @param eps - coincidence tolerance (default 1e-9).\n * @returns whether `a` and `b` are the same point.\n */\nexport function samePoint(a: readonly [number, number], b: readonly [number, number], eps = 1e-9): boolean {\n return distance2d(a, b) <= eps\n}\n\n/**\n * Convert polar `[r, theta]` (radians) to Cartesian `[x, y]`.\n * @param r - radial distance.\n * @param theta - angle in radians.\n * @returns the Cartesian point.\n */\nexport function polarToCartesian(r: number, theta: number): [number, number] {\n return [r * Math.cos(theta), r * Math.sin(theta)]\n}\n\n/**\n * Normalize a 2D vector to unit length.\n * @param v - the input vector.\n * @returns the unit vector (the zero vector normalizes to `[1,0]`).\n */\nexport function normalize2d(v: readonly [number, number]): [number, number] {\n const len = Math.hypot(v[0], v[1])\n if (len < 1e-12) return [1, 0]\n return [v[0] / len, v[1] / len]\n}\n\n/**\n * Absolute polar angle of `b` relative to `a`.\n * @param a - the reference point.\n * @param b - the target point.\n * @returns the angle in radians, in `[0, 2π)`.\n */\nexport function polarAngle2d(a: readonly [number, number], b: readonly [number, number]): number {\n return Math.atan2(b[1] - a[1], b[0] - a[0])\n}"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geometry2d — SVG-style elliptical arc construction (SVG endpoint form).
|
|
3
|
+
*
|
|
4
|
+
* Ported from brepjs `2d/blueprints/ellipseUtils.ts` (Apache-2.0). Adapts the
|
|
5
|
+
* SVG F.6.5/F.6.6 endpoint→center conversion onto the pure `Curve2dObj` base:
|
|
6
|
+
* the resulting elliptical arc is a `TrimmedCurve2d` over an `Ellipse2d`, whose
|
|
7
|
+
* parameter is the sweep angle in radians (CCW positive).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { type Curve2dObj } from './curve2d.js';
|
|
12
|
+
/** A `[x, y]` 2D point. */
|
|
13
|
+
type Pt = [number, number];
|
|
14
|
+
/**
|
|
15
|
+
* Normalize ellipse radii so the major axis is horizontal, adjusting rotation.
|
|
16
|
+
* @param horizontalRadius - the radius along the SVG x-axis.
|
|
17
|
+
* @param verticalRadius - the radius along the SVG y-axis.
|
|
18
|
+
* @param rotation - rotation in degrees.
|
|
19
|
+
* @returns the normalized radius set.
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeEllipseRadii(horizontalRadius: number, verticalRadius: number, rotation: number): {
|
|
22
|
+
majorRadius: number;
|
|
23
|
+
minorRadius: number;
|
|
24
|
+
rotationAngle: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Convert SVG elliptical-arc endpoint parameters to the centerly parametrization
|
|
28
|
+
* (SVG F6.5.1–F6.5.6).
|
|
29
|
+
* @param x1 - start x.
|
|
30
|
+
* @param y1 - start y.
|
|
31
|
+
* @param x2 - end x.
|
|
32
|
+
* @param y2 - end y.
|
|
33
|
+
* @param rx - x radius.
|
|
34
|
+
* @param ry - y radius.
|
|
35
|
+
* @param phi - rotation angle (radians).
|
|
36
|
+
* @param fA - large-arc flag.
|
|
37
|
+
* @param fS - sweep flag.
|
|
38
|
+
* @returns the center, radii and angular parametrization.
|
|
39
|
+
*/
|
|
40
|
+
export declare function convertSvgEllipseParams(x1: number, y1: number, x2: number, y2: number, rx: number, ry: number, phi: number, fA: boolean, fS: boolean): {
|
|
41
|
+
cx: number;
|
|
42
|
+
cy: number;
|
|
43
|
+
startAngle: number;
|
|
44
|
+
endAngle: number;
|
|
45
|
+
clockwise: boolean;
|
|
46
|
+
rx: number;
|
|
47
|
+
ry: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Build an elliptical arc `Curve2dObj` from SVG endpoint parameters.
|
|
51
|
+
* @param startUV - the start point.
|
|
52
|
+
* @param endUV - the end point.
|
|
53
|
+
* @param majorRadius - the major radius.
|
|
54
|
+
* @param minorRadius - the minor radius.
|
|
55
|
+
* @param rotationAngleDeg - rotation in degrees.
|
|
56
|
+
* @param longAxis - SVG large-arc flag.
|
|
57
|
+
* @param sweep - SVG sweep flag.
|
|
58
|
+
* @returns a trimmed elliptical arc.
|
|
59
|
+
*/
|
|
60
|
+
export declare function makeEllipseArcFromSvgParams(startUV: Pt, endUV: Pt, majorRadius: number, minorRadius: number, rotationAngleDeg: number, longAxis: boolean, sweep: boolean): Curve2dObj;
|
|
61
|
+
/**
|
|
62
|
+
* Build an elliptical arc as a trimmed ellipse over an angle range.
|
|
63
|
+
* @param rx - x radius.
|
|
64
|
+
* @param ry - y radius.
|
|
65
|
+
* @param startAngle - start angle (radians, ellipse-param space).
|
|
66
|
+
* @param endAngle - end angle (radians).
|
|
67
|
+
* @param center - the ellipse center.
|
|
68
|
+
* @param xDir - the in-plane X axis of the ellipse.
|
|
69
|
+
* @param clockwise - sweep direction.
|
|
70
|
+
* @returns a trimmed elliptical arc.
|
|
71
|
+
*/
|
|
72
|
+
export declare function makeEllipseArcFromCenter(rx: number, ry: number, startAngle: number, endAngle: number, center: Pt, xDir: Pt, clockwise: boolean): Curve2dObj;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=svg-ellipse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-ellipse.d.ts","sourceRoot":"","sources":["../../src/geometry2d/svg-ellipse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AAM1D,2BAA2B;AAC3B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AA0C1B;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,GACf;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAKrE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,OAAO,EACX,EAAE,EAAE,OAAO,GACV;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAiC9G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,EAAE,EACX,KAAK,EAAE,EAAE,EACT,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,OAAO,GACb,UAAU,CASZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,EAAE,EACV,IAAI,EAAE,EAAE,EACR,SAAS,EAAE,OAAO,GACjB,UAAU,CAOZ"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* geometry2d — SVG-style elliptical arc construction (SVG endpoint form).
|
|
3
|
+
*
|
|
4
|
+
* Ported from brepjs `2d/blueprints/ellipseUtils.ts` (Apache-2.0). Adapts the
|
|
5
|
+
* SVG F.6.5/F.6.6 endpoint→center conversion onto the pure `Curve2dObj` base:
|
|
6
|
+
* the resulting elliptical arc is a `TrimmedCurve2d` over an `Ellipse2d`, whose
|
|
7
|
+
* parameter is the sweep angle in radians (CCW positive).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { makeEllipse2d } from './curve2d.js';
|
|
12
|
+
import { normalize2d } from './point.js';
|
|
13
|
+
const DEG2RAD = Math.PI / 180;
|
|
14
|
+
const TWO_PI = Math.PI * 2;
|
|
15
|
+
function bug(caller, message) {
|
|
16
|
+
throw new Error(`[geometry2d/svg-ellipse] ${caller}: ${message}`);
|
|
17
|
+
}
|
|
18
|
+
/** Rotate a 2D point by `rad` radians. */
|
|
19
|
+
function rotate2d([x, y], rad) {
|
|
20
|
+
return [x * Math.cos(rad) - y * Math.sin(rad), x * Math.sin(rad) + y * Math.cos(rad)];
|
|
21
|
+
}
|
|
22
|
+
/** Signed angle from `[ux,uy]` to `[vx,vy]` in `[−π, π]`. */
|
|
23
|
+
function radianAngle(ux, uy, vx, vy) {
|
|
24
|
+
const dot = ux * vx + uy * vy;
|
|
25
|
+
const mod = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
|
26
|
+
if (mod < 1e-12)
|
|
27
|
+
bug('radianAngle', 'Cannot compute angle between zero-length vectors');
|
|
28
|
+
let rad = Math.acos(Math.max(-1, Math.min(1, dot / mod)));
|
|
29
|
+
if (ux * vy - uy * vx < 0)
|
|
30
|
+
rad = -rad;
|
|
31
|
+
return rad;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Compute arc start/end angles from the unit-circle parameterization (SVG F6.5.5).
|
|
35
|
+
* @param xcr1 - first unit-circle x.
|
|
36
|
+
* @param ycr1 - first unit-circle y.
|
|
37
|
+
* @param xcr2 - second unit-circle x.
|
|
38
|
+
* @param ycr2 - second unit-circle y.
|
|
39
|
+
* @param fS - sweep flag.
|
|
40
|
+
* @returns the `{ startAngle, endAngle }` pair (radians).
|
|
41
|
+
*/
|
|
42
|
+
function computeArcAngles(xcr1, ycr1, xcr2, ycr2, fS) {
|
|
43
|
+
const startAngle = radianAngle(1, 0, xcr1, ycr1);
|
|
44
|
+
let deltaAngle = radianAngle(xcr1, ycr1, -xcr2, -ycr2);
|
|
45
|
+
while (deltaAngle > TWO_PI)
|
|
46
|
+
deltaAngle -= TWO_PI;
|
|
47
|
+
while (deltaAngle < 0)
|
|
48
|
+
deltaAngle += TWO_PI;
|
|
49
|
+
if (!fS)
|
|
50
|
+
deltaAngle -= TWO_PI;
|
|
51
|
+
let endAngle = startAngle + deltaAngle;
|
|
52
|
+
while (endAngle > TWO_PI)
|
|
53
|
+
endAngle -= TWO_PI;
|
|
54
|
+
while (endAngle < 0)
|
|
55
|
+
endAngle += TWO_PI;
|
|
56
|
+
return { startAngle, endAngle };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalize ellipse radii so the major axis is horizontal, adjusting rotation.
|
|
60
|
+
* @param horizontalRadius - the radius along the SVG x-axis.
|
|
61
|
+
* @param verticalRadius - the radius along the SVG y-axis.
|
|
62
|
+
* @param rotation - rotation in degrees.
|
|
63
|
+
* @returns the normalized radius set.
|
|
64
|
+
*/
|
|
65
|
+
export function normalizeEllipseRadii(horizontalRadius, verticalRadius, rotation) {
|
|
66
|
+
if (horizontalRadius < verticalRadius) {
|
|
67
|
+
return { majorRadius: verticalRadius, minorRadius: horizontalRadius, rotationAngle: rotation + 90 };
|
|
68
|
+
}
|
|
69
|
+
return { majorRadius: horizontalRadius, minorRadius: verticalRadius, rotationAngle: rotation };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert SVG elliptical-arc endpoint parameters to the centerly parametrization
|
|
73
|
+
* (SVG F6.5.1–F6.5.6).
|
|
74
|
+
* @param x1 - start x.
|
|
75
|
+
* @param y1 - start y.
|
|
76
|
+
* @param x2 - end x.
|
|
77
|
+
* @param y2 - end y.
|
|
78
|
+
* @param rx - x radius.
|
|
79
|
+
* @param ry - y radius.
|
|
80
|
+
* @param phi - rotation angle (radians).
|
|
81
|
+
* @param fA - large-arc flag.
|
|
82
|
+
* @param fS - sweep flag.
|
|
83
|
+
* @returns the center, radii and angular parametrization.
|
|
84
|
+
*/
|
|
85
|
+
export function convertSvgEllipseParams(x1, y1, x2, y2, rx, ry, phi, fA, fS) {
|
|
86
|
+
if (rx < 0)
|
|
87
|
+
rx = -rx;
|
|
88
|
+
if (ry < 0)
|
|
89
|
+
ry = -ry;
|
|
90
|
+
if (rx < 1e-10 || ry < 1e-10)
|
|
91
|
+
bug('convertSvgEllipseParams', 'rx and ry cannot be 0');
|
|
92
|
+
const s_phi = Math.sin(phi);
|
|
93
|
+
const c_phi = Math.cos(phi);
|
|
94
|
+
const hd_x = (x1 - x2) / 2;
|
|
95
|
+
const hd_y = (y1 - y2) / 2;
|
|
96
|
+
const hs_x = (x1 + x2) / 2;
|
|
97
|
+
const hs_y = (y1 + y2) / 2;
|
|
98
|
+
// F6.5.1: transform to (x', y')
|
|
99
|
+
const x1_ = c_phi * hd_x + s_phi * hd_y;
|
|
100
|
+
const y1_ = c_phi * hd_y - s_phi * hd_x;
|
|
101
|
+
// F.6.6: correct out-of-range radii
|
|
102
|
+
const lambda = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
|
|
103
|
+
if (lambda > 1) {
|
|
104
|
+
rx = rx * Math.sqrt(lambda);
|
|
105
|
+
ry = ry * Math.sqrt(lambda);
|
|
106
|
+
}
|
|
107
|
+
const rxry = rx * ry;
|
|
108
|
+
const rxy1_ = rx * y1_;
|
|
109
|
+
const ryx1_ = ry * x1_;
|
|
110
|
+
const sum_of_sq = rxy1_ * rxy1_ + ryx1_ * ryx1_;
|
|
111
|
+
if (!sum_of_sq)
|
|
112
|
+
bug('convertSvgEllipseParams', 'Start point cannot be the same as end point');
|
|
113
|
+
let coe = Math.sqrt(Math.abs((rxry * rxry - sum_of_sq) / sum_of_sq));
|
|
114
|
+
if (fA === fS)
|
|
115
|
+
coe = -coe;
|
|
116
|
+
const cx_ = (coe * rxy1_) / ry;
|
|
117
|
+
const cy_ = (-coe * ryx1_) / rx;
|
|
118
|
+
// F6.5.3: back-transform to absolute center
|
|
119
|
+
const cx = c_phi * cx_ - s_phi * cy_ + hs_x;
|
|
120
|
+
const cy = s_phi * cx_ + c_phi * cy_ + hs_y;
|
|
121
|
+
const { startAngle, endAngle } = computeArcAngles((x1_ - cx_) / rx, (y1_ - cy_) / ry, (x1_ + cx_) / rx, (y1_ + cy_) / ry, fS);
|
|
122
|
+
return { cx, cy, startAngle, endAngle, clockwise: fS, rx, ry };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Build an elliptical arc `Curve2dObj` from SVG endpoint parameters.
|
|
126
|
+
* @param startUV - the start point.
|
|
127
|
+
* @param endUV - the end point.
|
|
128
|
+
* @param majorRadius - the major radius.
|
|
129
|
+
* @param minorRadius - the minor radius.
|
|
130
|
+
* @param rotationAngleDeg - rotation in degrees.
|
|
131
|
+
* @param longAxis - SVG large-arc flag.
|
|
132
|
+
* @param sweep - SVG sweep flag.
|
|
133
|
+
* @returns a trimmed elliptical arc.
|
|
134
|
+
*/
|
|
135
|
+
export function makeEllipseArcFromSvgParams(startUV, endUV, majorRadius, minorRadius, rotationAngleDeg, longAxis, sweep) {
|
|
136
|
+
const radRotation = rotationAngleDeg * DEG2RAD;
|
|
137
|
+
const xDir = normalize2d(rotate2d([1, 0], radRotation));
|
|
138
|
+
const phi = Math.atan2(xDir[1], xDir[0]);
|
|
139
|
+
const { majorRadius: maAxis, minorRadius: miAxis } = normalizeEllipseRadii(majorRadius, minorRadius, rotationAngleDeg);
|
|
140
|
+
const { cx, cy, startAngle, endAngle, clockwise, rx, ry } = convertSvgEllipseParams(startUV[0], startUV[1], endUV[0], endUV[1], maAxis, miAxis, phi, longAxis, sweep);
|
|
141
|
+
return makeEllipseArcFromCenter(rx, ry, startAngle, endAngle, [cx, cy], xDir, clockwise);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Build an elliptical arc as a trimmed ellipse over an angle range.
|
|
145
|
+
* @param rx - x radius.
|
|
146
|
+
* @param ry - y radius.
|
|
147
|
+
* @param startAngle - start angle (radians, ellipse-param space).
|
|
148
|
+
* @param endAngle - end angle (radians).
|
|
149
|
+
* @param center - the ellipse center.
|
|
150
|
+
* @param xDir - the in-plane X axis of the ellipse.
|
|
151
|
+
* @param clockwise - sweep direction.
|
|
152
|
+
* @returns a trimmed elliptical arc.
|
|
153
|
+
*/
|
|
154
|
+
export function makeEllipseArcFromCenter(rx, ry, startAngle, endAngle, center, xDir, clockwise) {
|
|
155
|
+
const sense = !clockwise;
|
|
156
|
+
const aStart = sense ? startAngle : -startAngle;
|
|
157
|
+
let aEnd = sense ? endAngle : -endAngle;
|
|
158
|
+
if (aEnd < aStart - 1e-9)
|
|
159
|
+
aEnd += TWO_PI;
|
|
160
|
+
const ellipse = makeEllipse2d(center[0], center[1], rx, ry, xDir[0], xDir[1], sense);
|
|
161
|
+
return { kind2d: 'trimmed', basis: ellipse, tStart: aStart, tEnd: aEnd };
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=svg-ellipse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-ellipse.js","sourceRoot":"","sources":["../../src/geometry2d/svg-ellipse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAmB,MAAM,WAAW,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAA;AAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAA;AAK1B,SAAS,GAAG,CAAC,MAAc,EAAE,OAAe;IAC1C,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,KAAK,OAAO,EAAE,CAAC,CAAA;AACnE,CAAC;AAED,0CAA0C;AAC1C,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAK,EAAE,GAAW;IACvC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;AACvF,CAAC;AAED,6DAA6D;AAC7D,SAAS,WAAW,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;IACjE,MAAM,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IAChE,IAAI,GAAG,GAAG,KAAK;QAAE,GAAG,CAAC,aAAa,EAAE,kDAAkD,CAAC,CAAA;IACvF,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAA;IACzD,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;QAAE,GAAG,GAAG,CAAC,GAAG,CAAA;IACrC,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,EAAW;IAC3F,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IAChD,IAAI,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAA;IACtD,OAAO,UAAU,GAAG,MAAM;QAAE,UAAU,IAAI,MAAM,CAAA;IAChD,OAAO,UAAU,GAAG,CAAC;QAAE,UAAU,IAAI,MAAM,CAAA;IAC3C,IAAI,CAAC,EAAE;QAAE,UAAU,IAAI,MAAM,CAAA;IAC7B,IAAI,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;IACtC,OAAO,QAAQ,GAAG,MAAM;QAAE,QAAQ,IAAI,MAAM,CAAA;IAC5C,OAAO,QAAQ,GAAG,CAAC;QAAE,QAAQ,IAAI,MAAM,CAAA;IACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA;AACjC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,gBAAwB,EACxB,cAAsB,EACtB,QAAgB;IAEhB,IAAI,gBAAgB,GAAG,cAAc,EAAE,CAAC;QACtC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,QAAQ,GAAG,EAAE,EAAE,CAAA;IACrG,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAA;AAChG,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,EAAU,EACV,GAAW,EACX,EAAW,EACX,EAAW;IAEX,IAAI,EAAE,GAAG,CAAC;QAAE,EAAE,GAAG,CAAC,EAAE,CAAA;IACpB,IAAI,EAAE,GAAG,CAAC;QAAE,EAAE,GAAG,CAAC,EAAE,CAAA;IACpB,IAAI,EAAE,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK;QAAE,GAAG,CAAC,yBAAyB,EAAE,uBAAuB,CAAC,CAAA;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;IAC1B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;IAC1B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;IAC1B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;IAC1B,gCAAgC;IAChC,MAAM,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAA;IACvC,MAAM,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAA;IACvC,oCAAoC;IACpC,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAA;IAChE,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC3B,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC7B,CAAC;IACD,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,CAAA;IACpB,MAAM,KAAK,GAAG,EAAE,GAAG,GAAG,CAAA;IACtB,MAAM,KAAK,GAAG,EAAE,GAAG,GAAG,CAAA;IACtB,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;IAC/C,IAAI,CAAC,SAAS;QAAE,GAAG,CAAC,yBAAyB,EAAE,6CAA6C,CAAC,CAAA;IAC7F,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,CAAA;IACpE,IAAI,EAAE,KAAK,EAAE;QAAE,GAAG,GAAG,CAAC,GAAG,CAAA;IACzB,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;IAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;IAC/B,4CAA4C;IAC5C,MAAM,EAAE,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAA;IAC3C,MAAM,EAAE,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAA;IAC3C,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;IAC7H,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAA;AAChE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAW,EACX,KAAS,EACT,WAAmB,EACnB,WAAmB,EACnB,gBAAwB,EACxB,QAAiB,EACjB,KAAc;IAEd,MAAM,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAA;IAC9C,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAA;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAAC,WAAW,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAA;IACtH,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,uBAAuB,CACjF,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CACjF,CAAA;IACD,OAAO,wBAAwB,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;AAC1F,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,wBAAwB,CACtC,EAAU,EACV,EAAU,EACV,UAAkB,EAClB,QAAgB,EAChB,MAAU,EACV,IAAQ,EACR,SAAkB;IAElB,MAAM,KAAK,GAAG,CAAC,SAAS,CAAA;IACxB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAA;IAC/C,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;IACvC,IAAI,IAAI,GAAG,MAAM,GAAG,IAAI;QAAE,IAAI,IAAI,MAAM,CAAA;IACxC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACpF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;AAC1E,CAAC","sourcesContent":["/**\n * geometry2d — SVG-style elliptical arc construction (SVG endpoint form).\n *\n * Ported from brepjs `2d/blueprints/ellipseUtils.ts` (Apache-2.0). Adapts the\n * SVG F.6.5/F.6.6 endpoint→center conversion onto the pure `Curve2dObj` base:\n * the resulting elliptical arc is a `TrimmedCurve2d` over an `Ellipse2d`, whose\n * parameter is the sweep angle in radians (CCW positive).\n *\n * @module\n */\n\nimport { makeEllipse2d, type Curve2dObj } from './curve2d'\nimport { normalize2d } from './point'\n\nconst DEG2RAD = Math.PI / 180\nconst TWO_PI = Math.PI * 2\n\n/** A `[x, y]` 2D point. */\ntype Pt = [number, number]\n\nfunction bug(caller: string, message: string): never {\n throw new Error(`[geometry2d/svg-ellipse] ${caller}: ${message}`)\n}\n\n/** Rotate a 2D point by `rad` radians. */\nfunction rotate2d([x, y]: Pt, rad: number): Pt {\n return [x * Math.cos(rad) - y * Math.sin(rad), x * Math.sin(rad) + y * Math.cos(rad)]\n}\n\n/** Signed angle from `[ux,uy]` to `[vx,vy]` in `[−π, π]`. */\nfunction radianAngle(ux: number, uy: number, vx: number, vy: number): number {\n const dot = ux * vx + uy * vy\n const mod = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy))\n if (mod < 1e-12) bug('radianAngle', 'Cannot compute angle between zero-length vectors')\n let rad = Math.acos(Math.max(-1, Math.min(1, dot / mod)))\n if (ux * vy - uy * vx < 0) rad = -rad\n return rad\n}\n\n/**\n * Compute arc start/end angles from the unit-circle parameterization (SVG F6.5.5).\n * @param xcr1 - first unit-circle x.\n * @param ycr1 - first unit-circle y.\n * @param xcr2 - second unit-circle x.\n * @param ycr2 - second unit-circle y.\n * @param fS - sweep flag.\n * @returns the `{ startAngle, endAngle }` pair (radians).\n */\nfunction computeArcAngles(xcr1: number, ycr1: number, xcr2: number, ycr2: number, fS: boolean): { startAngle: number; endAngle: number } {\n const startAngle = radianAngle(1, 0, xcr1, ycr1)\n let deltaAngle = radianAngle(xcr1, ycr1, -xcr2, -ycr2)\n while (deltaAngle > TWO_PI) deltaAngle -= TWO_PI\n while (deltaAngle < 0) deltaAngle += TWO_PI\n if (!fS) deltaAngle -= TWO_PI\n let endAngle = startAngle + deltaAngle\n while (endAngle > TWO_PI) endAngle -= TWO_PI\n while (endAngle < 0) endAngle += TWO_PI\n return { startAngle, endAngle }\n}\n\n/**\n * Normalize ellipse radii so the major axis is horizontal, adjusting rotation.\n * @param horizontalRadius - the radius along the SVG x-axis.\n * @param verticalRadius - the radius along the SVG y-axis.\n * @param rotation - rotation in degrees.\n * @returns the normalized radius set.\n */\nexport function normalizeEllipseRadii(\n horizontalRadius: number,\n verticalRadius: number,\n rotation: number,\n): { majorRadius: number; minorRadius: number; rotationAngle: number } {\n if (horizontalRadius < verticalRadius) {\n return { majorRadius: verticalRadius, minorRadius: horizontalRadius, rotationAngle: rotation + 90 }\n }\n return { majorRadius: horizontalRadius, minorRadius: verticalRadius, rotationAngle: rotation }\n}\n\n/**\n * Convert SVG elliptical-arc endpoint parameters to the centerly parametrization\n * (SVG F6.5.1–F6.5.6).\n * @param x1 - start x.\n * @param y1 - start y.\n * @param x2 - end x.\n * @param y2 - end y.\n * @param rx - x radius.\n * @param ry - y radius.\n * @param phi - rotation angle (radians).\n * @param fA - large-arc flag.\n * @param fS - sweep flag.\n * @returns the center, radii and angular parametrization.\n */\nexport function convertSvgEllipseParams(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n rx: number,\n ry: number,\n phi: number,\n fA: boolean,\n fS: boolean,\n): { cx: number; cy: number; startAngle: number; endAngle: number; clockwise: boolean; rx: number; ry: number } {\n if (rx < 0) rx = -rx\n if (ry < 0) ry = -ry\n if (rx < 1e-10 || ry < 1e-10) bug('convertSvgEllipseParams', 'rx and ry cannot be 0')\n const s_phi = Math.sin(phi)\n const c_phi = Math.cos(phi)\n const hd_x = (x1 - x2) / 2\n const hd_y = (y1 - y2) / 2\n const hs_x = (x1 + x2) / 2\n const hs_y = (y1 + y2) / 2\n // F6.5.1: transform to (x', y')\n const x1_ = c_phi * hd_x + s_phi * hd_y\n const y1_ = c_phi * hd_y - s_phi * hd_x\n // F.6.6: correct out-of-range radii\n const lambda = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry)\n if (lambda > 1) {\n rx = rx * Math.sqrt(lambda)\n ry = ry * Math.sqrt(lambda)\n }\n const rxry = rx * ry\n const rxy1_ = rx * y1_\n const ryx1_ = ry * x1_\n const sum_of_sq = rxy1_ * rxy1_ + ryx1_ * ryx1_\n if (!sum_of_sq) bug('convertSvgEllipseParams', 'Start point cannot be the same as end point')\n let coe = Math.sqrt(Math.abs((rxry * rxry - sum_of_sq) / sum_of_sq))\n if (fA === fS) coe = -coe\n const cx_ = (coe * rxy1_) / ry\n const cy_ = (-coe * ryx1_) / rx\n // F6.5.3: back-transform to absolute center\n const cx = c_phi * cx_ - s_phi * cy_ + hs_x\n const cy = s_phi * cx_ + c_phi * cy_ + hs_y\n const { startAngle, endAngle } = computeArcAngles((x1_ - cx_) / rx, (y1_ - cy_) / ry, (x1_ + cx_) / rx, (y1_ + cy_) / ry, fS)\n return { cx, cy, startAngle, endAngle, clockwise: fS, rx, ry }\n}\n\n/**\n * Build an elliptical arc `Curve2dObj` from SVG endpoint parameters.\n * @param startUV - the start point.\n * @param endUV - the end point.\n * @param majorRadius - the major radius.\n * @param minorRadius - the minor radius.\n * @param rotationAngleDeg - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns a trimmed elliptical arc.\n */\nexport function makeEllipseArcFromSvgParams(\n startUV: Pt,\n endUV: Pt,\n majorRadius: number,\n minorRadius: number,\n rotationAngleDeg: number,\n longAxis: boolean,\n sweep: boolean,\n): Curve2dObj {\n const radRotation = rotationAngleDeg * DEG2RAD\n const xDir = normalize2d(rotate2d([1, 0], radRotation))\n const phi = Math.atan2(xDir[1], xDir[0])\n const { majorRadius: maAxis, minorRadius: miAxis } = normalizeEllipseRadii(majorRadius, minorRadius, rotationAngleDeg)\n const { cx, cy, startAngle, endAngle, clockwise, rx, ry } = convertSvgEllipseParams(\n startUV[0], startUV[1], endUV[0], endUV[1], maAxis, miAxis, phi, longAxis, sweep,\n )\n return makeEllipseArcFromCenter(rx, ry, startAngle, endAngle, [cx, cy], xDir, clockwise)\n}\n\n/**\n * Build an elliptical arc as a trimmed ellipse over an angle range.\n * @param rx - x radius.\n * @param ry - y radius.\n * @param startAngle - start angle (radians, ellipse-param space).\n * @param endAngle - end angle (radians).\n * @param center - the ellipse center.\n * @param xDir - the in-plane X axis of the ellipse.\n * @param clockwise - sweep direction.\n * @returns a trimmed elliptical arc.\n */\nexport function makeEllipseArcFromCenter(\n rx: number,\n ry: number,\n startAngle: number,\n endAngle: number,\n center: Pt,\n xDir: Pt,\n clockwise: boolean,\n): Curve2dObj {\n const sense = !clockwise\n const aStart = sense ? startAngle : -startAngle\n let aEnd = sense ? endAngle : -endAngle\n if (aEnd < aStart - 1e-9) aEnd += TWO_PI\n const ellipse = makeEllipse2d(center[0], center[1], rx, ry, xDir[0], xDir[1], sense)\n return { kind2d: 'trimmed', basis: ellipse, tStart: aStart, tEnd: aEnd }\n}"]}
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* 不得把折叠值写回源码(会丢失原表达式)。
|
|
20
20
|
*/
|
|
21
21
|
import type { HostArg } from './host-arg.js';
|
|
22
|
+
import { type OpDimMap } from './metadata-extractor.js';
|
|
23
|
+
import type { DimName, UnitName } from '../units.js';
|
|
22
24
|
/**
|
|
23
25
|
* `codeToArgs` 的返回契约:位置实参槽 + 尾随选项对象(HostArg 形态,纯数据无 IR)。
|
|
24
26
|
*/
|
|
@@ -26,6 +28,16 @@ export interface CodeToArgsResult {
|
|
|
26
28
|
positional: HostArg[];
|
|
27
29
|
args: Record<string, HostArg>;
|
|
28
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* codeToArgs 选项。`opDims` 为 P4/P6 (unit-system D8) 透传:callee → 量纲声明,
|
|
33
|
+
* 供单行回填路径的 dimension pass 消费(P6 落地前声明面透传即可,不影响解析结果)。
|
|
34
|
+
*/
|
|
35
|
+
export interface CodeToArgsOptions {
|
|
36
|
+
/** 该脚本顶层 import 的绑定名(F2)。 */
|
|
37
|
+
namespaces?: string[];
|
|
38
|
+
/** callee → 量纲声明(unit-system D8,P6 消费)。 */
|
|
39
|
+
opDims?: OpDimMap;
|
|
40
|
+
}
|
|
29
41
|
/**
|
|
30
42
|
* 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 IR 变体语义)。
|
|
31
43
|
*
|
|
@@ -52,7 +64,21 @@ export interface CodeToArgsResult {
|
|
|
52
64
|
* serialized JSON form).
|
|
53
65
|
* @throws ParseError — 行文本不是合法语句时抛出(含行号)
|
|
54
66
|
*/
|
|
55
|
-
export declare function codeToArgs(codeLine: string, opts?:
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
export declare function codeToArgs(codeLine: string, opts?: CodeToArgsOptions): CodeToArgsResult;
|
|
68
|
+
/**
|
|
69
|
+
* Parse a unit literal text expression (`n * UNIT`) into its base-unit value.
|
|
70
|
+
*
|
|
71
|
+
* P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like
|
|
72
|
+
* `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.
|
|
73
|
+
* Non-unit-literal expressions return `null` (host decides whether to
|
|
74
|
+
* downgrade to read-only).
|
|
75
|
+
*
|
|
76
|
+
* @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).
|
|
77
|
+
* @returns the parsed unit literal info, or `null` if not a unit literal.
|
|
78
|
+
*/
|
|
79
|
+
export declare function parseUnitLiteral(text: string): {
|
|
80
|
+
base: number;
|
|
81
|
+
dim: DimName;
|
|
82
|
+
unitName: UnitName;
|
|
83
|
+
} | null;
|
|
58
84
|
//# sourceMappingURL=code-to-args.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-to-args.d.ts","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"code-to-args.d.ts","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAGrE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAsDjD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,QAAQ,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,gBAAgB,CA+BvF;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAWxG"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { extractMetadata } from './metadata-extractor.js';
|
|
22
22
|
import { isHostRef } from './host-arg.js';
|
|
23
|
+
import { SCRIPT_UNIT_NAMES, UNIT_SCALE, UNIT_DIM, SCRIPT_UNIT_TO_NAME } from '../units.js';
|
|
23
24
|
/**
|
|
24
25
|
* 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):
|
|
25
26
|
* parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的
|
|
@@ -42,7 +43,10 @@ function extractIdentifiers(line, namespaces) {
|
|
|
42
43
|
const ids = new Set();
|
|
43
44
|
for (const m of withoutStrings.matchAll(IDENT_RE)) {
|
|
44
45
|
const id = m[0];
|
|
45
|
-
|
|
46
|
+
// P7/D10.4: unit constants (MM, INCH, DEGREE, …) must NOT be pre-declared
|
|
47
|
+
// as sentinel parameters (`let INCH = 0`), because that would shadow the
|
|
48
|
+
// real global value and cause `10 * INCH` to fold to 0.
|
|
49
|
+
if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id) || SCRIPT_UNIT_NAMES.has(id))
|
|
46
50
|
continue;
|
|
47
51
|
ids.add(id);
|
|
48
52
|
}
|
|
@@ -104,7 +108,12 @@ export function codeToArgs(codeLine, opts) {
|
|
|
104
108
|
// 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;
|
|
105
109
|
// 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,
|
|
106
110
|
// 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。
|
|
107
|
-
|
|
111
|
+
// opDims 透传给 dimension pass(P6 消费,P4 仅透传声明面)。
|
|
112
|
+
const meta = extractMetadata(code, {
|
|
113
|
+
namespaces: opts?.namespaces ?? [],
|
|
114
|
+
looseLocalCalls: true,
|
|
115
|
+
...(opts?.opDims ? { opDims: opts.opDims } : {}),
|
|
116
|
+
});
|
|
108
117
|
const last = meta.lines[meta.lines.length - 1];
|
|
109
118
|
if (!last)
|
|
110
119
|
return { positional: [], args: {} };
|
|
@@ -121,4 +130,34 @@ export function codeToArgs(codeLine, opts) {
|
|
|
121
130
|
}
|
|
122
131
|
return { positional, args: { ...last.args } };
|
|
123
132
|
}
|
|
133
|
+
// ── P7/D10: unit literal parsing ────────────────────────────────────────────
|
|
134
|
+
/**
|
|
135
|
+
* Reverse mapping: script-side constant name (UPPERCASE) → internal UnitName.
|
|
136
|
+
*/
|
|
137
|
+
const CONST_TO_UNIT = Object.freeze(Object.fromEntries(Object.keys(SCRIPT_UNIT_TO_NAME).map((k) => [k, SCRIPT_UNIT_TO_NAME[k]])));
|
|
138
|
+
/**
|
|
139
|
+
* Parse a unit literal text expression (`n * UNIT`) into its base-unit value.
|
|
140
|
+
*
|
|
141
|
+
* P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like
|
|
142
|
+
* `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.
|
|
143
|
+
* Non-unit-literal expressions return `null` (host decides whether to
|
|
144
|
+
* downgrade to read-only).
|
|
145
|
+
*
|
|
146
|
+
* @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).
|
|
147
|
+
* @returns the parsed unit literal info, or `null` if not a unit literal.
|
|
148
|
+
*/
|
|
149
|
+
export function parseUnitLiteral(text) {
|
|
150
|
+
const match = /^\s*(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\s*\*\s*([A-Z]+)\s*$/.exec(text);
|
|
151
|
+
if (!match)
|
|
152
|
+
return null;
|
|
153
|
+
const n = Number(match[1]);
|
|
154
|
+
const constName = match[2];
|
|
155
|
+
const unitName = CONST_TO_UNIT[constName];
|
|
156
|
+
if (!unitName)
|
|
157
|
+
return null;
|
|
158
|
+
const dim = UNIT_DIM[unitName];
|
|
159
|
+
// toBase: n * UNIT_SCALE[unitName]
|
|
160
|
+
const base = n * UNIT_SCALE[unitName];
|
|
161
|
+
return { base, dim, unitName };
|
|
162
|
+
}
|
|
124
163
|
//# sourceMappingURL=code-to-args.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-to-args.js","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * code-to-args — 单语句行 args 提取(编辑回填配套)\n *\n * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).\n *\n * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行\n * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),\n * 宿主不得用 acorn 自行解析(B3 修正)。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor 行级提取:\n * 单行文本经哨兵参数前置声明(与 MetadataExtractor looseLocalCalls 同构)\n * 交给 extractMetadata,取末条 op 行摘要的 positional/args。函数名、签名与\n * 返回契约(CodeToArgsResult)不变;HostArg 引用形态保真(A-5)。\n *\n * F1(表达式折叠):args 含计算表达式(binary/template/conditional/spread)时,\n * 与 parser 折叠语义一致地**求值后返回字面值**,不抛错。\n * 单行提取缺失参数真实值 → 前置声明用哨兵字面量 `let <id> = 0`(参数形态),\n * 使表达式可静态折叠;宿主用 StatementSummary.hasComputedArgs 判定只读降级,\n * 不得把折叠值写回源码(会丢失原表达式)。\n */\n\nimport type { HostArg } from './host-arg'\nimport { extractMetadata } from './metadata-extractor'\nimport { isHostRef } from './host-arg'\n\n/**\n * 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):\n * parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的\n * 裸标识符参数引用)要求变量已声明,而单行提取天然缺失声明上下文。\n * 规则:提取行内全部标识符(剥掉字符串字面量后),为每个非 `cad`/关键字\n * 标识符前置一行 `let <id> = 0`(哨兵参数)。parser 对该形态只做语法\n * 检查、不查符号表;多余声明对 varToId 仅是\"可查到\",不影响目标行的\n * args 解析结果。F1 起用哨兵参数(而非 `cad.assembly({})` 语句)——\n * 参数值已知 → 表达式可静态折叠,满足\"参数为表达式时返回折叠字面值\"。\n */\nconst IDENT_RE = /[A-Za-z_$][\\w$]*/g\nconst STRING_RE = /'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"/g\nconst NON_DECL = new Set([\n 'cad', 'const', 'let', 'true', 'false', 'null', 'undefined',\n 'await', 'return', 'new', 'typeof', 'var', 'function',\n])\n\nfunction extractIdentifiers(line: string, namespaces?: Set<string>): string[] {\n const withoutStrings = line.replace(STRING_RE, \"''\")\n const declared = declaredByLine(withoutStrings)\n const ids = new Set<string>()\n for (const m of withoutStrings.matchAll(IDENT_RE)) {\n const id = m[0]\n if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id)) continue\n ids.add(id)\n }\n return [...ids]\n}\n\n/**\n * 行内自身声明的标识符(前置声明必须跳过,否则 acorn 重声明报错):\n * - `const/let x = ...` 的 x\n * - `const { k1: v1, k2 } = ...` 的绑定名 v1/k2(键名 k1 不是声明,仍需前置声明——无害)\n */\nfunction declaredByLine(line: string): Set<string> {\n const ids = new Set<string>()\n let m = /^\\s*(?:const|let)\\s+([A-Za-z_$][\\w$]*)\\s*=/.exec(line)\n if (m) ids.add(m[1])\n m = /^\\s*const\\s*\\{([^}]*)\\}\\s*=/.exec(line)\n if (m) {\n for (const prop of m[1].split(',')) {\n const bound = (prop.split(':')[1] ?? prop).trim()\n const id = /^([A-Za-z_$][\\w$]*)/.exec(bound)\n if (id) ids.add(id[1])\n }\n }\n return ids\n}\n\n/**\n * `codeToArgs` 的返回契约:位置实参槽 + 尾随选项对象(HostArg 形态,纯数据无 IR)。\n */\nexport interface CodeToArgsResult {\n positional: HostArg[]\n args: Record<string, HostArg>\n}\n\n/**\n * 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 IR 变体语义)。\n *\n * true-JS-subset §4.6.3 新契约:返回 `{ positional, args }`——\n * - `positional`: HostArg[],按调用顺序的位置实参(字面量原样;var-ref/\n * param-ref/call-ref/expr-ref 以 `{kind,...}` 标记对象呈现,宿主据此降级为\n * 只读编辑);宿主不接触内部类型(纯数据面)。\n * - `args`: 尾随选项对象(键值 HostArg 形态;无选项对象时为 `{}`)。\n * 旧契约(只返回对象槽)在位置形态下会静默丢弃非对象实参——本契约显式保留全部信息。\n *\n * 支持的行形态(与 parser 接受的语句一致):\n * - `const part0 = cad.box(10, 20, 30)`\n * - `part0 = cad.fai_drill(part0, { diameter: 5 })`(裸重赋值)\n * - `const { front: a, back: b } = cad.fai_split(part0, { normal: [0,0,1] })`(解构)\n * - `asm0.add_constraint({ ... })`(成员方法调用)\n * - 位置实参为字面量/变量引用/表达式(`cad.box(10, 20, 30)`、`cad.hem(p0.solid, {...})`)\n * - args 中的裸标识符参数引用(`cad.box(10, 20, height)`)\n * - args 中的计算表达式(`cad.box(10, 20, base + 20)`)→ 折叠为字面值返回\n *\n * @param codeLine 单条语句源码行\n * @param opts.namespaces 该脚本顶层 import 的绑定名(F2:`mech.makeHeadstock(...)`\n * 中 `mech` 不得被前置声明为变量)。L0 不感知注册表,由宿主从脚本 imports 提供。\n * @returns the extracted positional slot and trailing options object (both in\n * serialized JSON form).\n * @throws ParseError — 行文本不是合法语句时抛出(含行号)\n */\nexport function codeToArgs(codeLine: string, opts?: { namespaces?: string[] }): CodeToArgsResult {\n const namespaces = new Set(opts?.namespaces ?? [])\n const decls = extractIdentifiers(codeLine, namespaces)\n .map((id) => `let ${id} = 0`)\n .join('\\n')\n const code = decls ? `${decls}\\n${codeLine}` : codeLine\n // 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;\n // 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,\n // 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。\n const meta = extractMetadata(code, { namespaces: opts?.namespaces ?? [], looseLocalCalls: true })\n const last = meta.lines[meta.lines.length - 1]\n if (!last) return { positional: [], args: {} }\n // 尾随纯对象(选项槽)从 positional 切出到 args(与现状 splitTrailingOptions\n // 同构:末位纯数据对象是选项槽;引用形态/字面量留在 positional)。\n const positional = [...last.positional]\n const lastArg = positional[positional.length - 1]\n if (\n lastArg !== null &&\n typeof lastArg === 'object' &&\n !Array.isArray(lastArg) &&\n !isHostRef(lastArg as HostArg)\n ) {\n positional.pop()\n return { positional, args: { ...(lastArg as Record<string, HostArg>) } }\n }\n return { positional, args: { ...last.args } }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"code-to-args.js","sourceRoot":"","sources":["../../src/lang/code-to-args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * code-to-args — 单语句行 args 提取(编辑回填配套)\n *\n * See docs/syntax-design.md §3 (statement model ↔ StatementSummary mapping) and §6.4 (check).\n *\n * 宿主编辑回填(FeatureEditor.backfill / editStatement)需要从代码行\n * 反提参数对象。此能力由 faijs 标配提供(与 parse 语义一致),\n * 宿主不得用 acorn 自行解析(B3 修正)。\n *\n * 无 IR 双通道方案(2026-09-06)后实现换 MetadataExtractor 行级提取:\n * 单行文本经哨兵参数前置声明(与 MetadataExtractor looseLocalCalls 同构)\n * 交给 extractMetadata,取末条 op 行摘要的 positional/args。函数名、签名与\n * 返回契约(CodeToArgsResult)不变;HostArg 引用形态保真(A-5)。\n *\n * F1(表达式折叠):args 含计算表达式(binary/template/conditional/spread)时,\n * 与 parser 折叠语义一致地**求值后返回字面值**,不抛错。\n * 单行提取缺失参数真实值 → 前置声明用哨兵字面量 `let <id> = 0`(参数形态),\n * 使表达式可静态折叠;宿主用 StatementSummary.hasComputedArgs 判定只读降级,\n * 不得把折叠值写回源码(会丢失原表达式)。\n */\n\nimport type { HostArg } from './host-arg'\nimport { extractMetadata, type OpDimMap } from './metadata-extractor'\nimport { isHostRef } from './host-arg'\nimport { SCRIPT_UNIT_NAMES, UNIT_SCALE, UNIT_DIM, SCRIPT_UNIT_TO_NAME } from '../units'\nimport type { DimName, UnitName } from '../units'\n\n/**\n * 单行提取的前置声明规则(确定性静态规则,非 try/catch 兜底):\n * parser 的作用域检查(inputs / 重赋值 LHS / 成员方法 receiver / args 中的\n * 裸标识符参数引用)要求变量已声明,而单行提取天然缺失声明上下文。\n * 规则:提取行内全部标识符(剥掉字符串字面量后),为每个非 `cad`/关键字\n * 标识符前置一行 `let <id> = 0`(哨兵参数)。parser 对该形态只做语法\n * 检查、不查符号表;多余声明对 varToId 仅是\"可查到\",不影响目标行的\n * args 解析结果。F1 起用哨兵参数(而非 `cad.assembly({})` 语句)——\n * 参数值已知 → 表达式可静态折叠,满足\"参数为表达式时返回折叠字面值\"。\n */\nconst IDENT_RE = /[A-Za-z_$][\\w$]*/g\nconst STRING_RE = /'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"/g\nconst NON_DECL = new Set([\n 'cad', 'const', 'let', 'true', 'false', 'null', 'undefined',\n 'await', 'return', 'new', 'typeof', 'var', 'function',\n])\n\nfunction extractIdentifiers(line: string, namespaces?: Set<string>): string[] {\n const withoutStrings = line.replace(STRING_RE, \"''\")\n const declared = declaredByLine(withoutStrings)\n const ids = new Set<string>()\n for (const m of withoutStrings.matchAll(IDENT_RE)) {\n const id = m[0]\n // P7/D10.4: unit constants (MM, INCH, DEGREE, …) must NOT be pre-declared\n // as sentinel parameters (`let INCH = 0`), because that would shadow the\n // real global value and cause `10 * INCH` to fold to 0.\n if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id) || SCRIPT_UNIT_NAMES.has(id)) continue\n ids.add(id)\n }\n return [...ids]\n}\n\n/**\n * 行内自身声明的标识符(前置声明必须跳过,否则 acorn 重声明报错):\n * - `const/let x = ...` 的 x\n * - `const { k1: v1, k2 } = ...` 的绑定名 v1/k2(键名 k1 不是声明,仍需前置声明——无害)\n */\nfunction declaredByLine(line: string): Set<string> {\n const ids = new Set<string>()\n let m = /^\\s*(?:const|let)\\s+([A-Za-z_$][\\w$]*)\\s*=/.exec(line)\n if (m) ids.add(m[1])\n m = /^\\s*const\\s*\\{([^}]*)\\}\\s*=/.exec(line)\n if (m) {\n for (const prop of m[1].split(',')) {\n const bound = (prop.split(':')[1] ?? prop).trim()\n const id = /^([A-Za-z_$][\\w$]*)/.exec(bound)\n if (id) ids.add(id[1])\n }\n }\n return ids\n}\n\n/**\n * `codeToArgs` 的返回契约:位置实参槽 + 尾随选项对象(HostArg 形态,纯数据无 IR)。\n */\nexport interface CodeToArgsResult {\n positional: HostArg[]\n args: Record<string, HostArg>\n}\n\n/**\n * codeToArgs 选项。`opDims` 为 P4/P6 (unit-system D8) 透传:callee → 量纲声明,\n * 供单行回填路径的 dimension pass 消费(P6 落地前声明面透传即可,不影响解析结果)。\n */\nexport interface CodeToArgsOptions {\n /** 该脚本顶层 import 的绑定名(F2)。 */\n namespaces?: string[]\n /** callee → 量纲声明(unit-system D8,P6 消费)。 */\n opDims?: OpDimMap\n}\n\n/**\n * 解析单条语句行,提取其位置实参槽与选项对象(序列化形态,无 IR 变体语义)。\n *\n * true-JS-subset §4.6.3 新契约:返回 `{ positional, args }`——\n * - `positional`: HostArg[],按调用顺序的位置实参(字面量原样;var-ref/\n * param-ref/call-ref/expr-ref 以 `{kind,...}` 标记对象呈现,宿主据此降级为\n * 只读编辑);宿主不接触内部类型(纯数据面)。\n * - `args`: 尾随选项对象(键值 HostArg 形态;无选项对象时为 `{}`)。\n * 旧契约(只返回对象槽)在位置形态下会静默丢弃非对象实参——本契约显式保留全部信息。\n *\n * 支持的行形态(与 parser 接受的语句一致):\n * - `const part0 = cad.box(10, 20, 30)`\n * - `part0 = cad.fai_drill(part0, { diameter: 5 })`(裸重赋值)\n * - `const { front: a, back: b } = cad.fai_split(part0, { normal: [0,0,1] })`(解构)\n * - `asm0.add_constraint({ ... })`(成员方法调用)\n * - 位置实参为字面量/变量引用/表达式(`cad.box(10, 20, 30)`、`cad.hem(p0.solid, {...})`)\n * - args 中的裸标识符参数引用(`cad.box(10, 20, height)`)\n * - args 中的计算表达式(`cad.box(10, 20, base + 20)`)→ 折叠为字面值返回\n *\n * @param codeLine 单条语句源码行\n * @param opts.namespaces 该脚本顶层 import 的绑定名(F2:`mech.makeHeadstock(...)`\n * 中 `mech` 不得被前置声明为变量)。L0 不感知注册表,由宿主从脚本 imports 提供。\n * @returns the extracted positional slot and trailing options object (both in\n * serialized JSON form).\n * @throws ParseError — 行文本不是合法语句时抛出(含行号)\n */\nexport function codeToArgs(codeLine: string, opts?: CodeToArgsOptions): CodeToArgsResult {\n const namespaces = new Set(opts?.namespaces ?? [])\n const decls = extractIdentifiers(codeLine, namespaces)\n .map((id) => `let ${id} = 0`)\n .join('\\n')\n const code = decls ? `${decls}\\n${codeLine}` : codeLine\n // 单行提取语义:前置哨兵参数(let id = 0)在 extractMetadata 中按参数行处理;\n // 末条 op 行摘要 = 目标行。裸本机函数 callee(makeArray 等)放行(looseLocalCalls,\n // 与现状 codeToArgs 的 MetadataExtractor looseLocalCalls 同语义;ABI 校验延后到完整脚本上下文)。\n // opDims 透传给 dimension pass(P6 消费,P4 仅透传声明面)。\n const meta = extractMetadata(code, {\n namespaces: opts?.namespaces ?? [],\n looseLocalCalls: true,\n ...(opts?.opDims ? { opDims: opts.opDims } : {}),\n })\n const last = meta.lines[meta.lines.length - 1]\n if (!last) return { positional: [], args: {} }\n // 尾随纯对象(选项槽)从 positional 切出到 args(与现状 splitTrailingOptions\n // 同构:末位纯数据对象是选项槽;引用形态/字面量留在 positional)。\n const positional = [...last.positional]\n const lastArg = positional[positional.length - 1]\n if (\n lastArg !== null &&\n typeof lastArg === 'object' &&\n !Array.isArray(lastArg) &&\n !isHostRef(lastArg as HostArg)\n ) {\n positional.pop()\n return { positional, args: { ...(lastArg as Record<string, HostArg>) } }\n }\n return { positional, args: { ...last.args } }\n}\n\n// ── P7/D10: unit literal parsing ────────────────────────────────────────────\n\n/**\n * Reverse mapping: script-side constant name (UPPERCASE) → internal UnitName.\n */\nconst CONST_TO_UNIT: Readonly<Record<string, UnitName>> = Object.freeze(\n Object.fromEntries(\n (Object.keys(SCRIPT_UNIT_TO_NAME) as string[]).map(\n (k) => [k, SCRIPT_UNIT_TO_NAME[k]] as [string, UnitName],\n ),\n ),\n)\n\n/**\n * Parse a unit literal text expression (`n * UNIT`) into its base-unit value.\n *\n * P7/D10.3: This is the reverse of `formatUnitLiteral`. Given text like\n * `10 * INCH`, returns `{ base: 254, dim: 'length', unitName: 'inch' }`.\n * Non-unit-literal expressions return `null` (host decides whether to\n * downgrade to read-only).\n *\n * @param text - the expression text (e.g. `10 * INCH` or `0.5 * DEGREE`).\n * @returns the parsed unit literal info, or `null` if not a unit literal.\n */\nexport function parseUnitLiteral(text: string): { base: number; dim: DimName; unitName: UnitName } | null {\n const match = /^\\s*(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)\\s*\\*\\s*([A-Z]+)\\s*$/.exec(text)\n if (!match) return null\n const n = Number(match[1])\n const constName = match[2]\n const unitName = CONST_TO_UNIT[constName]\n if (!unitName) return null\n const dim = UNIT_DIM[unitName]\n // toBase: n * UNIT_SCALE[unitName]\n const base = n * UNIT_SCALE[unitName]\n return { base, dim, unitName }\n}\n"]}
|
package/dist/lang/codegen.d.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* - 对象字面量 → `{key:value}`(冒号,合法 JS)
|
|
21
21
|
*/
|
|
22
22
|
import type { HostArg } from './host-arg.js';
|
|
23
|
+
import type { DimName, UnitName, UnitContext } from '../units.js';
|
|
23
24
|
/**
|
|
24
25
|
* Format a number as text: integers emit as-is; decimals retain at most 6
|
|
25
26
|
* significant fractional digits with trailing zeros stripped.
|
|
@@ -27,6 +28,43 @@ import type { HostArg } from './host-arg.js';
|
|
|
27
28
|
* @returns the formatted text representation.
|
|
28
29
|
*/
|
|
29
30
|
export declare function fmtNum(n: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Format a unit literal number using JS shortest-round-trip representation.
|
|
33
|
+
*
|
|
34
|
+
* P7/D10.3 rule 5: unit literal numbers MUST use `String(n)` (e.g.
|
|
35
|
+
* `0.39370078740157477`), NEVER `fmtNum` (which truncates to 6 decimal
|
|
36
|
+
* places and would silently zero out `1e-7`).
|
|
37
|
+
* @param n - the number to format.
|
|
38
|
+
* @returns the shortest JS round-trip text representation.
|
|
39
|
+
*/
|
|
40
|
+
export declare function fmtUnitNum(n: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* Format a base-unit value as a unit literal expression (`n * UNIT`).
|
|
43
|
+
*
|
|
44
|
+
* P7/D10.3: `base` is the base-unit (mm/degree) value; `dim` determines which
|
|
45
|
+
* system display unit to use; `unitName` is the target display unit.
|
|
46
|
+
* The number is formatted with `fmtUnitNum` (not `fmtNum`).
|
|
47
|
+
* @param base - the base-unit numeric value.
|
|
48
|
+
* @param dim - the dimension of the value.
|
|
49
|
+
* @param unitName - the display unit to express the value in.
|
|
50
|
+
* @returns text like `10 * INCH` or `0.39370078740157477 * INCH`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function formatUnitLiteral(base: number, dim: DimName, unitName: UnitName): string;
|
|
53
|
+
/**
|
|
54
|
+
* P7/D10.3: Options for unit-aware serialization of `formatCodeLine`.
|
|
55
|
+
*
|
|
56
|
+
* When provided, dimensioned parameters are emitted as unit literals
|
|
57
|
+
* (`n * UNIT`). When absent, output is byte-identical to the pre-P7 behavior.
|
|
58
|
+
*/
|
|
59
|
+
export interface UnitSerializeOptions {
|
|
60
|
+
/** System display unit; defaults to base (mm / degree). */
|
|
61
|
+
units?: UnitContext;
|
|
62
|
+
/** Parameter dimension declarations (host provides from op paramDims + slotMap). */
|
|
63
|
+
dims?: {
|
|
64
|
+
positional?: (DimName | null)[];
|
|
65
|
+
byKey?: Record<string, DimName>;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
30
68
|
/**
|
|
31
69
|
* Pure-data input for printing one faijs source line, decoupled from IR types.
|
|
32
70
|
*
|
|
@@ -65,8 +103,14 @@ export interface FormatCodeLineInput {
|
|
|
65
103
|
* 从纯数据(非 IR 类型)打印一行 faijs 源代码。
|
|
66
104
|
*
|
|
67
105
|
* 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
|
|
106
|
+
*
|
|
107
|
+
* P7/D10: when `opts` is provided, dimensioned parameters are serialized as
|
|
108
|
+
* unit literals (`n * UNIT`). When `opts` is absent, output is byte-identical
|
|
109
|
+
* to the pre-P7 behavior (zero-impact regression guarantee).
|
|
110
|
+
*
|
|
68
111
|
* @param input - the pure-data line description.
|
|
112
|
+
* @param opts - optional unit serialization options (P7/D10).
|
|
69
113
|
* @returns the printed single-line code text.
|
|
70
114
|
*/
|
|
71
|
-
export declare function formatCodeLine(input: FormatCodeLineInput): string;
|
|
115
|
+
export declare function formatCodeLine(input: FormatCodeLineInput, opts?: UnitSerializeOptions): string;
|
|
72
116
|
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/lang/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAK9D;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxC;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAcD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAIxF;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,oFAAoF;IACpF,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAC5E;AA0BD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,YAAY;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,0BAA0B;IAC1B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAyFD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,MAAM,CA4D9F"}
|