@faicad/faijs 0.19.0 → 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.
Files changed (140) hide show
  1. package/dist/api/brep-mirror/joinery-brep.d.ts.map +1 -1
  2. package/dist/api/brep-mirror/joinery-brep.js +3 -1
  3. package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
  4. package/dist/api/generated/script-face-manifest.d.ts +4 -0
  5. package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
  6. package/dist/api/generated/script-face-manifest.js.map +1 -1
  7. package/dist/api/knurl.d.ts.map +1 -1
  8. package/dist/api/knurl.js +1 -0
  9. package/dist/api/knurl.js.map +1 -1
  10. package/dist/api/primitives.d.ts +4 -3
  11. package/dist/api/primitives.d.ts.map +1 -1
  12. package/dist/api/primitives.js +9 -3
  13. package/dist/api/primitives.js.map +1 -1
  14. package/dist/api/profile.d.ts +34 -5
  15. package/dist/api/profile.d.ts.map +1 -1
  16. package/dist/api/profile.js +60 -9
  17. package/dist/api/profile.js.map +1 -1
  18. package/dist/api/punch-hole.d.ts +3 -0
  19. package/dist/api/punch-hole.d.ts.map +1 -1
  20. package/dist/api/punch-hole.js.map +1 -1
  21. package/dist/api/sketch-on-plane.d.ts +12 -6
  22. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  23. package/dist/api/sketch-on-plane.js +11 -8
  24. package/dist/api/sketch-on-plane.js.map +1 -1
  25. package/dist/api/surface/arg-spec.d.ts +8 -0
  26. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  27. package/dist/api/surface/arg-spec.js.map +1 -1
  28. package/dist/api/transform.d.ts +5 -5
  29. package/dist/api/transform.d.ts.map +1 -1
  30. package/dist/api/transform.js +12 -10
  31. package/dist/api/transform.js.map +1 -1
  32. package/dist/api/xml-dom.d.ts +27 -0
  33. package/dist/api/xml-dom.d.ts.map +1 -0
  34. package/dist/api/xml-dom.js +45 -0
  35. package/dist/api/xml-dom.js.map +1 -0
  36. package/dist/brep/brep-ops.d.ts +4 -4
  37. package/dist/brep/brep-ops.d.ts.map +1 -1
  38. package/dist/brep/brep-ops.js +8 -6
  39. package/dist/brep/brep-ops.js.map +1 -1
  40. package/dist/brep/brep-topology.d.ts.map +1 -1
  41. package/dist/brep/brep-topology.js +3 -1
  42. package/dist/brep/brep-topology.js.map +1 -1
  43. package/dist/brep/export/export-model.d.ts +79 -0
  44. package/dist/brep/export/export-model.d.ts.map +1 -0
  45. package/dist/brep/export/export-model.js +335 -0
  46. package/dist/brep/export/export-model.js.map +1 -0
  47. package/dist/brep/primitives-brep.d.ts.map +1 -1
  48. package/dist/brep/primitives-brep.js +3 -1
  49. package/dist/brep/primitives-brep.js.map +1 -1
  50. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  51. package/dist/brepkit-kernel/brepkitKernel.js +4 -2
  52. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  53. package/dist/cad-runtime/direct-executor.d.ts +4 -0
  54. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  55. package/dist/cad-runtime/direct-executor.js +17 -1
  56. package/dist/cad-runtime/direct-executor.js.map +1 -1
  57. package/dist/cad-runtime/runtime.d.ts +24 -1
  58. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  59. package/dist/cad-runtime/runtime.js +53 -3
  60. package/dist/cad-runtime/runtime.js.map +1 -1
  61. package/dist/define-op.d.ts +22 -0
  62. package/dist/define-op.d.ts.map +1 -1
  63. package/dist/define-op.js +15 -0
  64. package/dist/define-op.js.map +1 -1
  65. package/dist/env-agnostic.d.ts +7 -7
  66. package/dist/env-agnostic.d.ts.map +1 -1
  67. package/dist/env-agnostic.js +3 -3
  68. package/dist/env-agnostic.js.map +1 -1
  69. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  70. package/dist/geometry2d/bridge/lift-on-plane.js +6 -0
  71. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  72. package/dist/geometry2d/pen-sketcher.d.ts +25 -0
  73. package/dist/geometry2d/pen-sketcher.d.ts.map +1 -1
  74. package/dist/geometry2d/pen-sketcher.js +43 -0
  75. package/dist/geometry2d/pen-sketcher.js.map +1 -1
  76. package/dist/lang/code-to-args.d.ts +29 -3
  77. package/dist/lang/code-to-args.d.ts.map +1 -1
  78. package/dist/lang/code-to-args.js +41 -2
  79. package/dist/lang/code-to-args.js.map +1 -1
  80. package/dist/lang/codegen.d.ts +45 -1
  81. package/dist/lang/codegen.d.ts.map +1 -1
  82. package/dist/lang/codegen.js +135 -6
  83. package/dist/lang/codegen.js.map +1 -1
  84. package/dist/lang/host-arg.d.ts +6 -0
  85. package/dist/lang/host-arg.d.ts.map +1 -1
  86. package/dist/lang/host-arg.js.map +1 -1
  87. package/dist/lang/metadata-extractor.d.ts +25 -0
  88. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  89. package/dist/lang/metadata-extractor.js +289 -25
  90. package/dist/lang/metadata-extractor.js.map +1 -1
  91. package/dist/lang/parse-error.d.ts +7 -1
  92. package/dist/lang/parse-error.d.ts.map +1 -1
  93. package/dist/lang/parse-error.js.map +1 -1
  94. package/dist/lang/security-scanner.d.ts +9 -1
  95. package/dist/lang/security-scanner.d.ts.map +1 -1
  96. package/dist/lang/security-scanner.js +38 -1
  97. package/dist/lang/security-scanner.js.map +1 -1
  98. package/dist/mesh/io.d.ts +62 -9
  99. package/dist/mesh/io.d.ts.map +1 -1
  100. package/dist/mesh/io.js +124 -17
  101. package/dist/mesh/io.js.map +1 -1
  102. package/dist/mesh/threemf-loader.d.ts +15 -0
  103. package/dist/mesh/threemf-loader.d.ts.map +1 -0
  104. package/dist/mesh/threemf-loader.js +163 -0
  105. package/dist/mesh/threemf-loader.js.map +1 -0
  106. package/dist/mesh/transform.d.ts +2 -2
  107. package/dist/mesh/transform.d.ts.map +1 -1
  108. package/dist/mesh/transform.js +3 -3
  109. package/dist/mesh/transform.js.map +1 -1
  110. package/dist/mesh/types.d.ts +1 -1
  111. package/dist/mesh/types.d.ts.map +1 -1
  112. package/dist/mesh/types.js.map +1 -1
  113. package/dist/node-host/cli.d.ts.map +1 -1
  114. package/dist/node-host/cli.js +53 -26
  115. package/dist/node-host/cli.js.map +1 -1
  116. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  117. package/dist/occt-kernel/occtKernel.js +4 -2
  118. package/dist/occt-kernel/occtKernel.js.map +1 -1
  119. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  120. package/dist/occt-kernel/topologyExt.js +4 -1
  121. package/dist/occt-kernel/topologyExt.js.map +1 -1
  122. package/dist/runtime-state.d.ts +18 -0
  123. package/dist/runtime-state.d.ts.map +1 -1
  124. package/dist/runtime-state.js +23 -0
  125. package/dist/runtime-state.js.map +1 -1
  126. package/dist/sdk.d.ts +1 -1
  127. package/dist/sdk.d.ts.map +1 -1
  128. package/dist/sdk.js +1 -1
  129. package/dist/sdk.js.map +1 -1
  130. package/dist/tolerance.d.ts +38 -0
  131. package/dist/tolerance.d.ts.map +1 -0
  132. package/dist/tolerance.js +40 -0
  133. package/dist/tolerance.js.map +1 -0
  134. package/dist/topology/naming/score.js +3 -3
  135. package/dist/topology/naming/score.js.map +1 -1
  136. package/dist/units.d.ts +248 -0
  137. package/dist/units.d.ts.map +1 -0
  138. package/dist/units.js +397 -0
  139. package/dist/units.js.map +1 -0
  140. package/package.json +11 -2
@@ -1 +1 @@
1
- {"version":3,"file":"pen-sketcher.js","sourceRoot":"","sources":["../../src/geometry2d/pen-sketcher.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * geometry2d — 2D `BaseSketcher2d` pen (C1), adapted for the pure-object base.\n *\n * Ported from brepjs `2d/blueprints/baseSketcher2d.ts` (Apache-2.0).\n *\n * The brepjs original accumulates kernel-backed `Curve2D` handles (mutable:\n * `delete`/`reverse`/`tangentAt`). Here those are replaced by the pure\n * `Curve2dObj` base of `geometry2d/curve2d` — each pen method emits a plain\n * object, the pointer advances by plain arithmetic, and end-tangent lookup maps\n * to `tangentCurve2d`. `curves()`/`close()` return the ordered `Curve2dObj[]`,\n * which feeds `Blueprint` and the 2D→3D placement pipeline.\n *\n * Not-yet-ported (honest `throw`s, per the D-group/port plan):\n * · `ellipse*` — needs the SVG ellipse→arc helper;\n * · `smoothSplit*` — needs the spline control helper;\n * · `customCorner`/`closeWithMirror` — needs 2D corner/mirror ops (D-group).\n *\n * @module\n */\n\nimport {\n makeLine2d,\n makeArc2dThreePoints,\n makeArc2dTangent,\n makeBezier2d,\n tangentCurve2d,\n type Curve2dObj,\n} from './curve2d'\nimport { makeEllipseArcFromSvgParams, normalizeEllipseRadii } from './svg-ellipse'\nimport { distance2d, normalize2d, polarAngle2d, polarToCartesian, samePoint } from './point'\n\nconst DEG2RAD = Math.PI / 180\nconst RAD2DEG = 180 / Math.PI\n\n/** A `[x, y]` 2D point (plain tuple). */\nexport type Point2 = [number, number]\n\n/** Options accepted by the spline methods. */\nexport type SplineOptions = {\n /** Explicit start tangent; defaults to `[1,0]` or the previous segment's end tangent. */\n startTangent?: Point2\n /** Explicit end tangent, or the literal `'symmetric'` (mirror of the start tangent). */\n endTangent?: Point2 | 'symmetric'\n /** Start control-length factor. */\n startFactor?: number\n /** End control-length factor. */\n endFactor?: number\n}\n\n/** Corner modes accepted by `customCorner` (D-group, not yet ported). */\nexport type CornerMode = 'fillet' | 'chamfer' | 'dogbone'\n\n/** Guard-style error: throw so callers immediately see pen misuse. */\nfunction bug(caller: string, message: string): never {\n throw new Error(`[geometry2d/pen] ${caller}: ${message}`)\n}\n\n/** Non-normalized tangent at the end of a curve (t=1 within its direct parameter space). */\nfunction endTangent(c: Curve2dObj): [number, number] {\n return tangentCurve2d(c, 1)\n}\n\n/**\n * Base class for 2D flood-pen sketchers that accumulate `Curve2dObj` segments.\n *\n * Provides the shared pen-drawing API (lines, arcs, beziers) used by the\n * drawing DSL. Subclasses implement `close()` to package the accumulated curves\n * as a `Blueprint` or plain curve list.\n */\nexport class BaseSketcher2d {\n /** Current pen position `[x, y]`. */\n pointer: Point2\n /** The starting point of the pen run. */\n firstPoint: Point2\n /** Accumulated segments, in draw order. */\n pendingCurves: Curve2dObj[]\n /** A queued one-shot corner transform (D-group; unused until ported). */\n _nextCorner: ((a: Curve2dObj, b: Curve2dObj) => Curve2dObj[]) | null\n\n constructor(origin: Point2 = [0, 0]) {\n this.pointer = origin\n this.firstPoint = origin\n this.pendingCurves = []\n this._nextCorner = null\n }\n\n /**\n * The most recently drawn curve, or `null`.\n * @returns the last drawn curve, or `null` when nothing has been drawn.\n */\n _lastCurve(): Curve2dObj | null {\n return this.pendingCurves.length ? this.pendingCurves[this.pendingCurves.length - 1]! : null\n }\n\n /**\n * Fetch the last drawn curve, or throw a misuse error.\n * @param caller - the calling method name (for the error message).\n * @returns the last curve.\n */\n _requireLastCurve(caller: string): Curve2dObj {\n const c = this._lastCurve()\n if (!c) bug(caller, 'You need a previous curve to continue')\n return c\n }\n\n /**\n * Add a relative offset to the current pointer.\n * @param xDist - relative x distance.\n * @param yDist - relative y distance.\n * @returns the resulting absolute point.\n */\n _resolveRelative(xDist: number, yDist: number): Point2 {\n return [this.pointer[0] + xDist, this.pointer[1] + yDist]\n }\n\n /**\n * Save a curve and advance the pen to `end`.\n * @param curve - the curve to record.\n * @param end - the new pen position.\n * @returns this pen, for chaining.\n */\n _saveCurveAndAdvance(curve: Curve2dObj, end: Point2): this {\n this.saveCurve(curve)\n this.pointer = end\n return this\n }\n\n /** The current pen position `[x, y]`. */\n get penPosition(): Point2 {\n return this.pointer\n }\n\n /** The current pen angle in degrees (direction of the last segment's end tangent). */\n get penAngle(): number {\n const last = this._lastCurve()\n if (!last) return 0\n const [dx, dy] = endTangent(last)\n return Math.atan2(dy, dx) * RAD2DEG\n }\n\n /**\n * Move the pen to an absolute position before any segment is drawn.\n * @param point - the absolute start position.\n * @returns this pen, for chaining.\n */\n movePointerTo(point: Point2): this {\n if (this.pendingCurves.length) bug('movePointerTo', 'You can only move the pointer if there is no curve defined')\n this.pointer = point\n this.firstPoint = point\n return this\n }\n\n /**\n * Record a segment, applying a queued corner transform if present.\n * @param curve - the curve to record.\n */\n saveCurve(curve: Curve2dObj): void {\n if (!this._nextCorner) {\n this.pendingCurves.push(curve)\n return\n }\n const previous = this.pendingCurves.pop()\n if (!previous) bug('saveCurve', 'No previous curve available for custom corner')\n const cornered = this._nextCorner!(previous, curve)\n this.pendingCurves.push(...cornered)\n this._nextCorner = null\n }\n\n /**\n * Draw a straight line to an absolute point.\n * @param point - the absolute end point.\n * @returns this pen, for chaining.\n */\n lineTo(point: Point2): this {\n return this._saveCurveAndAdvance(makeLine2d(this.pointer[0], this.pointer[1], point[0], point[1]), point)\n }\n\n /**\n * Draw a straight line by relative horizontal and vertical distances.\n * @param x - relative x distance.\n * @param y - relative y distance.\n * @returns this pen, for chaining.\n */\n line(x: number, y: number): this {\n return this.lineTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw a vertical line of the given signed distance.\n * @param distance - signed vertical distance.\n * @returns this pen, for chaining.\n */\n vLine(distance: number): this {\n return this.line(0, distance)\n }\n\n /**\n * Draw a horizontal line of the given signed distance.\n * @param distance - signed horizontal distance.\n * @returns this pen, for chaining.\n */\n hLine(distance: number): this {\n return this.line(distance, 0)\n }\n\n /**\n * Draw a vertical line to an absolute Y coordinate.\n * @param yPos - the absolute y.\n * @returns this pen, for chaining.\n */\n vLineTo(yPos: number): this {\n return this.lineTo([this.pointer[0], yPos])\n }\n\n /**\n * Draw a horizontal line to an absolute X coordinate.\n * @param xPos - the absolute x.\n * @returns this pen, for chaining.\n */\n hLineTo(xPos: number): this {\n return this.lineTo([xPos, this.pointer[1]])\n }\n\n /**\n * Draw a line to an absolute point in polar form.\n * @param polar - `[radius, angleDeg]`.\n * @returns this pen, for chaining.\n */\n polarLineTo(polar: Point2): this {\n const [x, y] = polarToCartesian(polar[0], polar[1] * DEG2RAD)\n return this.lineTo([x, y])\n }\n\n /**\n * Draw a line in polar relative form.\n * @param distance - radial distance.\n * @param angle - angle in degrees.\n * @returns this pen, for chaining.\n */\n polarLine(distance: number, angle: number): this {\n const [x, y] = polarToCartesian(distance, angle * DEG2RAD)\n return this.line(x, y)\n }\n\n /**\n * Draw a line tangent to the previous curve.\n * @param distance - distance along the tangent.\n * @returns this pen, for chaining.\n */\n tangentLine(distance: number): this {\n const previous = this._requireLastCurve('tangentLine')\n const [dx, dy] = normalize2d(endTangent(previous))\n return this.line(dx * distance, dy * distance)\n }\n\n /**\n * Draw a circular arc through a mid-point to an absolute end point.\n * @param end - the absolute end point.\n * @param midPoint - a point on the arc.\n * @returns this pen, for chaining.\n */\n threePointsArcTo(end: Point2, midPoint: Point2): this {\n const curve = makeArc2dThreePoints(this.pointer[0], this.pointer[1], midPoint[0], midPoint[1], end[0], end[1])\n return this._saveCurveAndAdvance(curve, end)\n }\n\n /**\n * Draw a circular arc through a via-point to an end point, both relative.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param viaX - relative via x distance.\n * @param viaY - relative via y distance.\n * @returns this pen, for chaining.\n */\n threePointsArc(x: number, y: number, viaX: number, viaY: number): this {\n const [ax, ay] = this.pointer\n return this.threePointsArcTo([ax + x, ay + y], [ax + viaX, ay + viaY])\n }\n\n /**\n * Draw a circular arc to an absolute end, bulging `sagitta` off the chord.\n * @param end - the absolute end point.\n * @param sagitta - the sagitta (signed bulge off the chord).\n * @returns this pen, for chaining.\n */\n sagittaArcTo(end: Point2, sagitta: number): this {\n const [x0, y0] = this.pointer\n const [x1, y1] = end\n const midX = (x0 + x1) / 2\n const midY = (y0 + y1) / 2\n const sX = -(y1 - y0)\n const sY = x1 - x0\n const sLen = Math.hypot(sX, sY)\n if (sLen < 1e-12) bug('sagittaArcTo', 'Start and end points cannot be identical')\n const sag: Point2 = [midX + (sX / sLen) * sagitta, midY + (sY / sLen) * sagitta]\n return this.threePointsArcTo(end, sag)\n }\n\n /**\n * Draw a circular arc to a relative end, bulging `sagitta`.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n sagittaArc(x: number, y: number, sagitta: number): this {\n return this.sagittaArcTo(this._resolveRelative(x, y), sagitta)\n }\n\n /**\n * Draw a vertical sagitta arc of `distance` and `sagitta`.\n * @param distance - vertical distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n vSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(0, distance, sagitta)\n }\n\n /**\n * Draw a horizontal sagitta arc of `distance` and `sagitta`.\n * @param distance - horizontal distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n hSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(distance, 0, sagitta)\n }\n\n /**\n * Draw a circular arc to an absolute end via a bulge factor.\n * @param end - the absolute end point.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArcTo(end: Point2, bulge: number): this {\n if (!bulge) return this.lineTo(end)\n const halfChord = distance2d(this.pointer, end) / 2\n return this.sagittaArcTo(end, -bulge * halfChord)\n }\n\n /**\n * Draw a circular arc to a relative end via a bulge factor.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArc(x: number, y: number, bulge: number): this {\n return this.bulgeArcTo(this._resolveRelative(x, y), bulge)\n }\n\n /**\n * Draw a vertical bulge arc.\n * @param distance - vertical distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n vBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(0, distance, bulge)\n }\n\n /**\n * Draw a horizontal bulge arc.\n * @param distance - horizontal distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n hBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(distance, 0, bulge)\n }\n\n /**\n * Draw a circular arc tangent to the previous curve, ending at `end`.\n * @param end - the absolute end point.\n * @returns this pen, for chaining.\n */\n tangentArcTo(end: Point2): this {\n const previous = this._requireLastCurve('tangentArc')\n const arc = makeArc2dTangent(this.pointer[0], this.pointer[1], ...endTangent(previous), end[0], end[1])\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw a tangent arc to a relative offset.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @returns this pen, for chaining.\n */\n tangentArc(x: number, y: number): this {\n return this.tangentArcTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw an elliptical arc (SVG-style endpoint parameters).\n * @param end - the absolute end point.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipseTo(end: Point2, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n const { majorRadius, minorRadius, rotationAngle } = normalizeEllipseRadii(horizontalRadius, verticalRadius, rotation)\n const arc = makeEllipseArcFromSvgParams(this.pointer, end, majorRadius, minorRadius, rotationAngle, longAxis, sweep)\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw an elliptical arc to a relative end point.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipse(x: number, y: number, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n return this.ellipseTo(this._resolveRelative(x, y), horizontalRadius, verticalRadius, rotation, longAxis, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to an absolute end point with a given minor radius.\n * @param end - the absolute end point.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipseTo(end: Point2, minorRadius: number, sweep = false): this {\n const angle = polarAngle2d(end, this.pointer)\n const dist = distance2d(end, this.pointer)\n return this.ellipseTo(end, dist / 2, minorRadius, angle * RAD2DEG, true, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to a relative end point with a given minor radius.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipse(x: number, y: number, minorRadius: number, sweep = false): this {\n return this.halfEllipseTo(this._resolveRelative(x, y), minorRadius, sweep)\n }\n\n /**\n * Draw a Bezier curve to an absolute end through control points.\n * @param end - the absolute end point.\n * @param controlPoints - one control point (quadratic) or two (cubic).\n * @returns this pen, for chaining.\n */\n bezierCurveTo(end: Point2, controlPoints: Point2[]): this {\n const poles: [number, number][] = [[this.pointer[0], this.pointer[1]], ...controlPoints, [end[0], end[1]]]\n return this._saveCurveAndAdvance(makeBezier2d(poles), end)\n }\n\n /**\n * Draw a quadratic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param controlPoint - the single control point.\n * @returns this pen, for chaining.\n */\n quadraticBezierCurveTo(end: Point2, controlPoint: Point2): this {\n return this.bezierCurveTo(end, [controlPoint])\n }\n\n /**\n * Draw a cubic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param startControlPoint - the start control point.\n * @param endControlPoint - the end control point.\n * @returns this pen, for chaining.\n */\n cubicBezierCurveTo(end: Point2, startControlPoint: Point2, endControlPoint: Point2): this {\n return this.bezierCurveTo(end, [startControlPoint, endControlPoint])\n }\n\n /**\n * Draw a smooth cubic spline to an absolute end point.\n * @param _end - the absolute end point.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSplineTo(_end: Point2, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSplineTo is not yet ported')\n }\n\n /**\n * Draw a smooth cubic spline to a relative end point.\n * @param _x - relative x end distance.\n * @param _y - relative y end distance.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSpline(_x: number, _y: number, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSpline is not yet ported')\n }\n\n /**\n * Change the corner between the previous and next segment.\n * @param _radius - the corner radius.\n * @param _mode - the corner kind.\n * @returns this pen, for chaining.\n * @throws D-group corner ops (fillet/chamfer/dogbone) are not yet ported.\n */\n customCorner(_radius: number, _mode: CornerMode = 'fillet'): this {\n throw new Error('[geometry2d/pen] customCorner: D-group corner ops are not yet ported')\n }\n\n /**\n * Close the sketch by drawing a final segment back to the start.\n * @returns the closed, ordered curve list.\n */\n close(): Curve2dObj[] {\n if (!samePoint(this.pointer, this.firstPoint)) {\n this.lineTo(this.firstPoint)\n }\n return [...this.pendingCurves]\n }\n\n /**\n * Close by mirroring the drawn segments across the start→current chord.\n * @returns the closed, mirror-augmented curve list.\n * @throws not yet ported (needs the curve-mirror transform).\n */\n closeWithMirror(): Curve2dObj[] {\n throw new Error('[geometry2d/pen] closeWithMirror is not yet ported')\n }\n\n /**\n * The ordered drawn curve list (no implicit close).\n * @returns the drawn segments in draw order.\n */\n curves(): Curve2dObj[] {\n return [...this.pendingCurves]\n }\n}"]}
1
+ {"version":3,"file":"pen-sketcher.js","sourceRoot":"","sources":["../../src/geometry2d/pen-sketcher.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * geometry2d — 2D `BaseSketcher2d` pen (C1), adapted for the pure-object base.\n *\n * Ported from brepjs `2d/blueprints/baseSketcher2d.ts` (Apache-2.0).\n *\n * The brepjs original accumulates kernel-backed `Curve2D` handles (mutable:\n * `delete`/`reverse`/`tangentAt`). Here those are replaced by the pure\n * `Curve2dObj` base of `geometry2d/curve2d` — each pen method emits a plain\n * object, the pointer advances by plain arithmetic, and end-tangent lookup maps\n * to `tangentCurve2d`. `curves()`/`close()` return the ordered `Curve2dObj[]`,\n * which feeds `Blueprint` and the 2D→3D placement pipeline.\n *\n * Not-yet-ported (honest `throw`s, per the D-group/port plan):\n * · `ellipse*` — needs the SVG ellipse→arc helper;\n * · `smoothSplit*` — needs the spline control helper;\n * · `customCorner`/`closeWithMirror` — needs 2D corner/mirror ops (D-group).\n *\n * @module\n */\n\nimport {\n makeLine2d,\n makeArc2dThreePoints,\n makeArc2dTangent,\n makeBezier2d,\n tangentCurve2d,\n type Curve2dObj,\n} from './curve2d'\nimport { makeEllipseArcFromSvgParams, normalizeEllipseRadii } from './svg-ellipse'\nimport { distance2d, normalize2d, polarAngle2d, polarToCartesian, samePoint } from './point'\n\nconst DEG2RAD = Math.PI / 180\nconst RAD2DEG = 180 / Math.PI\n\n/** A `[x, y]` 2D point (plain tuple). */\nexport type Point2 = [number, number]\n\n/** Options accepted by the spline methods. */\nexport type SplineOptions = {\n /** Explicit start tangent; defaults to `[1,0]` or the previous segment's end tangent. */\n startTangent?: Point2\n /** Explicit end tangent, or the literal `'symmetric'` (mirror of the start tangent). */\n endTangent?: Point2 | 'symmetric'\n /** Start control-length factor. */\n startFactor?: number\n /** End control-length factor. */\n endFactor?: number\n}\n\n/** Corner modes accepted by `customCorner` (D-group, not yet ported). */\nexport type CornerMode = 'fillet' | 'chamfer' | 'dogbone'\n\n/** Guard-style error: throw so callers immediately see pen misuse. */\nfunction bug(caller: string, message: string): never {\n throw new Error(`[geometry2d/pen] ${caller}: ${message}`)\n}\n\n/** Non-normalized tangent at the end of a curve (t=1 within its direct parameter space). */\nfunction endTangent(c: Curve2dObj): [number, number] {\n return tangentCurve2d(c, 1)\n}\n\n/**\n * Base class for 2D flood-pen sketchers that accumulate `Curve2dObj` segments.\n *\n * Provides the shared pen-drawing API (lines, arcs, beziers) used by the\n * drawing DSL. Subclasses implement `close()` to package the accumulated curves\n * as a `Blueprint` or plain curve list.\n */\nexport class BaseSketcher2d {\n /** Current pen position `[x, y]`. */\n pointer: Point2\n /** The starting point of the pen run. */\n firstPoint: Point2\n /** Accumulated segments, in draw order. */\n pendingCurves: Curve2dObj[]\n /** A queued one-shot corner transform (D-group; unused until ported). */\n _nextCorner: ((a: Curve2dObj, b: Curve2dObj) => Curve2dObj[]) | null\n\n constructor(origin: Point2 = [0, 0]) {\n this.pointer = origin\n this.firstPoint = origin\n this.pendingCurves = []\n this._nextCorner = null\n }\n\n /**\n * The most recently drawn curve, or `null`.\n * @returns the last drawn curve, or `null` when nothing has been drawn.\n */\n _lastCurve(): Curve2dObj | null {\n return this.pendingCurves.length ? this.pendingCurves[this.pendingCurves.length - 1]! : null\n }\n\n /**\n * Fetch the last drawn curve, or throw a misuse error.\n * @param caller - the calling method name (for the error message).\n * @returns the last curve.\n */\n _requireLastCurve(caller: string): Curve2dObj {\n const c = this._lastCurve()\n if (!c) bug(caller, 'You need a previous curve to continue')\n return c\n }\n\n /**\n * Add a relative offset to the current pointer.\n * @param xDist - relative x distance.\n * @param yDist - relative y distance.\n * @returns the resulting absolute point.\n */\n _resolveRelative(xDist: number, yDist: number): Point2 {\n return [this.pointer[0] + xDist, this.pointer[1] + yDist]\n }\n\n /**\n * Save a curve and advance the pen to `end`.\n * @param curve - the curve to record.\n * @param end - the new pen position.\n * @returns this pen, for chaining.\n */\n _saveCurveAndAdvance(curve: Curve2dObj, end: Point2): this {\n this.saveCurve(curve)\n this.pointer = end\n return this\n }\n\n /** The current pen position `[x, y]`. */\n get penPosition(): Point2 {\n return this.pointer\n }\n\n /** The current pen angle in degrees (direction of the last segment's end tangent). */\n get penAngle(): number {\n const last = this._lastCurve()\n if (!last) return 0\n const [dx, dy] = endTangent(last)\n return Math.atan2(dy, dx) * RAD2DEG\n }\n\n /**\n * Move the pen to an absolute position before any segment is drawn.\n * @param point - the absolute start position.\n * @returns this pen, for chaining.\n */\n movePointerTo(point: Point2): this {\n if (this.pendingCurves.length) bug('movePointerTo', 'You can only move the pointer if there is no curve defined')\n this.pointer = point\n this.firstPoint = point\n return this\n }\n\n /**\n * Record a segment, applying a queued corner transform if present.\n * @param curve - the curve to record.\n */\n saveCurve(curve: Curve2dObj): void {\n if (!this._nextCorner) {\n this.pendingCurves.push(curve)\n return\n }\n const previous = this.pendingCurves.pop()\n if (!previous) bug('saveCurve', 'No previous curve available for custom corner')\n const cornered = this._nextCorner!(previous, curve)\n this.pendingCurves.push(...cornered)\n this._nextCorner = null\n }\n\n /**\n * Draw a straight line to an absolute point.\n * @param point - the absolute end point.\n * @returns this pen, for chaining.\n */\n lineTo(point: Point2): this {\n return this._saveCurveAndAdvance(makeLine2d(this.pointer[0], this.pointer[1], point[0], point[1]), point)\n }\n\n /**\n * Draw a straight line by relative horizontal and vertical distances.\n * @param x - relative x distance.\n * @param y - relative y distance.\n * @returns this pen, for chaining.\n */\n line(x: number, y: number): this {\n return this.lineTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw a vertical line of the given signed distance.\n * @param distance - signed vertical distance.\n * @returns this pen, for chaining.\n */\n vLine(distance: number): this {\n return this.line(0, distance)\n }\n\n /**\n * Draw a horizontal line of the given signed distance.\n * @param distance - signed horizontal distance.\n * @returns this pen, for chaining.\n */\n hLine(distance: number): this {\n return this.line(distance, 0)\n }\n\n /**\n * Draw a vertical line to an absolute Y coordinate.\n * @param yPos - the absolute y.\n * @returns this pen, for chaining.\n */\n vLineTo(yPos: number): this {\n return this.lineTo([this.pointer[0], yPos])\n }\n\n /**\n * Draw a horizontal line to an absolute X coordinate.\n * @param xPos - the absolute x.\n * @returns this pen, for chaining.\n */\n hLineTo(xPos: number): this {\n return this.lineTo([xPos, this.pointer[1]])\n }\n\n /**\n * Draw a whole contour from an explicit point list, in one call.\n *\n * The batched counterpart of a chained `lineTo` run, and the only form that\n * survives the `.fai.js` dialect: the parser caps AST nesting at 100\n * (`SEC_LIMIT`), and a chained call builds a nested\n * `MemberExpression`/`CallExpression` tree whose depth equals the segment count\n * — a contour of a few hundred tessellated points cannot be emitted as\n * `pen.lineTo(a).lineTo(b)…` (measured: a 150-call chain already trips the\n * limit). Handing the points over as ONE array literal keeps the emitted depth\n * constant (array nesting = 2) at any point count.\n *\n * The first point also (re)seats an empty pen, so `firstPoint` keeps its\n * meaning for {@link close} / `movePointerTo`. GOTCHA (2026-09-28):\n * `movePointerTo` refuses to lift the pointer once a curve exists, so ONE pen\n * carries exactly ONE contour — a shape holding many disjoint loops (a rebuilt\n * Draft drawing was measured carrying 12 / 36 / 56 / 61 of them) needs one pen\n * per loop, never one pen with several lifts.\n *\n * @param points - the contour's points in draw order (at least 2).\n * @param close - append a final segment back to `points[0]` (skipped when the\n * run already ended there, mirroring {@link close}).\n * @returns this pen, for chaining.\n */\n polyline(points: Point2[], close = false): this {\n if (points.length < 2) bug('polyline', 'a polyline needs at least two points')\n const start = points[0]!\n if (this.pendingCurves.length === 0) {\n this.pointer = [start[0], start[1]]\n this.firstPoint = this.pointer\n } else if (!samePoint(this.pointer, start)) {\n bug(\n 'polyline',\n 'a run is already in flight — the pen must be sitting on the polyline start (use one pen per contour)',\n )\n }\n for (let i = 1; i < points.length; i++) {\n const p = points[i]!\n this.lineTo([p[0], p[1]])\n }\n if (close && !samePoint(this.pointer, start)) this.lineTo([start[0], start[1]])\n return this\n }\n\n /**\n * Draw a line to an absolute point in polar form.\n * @param polar - `[radius, angleDeg]`.\n * @returns this pen, for chaining.\n */\n polarLineTo(polar: Point2): this {\n const [x, y] = polarToCartesian(polar[0], polar[1] * DEG2RAD)\n return this.lineTo([x, y])\n }\n\n /**\n * Draw a line in polar relative form.\n * @param distance - radial distance.\n * @param angle - angle in degrees.\n * @returns this pen, for chaining.\n */\n polarLine(distance: number, angle: number): this {\n const [x, y] = polarToCartesian(distance, angle * DEG2RAD)\n return this.line(x, y)\n }\n\n /**\n * Draw a line tangent to the previous curve.\n * @param distance - distance along the tangent.\n * @returns this pen, for chaining.\n */\n tangentLine(distance: number): this {\n const previous = this._requireLastCurve('tangentLine')\n const [dx, dy] = normalize2d(endTangent(previous))\n return this.line(dx * distance, dy * distance)\n }\n\n /**\n * Draw a circular arc through a mid-point to an absolute end point.\n * @param end - the absolute end point.\n * @param midPoint - a point on the arc.\n * @returns this pen, for chaining.\n */\n threePointsArcTo(end: Point2, midPoint: Point2): this {\n const curve = makeArc2dThreePoints(this.pointer[0], this.pointer[1], midPoint[0], midPoint[1], end[0], end[1])\n return this._saveCurveAndAdvance(curve, end)\n }\n\n /**\n * Draw a circular arc through a via-point to an end point, both relative.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param viaX - relative via x distance.\n * @param viaY - relative via y distance.\n * @returns this pen, for chaining.\n */\n threePointsArc(x: number, y: number, viaX: number, viaY: number): this {\n const [ax, ay] = this.pointer\n return this.threePointsArcTo([ax + x, ay + y], [ax + viaX, ay + viaY])\n }\n\n /**\n * Draw a circular arc to an absolute end, bulging `sagitta` off the chord.\n * @param end - the absolute end point.\n * @param sagitta - the sagitta (signed bulge off the chord).\n * @returns this pen, for chaining.\n */\n sagittaArcTo(end: Point2, sagitta: number): this {\n const [x0, y0] = this.pointer\n const [x1, y1] = end\n const midX = (x0 + x1) / 2\n const midY = (y0 + y1) / 2\n const sX = -(y1 - y0)\n const sY = x1 - x0\n const sLen = Math.hypot(sX, sY)\n if (sLen < 1e-12) bug('sagittaArcTo', 'Start and end points cannot be identical')\n const sag: Point2 = [midX + (sX / sLen) * sagitta, midY + (sY / sLen) * sagitta]\n return this.threePointsArcTo(end, sag)\n }\n\n /**\n * Draw a circular arc to a relative end, bulging `sagitta`.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n sagittaArc(x: number, y: number, sagitta: number): this {\n return this.sagittaArcTo(this._resolveRelative(x, y), sagitta)\n }\n\n /**\n * Draw a vertical sagitta arc of `distance` and `sagitta`.\n * @param distance - vertical distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n vSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(0, distance, sagitta)\n }\n\n /**\n * Draw a horizontal sagitta arc of `distance` and `sagitta`.\n * @param distance - horizontal distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n hSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(distance, 0, sagitta)\n }\n\n /**\n * Draw a circular arc to an absolute end via a bulge factor.\n * @param end - the absolute end point.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArcTo(end: Point2, bulge: number): this {\n if (!bulge) return this.lineTo(end)\n const halfChord = distance2d(this.pointer, end) / 2\n return this.sagittaArcTo(end, -bulge * halfChord)\n }\n\n /**\n * Draw a circular arc to a relative end via a bulge factor.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArc(x: number, y: number, bulge: number): this {\n return this.bulgeArcTo(this._resolveRelative(x, y), bulge)\n }\n\n /**\n * Draw a vertical bulge arc.\n * @param distance - vertical distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n vBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(0, distance, bulge)\n }\n\n /**\n * Draw a horizontal bulge arc.\n * @param distance - horizontal distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n hBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(distance, 0, bulge)\n }\n\n /**\n * Draw a circular arc tangent to the previous curve, ending at `end`.\n * @param end - the absolute end point.\n * @returns this pen, for chaining.\n */\n tangentArcTo(end: Point2): this {\n const previous = this._requireLastCurve('tangentArc')\n const arc = makeArc2dTangent(this.pointer[0], this.pointer[1], ...endTangent(previous), end[0], end[1])\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw a tangent arc to a relative offset.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @returns this pen, for chaining.\n */\n tangentArc(x: number, y: number): this {\n return this.tangentArcTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw an elliptical arc (SVG-style endpoint parameters).\n * @param end - the absolute end point.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipseTo(end: Point2, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n const { majorRadius, minorRadius, rotationAngle } = normalizeEllipseRadii(horizontalRadius, verticalRadius, rotation)\n const arc = makeEllipseArcFromSvgParams(this.pointer, end, majorRadius, minorRadius, rotationAngle, longAxis, sweep)\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw an elliptical arc to a relative end point.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipse(x: number, y: number, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n return this.ellipseTo(this._resolveRelative(x, y), horizontalRadius, verticalRadius, rotation, longAxis, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to an absolute end point with a given minor radius.\n * @param end - the absolute end point.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipseTo(end: Point2, minorRadius: number, sweep = false): this {\n const angle = polarAngle2d(end, this.pointer)\n const dist = distance2d(end, this.pointer)\n return this.ellipseTo(end, dist / 2, minorRadius, angle * RAD2DEG, true, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to a relative end point with a given minor radius.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipse(x: number, y: number, minorRadius: number, sweep = false): this {\n return this.halfEllipseTo(this._resolveRelative(x, y), minorRadius, sweep)\n }\n\n /**\n * Draw a Bezier curve to an absolute end through control points.\n * @param end - the absolute end point.\n * @param controlPoints - one control point (quadratic) or two (cubic).\n * @returns this pen, for chaining.\n */\n bezierCurveTo(end: Point2, controlPoints: Point2[]): this {\n const poles: [number, number][] = [[this.pointer[0], this.pointer[1]], ...controlPoints, [end[0], end[1]]]\n return this._saveCurveAndAdvance(makeBezier2d(poles), end)\n }\n\n /**\n * Draw a quadratic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param controlPoint - the single control point.\n * @returns this pen, for chaining.\n */\n quadraticBezierCurveTo(end: Point2, controlPoint: Point2): this {\n return this.bezierCurveTo(end, [controlPoint])\n }\n\n /**\n * Draw a cubic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param startControlPoint - the start control point.\n * @param endControlPoint - the end control point.\n * @returns this pen, for chaining.\n */\n cubicBezierCurveTo(end: Point2, startControlPoint: Point2, endControlPoint: Point2): this {\n return this.bezierCurveTo(end, [startControlPoint, endControlPoint])\n }\n\n /**\n * Draw a smooth cubic spline to an absolute end point.\n * @param _end - the absolute end point.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSplineTo(_end: Point2, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSplineTo is not yet ported')\n }\n\n /**\n * Draw a smooth cubic spline to a relative end point.\n * @param _x - relative x end distance.\n * @param _y - relative y end distance.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSpline(_x: number, _y: number, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSpline is not yet ported')\n }\n\n /**\n * Change the corner between the previous and next segment.\n * @param _radius - the corner radius.\n * @param _mode - the corner kind.\n * @returns this pen, for chaining.\n * @throws D-group corner ops (fillet/chamfer/dogbone) are not yet ported.\n */\n customCorner(_radius: number, _mode: CornerMode = 'fillet'): this {\n throw new Error('[geometry2d/pen] customCorner: D-group corner ops are not yet ported')\n }\n\n /**\n * Close the sketch by drawing a final segment back to the start.\n * @returns the closed, ordered curve list.\n */\n close(): Curve2dObj[] {\n if (!samePoint(this.pointer, this.firstPoint)) {\n this.lineTo(this.firstPoint)\n }\n return [...this.pendingCurves]\n }\n\n /**\n * Close by mirroring the drawn segments across the start→current chord.\n * @returns the closed, mirror-augmented curve list.\n * @throws not yet ported (needs the curve-mirror transform).\n */\n closeWithMirror(): Curve2dObj[] {\n throw new Error('[geometry2d/pen] closeWithMirror is not yet ported')\n }\n\n /**\n * The ordered drawn curve list (no implicit close).\n * @returns the drawn segments in draw order.\n */\n curves(): Curve2dObj[] {\n return [...this.pendingCurves]\n }\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
- namespaces?: string[];
57
- }): CodeToArgsResult;
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;AAqDzC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,gBAAgB,CA0B/F"}
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
- if (NON_DECL.has(id) || declared.has(id) || namespaces?.has(id))
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
- const meta = extractMetadata(code, { namespaces: opts?.namespaces ?? [], looseLocalCalls: true });
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"]}
@@ -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;AAKzC;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxC;AAmDD;;;;;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;AAOD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAoDjE"}
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"}
@@ -20,6 +20,7 @@
20
20
  * - 对象字面量 → `{key:value}`(冒号,合法 JS)
21
21
  */
22
22
  import { isHostVarRef, isHostParamRef, isHostCallRef, isHostExprRef, isHostRef } from './host-arg.js';
23
+ import { unitFor, fromBase } from '../units.js';
23
24
  // ── 数值格式化 ──
24
25
  /**
25
26
  * Format a number as text: integers emit as-is; decimals retain at most 6
@@ -57,6 +58,45 @@ function escapeStr(s) {
57
58
  }
58
59
  return out;
59
60
  }
61
+ /**
62
+ * Format a unit literal number using JS shortest-round-trip representation.
63
+ *
64
+ * P7/D10.3 rule 5: unit literal numbers MUST use `String(n)` (e.g.
65
+ * `0.39370078740157477`), NEVER `fmtNum` (which truncates to 6 decimal
66
+ * places and would silently zero out `1e-7`).
67
+ * @param n - the number to format.
68
+ * @returns the shortest JS round-trip text representation.
69
+ */
70
+ export function fmtUnitNum(n) {
71
+ return String(n);
72
+ }
73
+ /**
74
+ * Reverse lookup: find the script-side unit constant name for a given
75
+ * `UnitName`. Returns the UPPERCASE constant name (e.g. `INCH` for `'inch'`).
76
+ */
77
+ const NAME_TO_CONST = {
78
+ mm: 'MM', cm: 'CM', m: 'METER', micron: 'MICRON',
79
+ inch: 'INCH', foot: 'FOOT', yard: 'YARD',
80
+ degree: 'DEGREE', radian: 'RADIAN',
81
+ gram: 'GRAM', kilogram: 'KILOGRAM',
82
+ second: 'SECOND',
83
+ };
84
+ /**
85
+ * Format a base-unit value as a unit literal expression (`n * UNIT`).
86
+ *
87
+ * P7/D10.3: `base` is the base-unit (mm/degree) value; `dim` determines which
88
+ * system display unit to use; `unitName` is the target display unit.
89
+ * The number is formatted with `fmtUnitNum` (not `fmtNum`).
90
+ * @param base - the base-unit numeric value.
91
+ * @param dim - the dimension of the value.
92
+ * @param unitName - the display unit to express the value in.
93
+ * @returns text like `10 * INCH` or `0.39370078740157477 * INCH`.
94
+ */
95
+ export function formatUnitLiteral(base, dim, unitName) {
96
+ const displayValue = fromBase(base, unitName, dim);
97
+ const constName = NAME_TO_CONST[unitName];
98
+ return `${fmtUnitNum(displayValue)} * ${constName}`;
99
+ }
60
100
  /** 参数值 → 文本(递归,HostArg 面) */
61
101
  function fmtValue(value) {
62
102
  if (value === null)
@@ -77,7 +117,7 @@ function fmtValue(value) {
77
117
  return `${namespace ?? 'cad'}.${callee}(${inner})`;
78
118
  }
79
119
  if (isHostExprRef(value))
80
- return `(${value.text})`;
120
+ return value.bare ? value.text : `(${value.text})`;
81
121
  if (Array.isArray(value))
82
122
  return `[${value.map(fmtValue).join(',')}]`;
83
123
  if (typeof value === 'object') {
@@ -91,13 +131,34 @@ function isPlainObjArg(arg) {
91
131
  return arg !== null && typeof arg === 'object' && !Array.isArray(arg) && !isHostRef(arg);
92
132
  }
93
133
  /**
94
- * 从纯数据(非 IR 类型)打印一行 faijs 源代码。
134
+ * Recursively format a HostArg value, applying unit wrapping to numbers inside
135
+ * arrays (vec3) and plain objects when a dimension is declared.
136
+ */
137
+ function fmtValueWithDim(value, dim, opts) {
138
+ if (opts && dim) {
139
+ // Number → unit literal
140
+ if (typeof value === 'number') {
141
+ const unitName = unitFor(dim, opts.units);
142
+ return formatUnitLiteral(value, dim, unitName);
143
+ }
144
+ // Array (vec3) → element-wise
145
+ if (Array.isArray(value)) {
146
+ return `[${value.map((el) => fmtValueWithDim(el, dim, opts)).join(',')}]`;
147
+ }
148
+ // Bare expr-ref already containing a unit literal → keep as-is
149
+ if (isHostExprRef(value) && value.bare)
150
+ return value.text;
151
+ }
152
+ return fmtValue(value);
153
+ }
154
+ /**
155
+ * Original `formatCodeLine` body without unit support (P7 fast path).
95
156
  *
96
- * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
97
- * @param input - the pure-data line description.
98
- * @returns the printed single-line code text.
157
+ * This is the byte-identical pre-P7 implementation, called when `opts` is
158
+ * absent or has no `dims` field. Kept as a separate function so the
159
+ * unit-aware path can be tested independently.
99
160
  */
100
- export function formatCodeLine(input) {
161
+ function formatCodeLineRaw(input) {
101
162
  const positional = input.positional;
102
163
  const argsInput = input.args ?? {};
103
164
  // 位置实参按序打印
@@ -145,4 +206,72 @@ export function formatCodeLine(input) {
145
206
  return `${out} = ${nsExpr}(${callArgs})`;
146
207
  return `let ${out} = ${nsExpr}(${callArgs})`;
147
208
  }
209
+ /**
210
+ * 从纯数据(非 IR 类型)打印一行 faijs 源代码。
211
+ *
212
+ * 宿主 buildCode / 编辑重排行(editStatement → replaceCodeAt)统一走此入口。
213
+ *
214
+ * P7/D10: when `opts` is provided, dimensioned parameters are serialized as
215
+ * unit literals (`n * UNIT`). When `opts` is absent, output is byte-identical
216
+ * to the pre-P7 behavior (zero-impact regression guarantee).
217
+ *
218
+ * @param input - the pure-data line description.
219
+ * @param opts - optional unit serialization options (P7/D10).
220
+ * @returns the printed single-line code text.
221
+ */
222
+ export function formatCodeLine(input, opts) {
223
+ // Fast path: no unit options → original behavior (byte-identical)
224
+ if (!opts || !opts.dims) {
225
+ return formatCodeLineRaw(input);
226
+ }
227
+ const positional = input.positional;
228
+ const argsInput = input.args ?? {};
229
+ const posDims = opts.dims.positional ?? [];
230
+ const keyDims = opts.dims.byKey ?? {};
231
+ // Positional args with per-index dimension
232
+ const positionalParts = positional.map((arg, i) => {
233
+ const dim = posDims[i] ?? null;
234
+ if (isPlainObjArg(arg)) {
235
+ const entries = Object.entries(arg);
236
+ return `{ ${entries.map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`).join(', ')} }`;
237
+ }
238
+ return fmtValueWithDim(arg, dim, opts);
239
+ });
240
+ // args slot (transitional compat: appended as trailing option when last positional is not a plain object)
241
+ const argsParts = Object.entries(argsInput).map(([k, v]) => `${k}:${fmtValueWithDim(v, keyDims[k] ?? null, opts)}`);
242
+ const lastIsPlainObject = positional.length > 0 && isPlainObjArg(positional[positional.length - 1]);
243
+ let callArgs;
244
+ if (positionalParts.length > 0) {
245
+ callArgs = positionalParts.join(', ');
246
+ if (!lastIsPlainObject && argsParts.length > 0) {
247
+ callArgs = [...positionalParts, `{ ${argsParts.join(', ')} }`].join(', ');
248
+ }
249
+ }
250
+ else if (input.receiver) {
251
+ callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '';
252
+ }
253
+ else {
254
+ callArgs = argsParts.length > 0 ? `{ ${argsParts.join(', ')} }` : '{}';
255
+ }
256
+ // F2:命名空间前缀(缺省 cad);本机函数调用 callee 无命名空间前缀
257
+ const nsExpr = input.namespace === undefined ? `cad.${input.callee}` : `${input.namespace}.${input.callee}`;
258
+ // 1) 解构:outputKeys + outputs 一一对应
259
+ if (input.outputKeys && input.outputKeys.length > 0) {
260
+ const destructure = input.outputKeys.map((k, i) => `${k}: ${input.outputs[i]}`).join(', ');
261
+ return `const { ${destructure} } = ${nsExpr}(${callArgs})`;
262
+ }
263
+ // 2) 成员调用
264
+ if (input.receiver) {
265
+ return `${input.receiver}.${input.callee}(${callArgs})`;
266
+ }
267
+ // 3) 无赋值调用
268
+ if (input.outputs.length === 0) {
269
+ return `${nsExpr}(${callArgs})`;
270
+ }
271
+ // 4) 赋值:outputDeclared → 裸重赋值;否则 let 声明
272
+ const out = input.outputs[0];
273
+ if (input.outputDeclared)
274
+ return `${out} = ${nsExpr}(${callArgs})`;
275
+ return `let ${out} = ${nsExpr}(${callArgs})`;
276
+ }
148
277
  //# sourceMappingURL=codegen.js.map