diff --git a/packages/drawtonomy-sdk/__tests__/nodeEsmResolution.test.ts b/packages/drawtonomy-sdk/__tests__/nodeEsmResolution.test.ts new file mode 100644 index 0000000..01faaa9 --- /dev/null +++ b/packages/drawtonomy-sdk/__tests__/nodeEsmResolution.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest' +import { execFileSync } from 'node:child_process' +import { existsSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, resolve } from 'node:path' + +/** + * Guards that the published build is importable by plain Node.js, not only by bundlers. + * + * The build previously emitted extensionless relative imports (`from './types'`), which + * bundlers resolve but Node's ESM loader rejects with ERR_MODULE_NOT_FOUND. Since the + * package ships `"type": "module"` and is documented for headless tooling, that made + * every `node script.mjs` usage fail while the bundled test suite stayed green. + * + * This test spawns a real Node process against `dist/`, so it fails if the emitted + * specifiers regress — something an in-process (Vite-transformed) test cannot catch. + */ +describe('published build resolves under plain Node ESM', () => { + const distEntry = resolve(dirname(fileURLToPath(import.meta.url)), '../dist/index.js') + + it.skipIf(!existsSync(distEntry))('imports and runs a full generate + export cycle', () => { + const script = ` + import * as sdk from ${JSON.stringify(distEntry)} + const lane = sdk.createLaneWithBoundaries( + [{ x: 0, y: 0 }, { x: 500, y: 0 }], + [{ x: 0, y: 50 }, { x: 500, y: 50 }], + ) + const snapshot = sdk.createSnapshot([...lane, sdk.createVehicle({ x: 100, y: 25 })]) + const xodr = sdk.exporter.exportToOpenDrive(snapshot, {}) + const reparsed = sdk.exporter.odrToShapes(sdk.exporter.parseOpenDriveXml(xodr)) + console.log(JSON.stringify({ + exports: Object.keys(sdk).length, + roads: (xodr.match(/ void diff --git a/packages/drawtonomy-sdk/src/exporter/index.ts b/packages/drawtonomy-sdk/src/exporter/index.ts index 43fd575..2ccf90b 100644 --- a/packages/drawtonomy-sdk/src/exporter/index.ts +++ b/packages/drawtonomy-sdk/src/exporter/index.ts @@ -7,37 +7,37 @@ // turns OSM XML back into editor-ready primitives (points / linestrings / // lanes), enabling round-trip workflows. -export { exportToOpenDrive, type OpenDriveExportOptions } from './opendrive' +export { exportToOpenDrive, type OpenDriveExportOptions } from './opendrive.js' export { latLonToTmercProj, latLonToUtmProj, originToProjString, FALLBACK_GEO_REFERENCE, type GeoOrigin, -} from './projection' +} from './projection.js' export { exportToOpenScenario, templateIdToVehicleCategory, type OpenScenarioExportOptions, type TemplateResolver, -} from './openscenario' +} from './openscenario.js' export { buildPathTrajectory, DEFAULT_PATH_SPEED_MPS, type PathSamplePoint, type PathTrajectoryInput, -} from './trajectory' +} from './trajectory.js' export { computeCenterlineWithWidth, sampleAtParam, computeHeadings, type Point2D, type CenterlineSample, -} from './laneCenterline' -export { buildEsminiZip, type EsminiPackageOptions, type EsminiPackageResult } from './packageEsmini' -export { buildZip, type ZipEntry } from './zip' -export { sanitizeFileBaseName } from './sanitize' -export { PIXELS_PER_METER } from './units' +} from './laneCenterline.js' +export { buildEsminiZip, type EsminiPackageOptions, type EsminiPackageResult } from './packageEsmini.js' +export { buildZip, type ZipEntry } from './zip.js' +export { sanitizeFileBaseName } from './sanitize.js' +export { PIXELS_PER_METER } from './units.js' export { exportToLanelet2, trafficSignCode, @@ -47,7 +47,7 @@ export { type Lanelet2ExportOptions, type OsmSidecar, type MapOrigin, -} from './lanelet2' +} from './lanelet2.js' export { parseOsmXml, latLonToCanvas, @@ -56,7 +56,7 @@ export { type OsmNode, type OsmWay, type OsmRelation, -} from './osmParser' +} from './osmParser.js' export { osmToShapes, alignBoundaries, @@ -71,7 +71,7 @@ export { type ImportBounds, type OsmToShapesOptions, type ShapeIdAllocator, -} from './osmToShapes' +} from './osmToShapes.js' export { parseOpenDriveXml, type OdrMap, @@ -93,7 +93,7 @@ export { type OdrJunctionLaneLink, type OdrCubic, type OdrElevation, -} from './opendriveParser' +} from './opendriveParser.js' export { evalElevation, evalGeometry, @@ -103,14 +103,14 @@ export { type GeomPose, type ReferenceSample, type SampleReferenceLineOptions, -} from './odrGeometry' +} from './odrGeometry.js' export { evalElevationRecords, fitElevationProfile, type ElevationRecord, type ElevationSample, type FitElevationOptions, -} from './odrElevationFit' +} from './odrElevationFit.js' export { odrToShapes, parseGeoReferenceOrigin, @@ -118,4 +118,4 @@ export { type OdrRoadRecord, type OdrSidecar, type OdrToShapesOptions, -} from './odrToShapes' +} from './odrToShapes.js' diff --git a/packages/drawtonomy-sdk/src/exporter/lanelet2.ts b/packages/drawtonomy-sdk/src/exporter/lanelet2.ts index 6aa4e5f..eb97dd1 100644 --- a/packages/drawtonomy-sdk/src/exporter/lanelet2.ts +++ b/packages/drawtonomy-sdk/src/exporter/lanelet2.ts @@ -42,8 +42,8 @@ import type { PointProps, TrafficLightProps, TrafficSignProps, -} from '../types' -import { canvasToLatLon, parseOsmXml, type OsmData } from './osmParser' +} from '../types.js' +import { canvasToLatLon, parseOsmXml, type OsmData } from './osmParser.js' type LaneShape = BaseShape<'lane', LaneProps> type LinestringShape = BaseShape<'linestring', LinestringProps> diff --git a/packages/drawtonomy-sdk/src/exporter/odrCarryThrough.ts b/packages/drawtonomy-sdk/src/exporter/odrCarryThrough.ts index 899a46e..436140f 100644 --- a/packages/drawtonomy-sdk/src/exporter/odrCarryThrough.ts +++ b/packages/drawtonomy-sdk/src/exporter/odrCarryThrough.ts @@ -24,7 +24,7 @@ // collision-free, and rewrite only the link elementIds that must point at // regenerated roads — leaving every other byte untouched. -import type { Point2D } from './laneCenterline' +import type { Point2D } from './laneCenterline.js' /** Per-road record captured at import time (stored in the sidecar). */ export interface OdrRoadRecord { diff --git a/packages/drawtonomy-sdk/src/exporter/odrGeometry.ts b/packages/drawtonomy-sdk/src/exporter/odrGeometry.ts index 8a699dc..74e5441 100644 --- a/packages/drawtonomy-sdk/src/exporter/odrGeometry.ts +++ b/packages/drawtonomy-sdk/src/exporter/odrGeometry.ts @@ -8,7 +8,7 @@ // // No external dependencies. -import type { OdrCubic, OdrGeometry, OdrRoad } from './opendriveParser' +import type { OdrCubic, OdrGeometry, OdrRoad } from './opendriveParser.js' /** Pose on the reference line: inertial position + heading. */ export interface GeomPose { diff --git a/packages/drawtonomy-sdk/src/exporter/odrGeometryFit.ts b/packages/drawtonomy-sdk/src/exporter/odrGeometryFit.ts index 2625c6e..7c643a2 100644 --- a/packages/drawtonomy-sdk/src/exporter/odrGeometryFit.ts +++ b/packages/drawtonomy-sdk/src/exporter/odrGeometryFit.ts @@ -26,8 +26,8 @@ // // No external dependencies. -import type { OdrGeometry } from './opendriveParser' -import { evalGeometry, type GeomPose } from './odrGeometry' +import type { OdrGeometry } from './opendriveParser.js' +import { evalGeometry, type GeomPose } from './odrGeometry.js' export interface FitPoint { x: number diff --git a/packages/drawtonomy-sdk/src/exporter/odrToShapes.ts b/packages/drawtonomy-sdk/src/exporter/odrToShapes.ts index 1931b77..f2abf60 100644 --- a/packages/drawtonomy-sdk/src/exporter/odrToShapes.ts +++ b/packages/drawtonomy-sdk/src/exporter/odrToShapes.ts @@ -36,9 +36,9 @@ import type { OdrRoad, OdrRoadMark, OdrSignalValidity, -} from './opendriveParser' -import { evalPoly3, sampleReferenceLine, type ReferenceSample } from './odrGeometry' -import { sampleAtParam, type Point2D } from './laneCenterline' +} from './opendriveParser.js' +import { evalPoly3, sampleReferenceLine, type ReferenceSample } from './odrGeometry.js' +import { sampleAtParam, type Point2D } from './laneCenterline.js' import { createShapeIdAllocator, type ImportBounds, @@ -51,16 +51,16 @@ import { type ImportedTrafficLight, type ImportedTrafficSign, type ShapeIdAllocator, -} from './osmToShapes' -import { PIXELS_PER_METER } from './units' +} from './osmToShapes.js' +import { PIXELS_PER_METER } from './units.js' import { hashRoadState, type CarryLaneState, type CarryRegulatoryState, type OdrRoadRecord, -} from './odrCarryThrough' +} from './odrCarryThrough.js' -export type { OdrRoadRecord } from './odrCarryThrough' +export type { OdrRoadRecord } from './odrCarryThrough.js' /** Sidecar captured at OpenDRIVE import time (for verbatim round-trip export). */ export interface OdrSidecar { diff --git a/packages/drawtonomy-sdk/src/exporter/opendrive.ts b/packages/drawtonomy-sdk/src/exporter/opendrive.ts index 26f887d..1f8f273 100644 --- a/packages/drawtonomy-sdk/src/exporter/opendrive.ts +++ b/packages/drawtonomy-sdk/src/exporter/opendrive.ts @@ -32,14 +32,14 @@ import type { PolygonProps, TrafficLightProps, TrafficSignProps, -} from '../types' -import { sampleAtParam, type Point2D } from './laneCenterline' -import { evalGeometry } from './odrGeometry' -import { fitPlanView, type FittedSamplePose } from './odrGeometryFit' -import { fitElevationProfile, type ElevationSample } from './odrElevationFit' -import type { OdrGeometry } from './opendriveParser' -import { originToProjString } from './projection' -import { escapeXml, fmt, fmtPrecise, pxToEnuX, pxToEnuY, pxToMeter } from './units' +} from '../types.js' +import { sampleAtParam, type Point2D } from './laneCenterline.js' +import { evalGeometry } from './odrGeometry.js' +import { fitPlanView, type FittedSamplePose } from './odrGeometryFit.js' +import { fitElevationProfile, type ElevationSample } from './odrElevationFit.js' +import type { OdrGeometry } from './opendriveParser.js' +import { originToProjString } from './projection.js' +import { escapeXml, fmt, fmtPrecise, pxToEnuX, pxToEnuY, pxToMeter } from './units.js' import { appendControlRecords, dropControlRecords, @@ -51,9 +51,9 @@ import { type OdrDocRoad, type OdrDocument, type OdrRoadRecord, -} from './odrCarryThrough' -import type { OdrSidecar } from './odrToShapes' -import { trafficSignCode } from './lanelet2' +} from './odrCarryThrough.js' +import type { OdrSidecar } from './odrToShapes.js' +import { trafficSignCode } from './lanelet2.js' type LaneShape = BaseShape<'lane', LaneProps> type LinestringShape = BaseShape<'linestring', LinestringProps> diff --git a/packages/drawtonomy-sdk/src/exporter/openscenario.ts b/packages/drawtonomy-sdk/src/exporter/openscenario.ts index a519895..0e80184 100644 --- a/packages/drawtonomy-sdk/src/exporter/openscenario.ts +++ b/packages/drawtonomy-sdk/src/exporter/openscenario.ts @@ -14,9 +14,9 @@ import type { LinestringProps, PointProps, VehicleProps, -} from '../types' -import { buildPathTrajectory, type PathSamplePoint } from './trajectory' -import { escapeXml, fmt, pxToEnuX, pxToEnuY, pxToMeter } from './units' +} from '../types.js' +import { buildPathTrajectory, type PathSamplePoint } from './trajectory.js' +import { escapeXml, fmt, pxToEnuX, pxToEnuY, pxToMeter } from './units.js' type VehicleShape = BaseShape<'vehicle', VehicleProps> type LinestringShape = BaseShape<'linestring', LinestringProps> diff --git a/packages/drawtonomy-sdk/src/exporter/osmToShapes.ts b/packages/drawtonomy-sdk/src/exporter/osmToShapes.ts index 5370b5b..c3c47f8 100644 --- a/packages/drawtonomy-sdk/src/exporter/osmToShapes.ts +++ b/packages/drawtonomy-sdk/src/exporter/osmToShapes.ts @@ -9,8 +9,8 @@ // alignment, progress reporting, etc.). Callers can wrap the result into // shapes themselves. -import type { ShapeId } from '../types' -import { latLonToCanvas, type OsmData } from './osmParser' +import type { ShapeId } from '../types.js' +import { latLonToCanvas, type OsmData } from './osmParser.js' /** * ID allocator interface. The default implementation produces predictable diff --git a/packages/drawtonomy-sdk/src/exporter/packageEsmini.ts b/packages/drawtonomy-sdk/src/exporter/packageEsmini.ts index 88c923a..43c6629 100644 --- a/packages/drawtonomy-sdk/src/exporter/packageEsmini.ts +++ b/packages/drawtonomy-sdk/src/exporter/packageEsmini.ts @@ -3,11 +3,11 @@ // `/.xosc`. The xosc reference uses the same // baseName so the bundle works without renames. -import type { DrawtonomySnapshot } from '../types' -import { exportToOpenDrive } from './opendrive' -import { exportToOpenScenario, type TemplateResolver } from './openscenario' -import { sanitizeFileBaseName } from './sanitize' -import { buildZip } from './zip' +import type { DrawtonomySnapshot } from '../types.js' +import { exportToOpenDrive } from './opendrive.js' +import { exportToOpenScenario, type TemplateResolver } from './openscenario.js' +import { sanitizeFileBaseName } from './sanitize.js' +import { buildZip } from './zip.js' export interface EsminiPackageOptions { /** diff --git a/packages/drawtonomy-sdk/src/exporter/trajectory.ts b/packages/drawtonomy-sdk/src/exporter/trajectory.ts index 168f377..147a236 100644 --- a/packages/drawtonomy-sdk/src/exporter/trajectory.ts +++ b/packages/drawtonomy-sdk/src/exporter/trajectory.ts @@ -23,7 +23,7 @@ // // Default speed: 10 m/s (≈ 36 km/h, residential). -import { PIXELS_PER_METER } from './units' +import { PIXELS_PER_METER } from './units.js' export interface PathSamplePoint { /** ENU x (m) */ diff --git a/packages/drawtonomy-sdk/src/helpers.ts b/packages/drawtonomy-sdk/src/helpers.ts index a45467c..285a68d 100644 --- a/packages/drawtonomy-sdk/src/helpers.ts +++ b/packages/drawtonomy-sdk/src/helpers.ts @@ -10,8 +10,8 @@ import type { EllipseProps, TextProps, DrawtonomySnapshot, -} from './types' -import { evaluatePathAt, uniformTValues } from './geometry' +} from './types.js' +import { evaluatePathAt, uniformTValues } from './geometry.js' let idCounter = 0 diff --git a/packages/drawtonomy-sdk/src/index.ts b/packages/drawtonomy-sdk/src/index.ts index 4282f70..425613f 100644 --- a/packages/drawtonomy-sdk/src/index.ts +++ b/packages/drawtonomy-sdk/src/index.ts @@ -1,8 +1,8 @@ // @drawtonomy/sdk - Entry Point -export * from './types' -export * from './helpers' -export * from './geometry' -export { ExtensionClient } from './ExtensionClient' -export { parseDrawtonomySvg } from './snapshot' +export * from './types.js' +export * from './helpers.js' +export * from './geometry.js' +export { ExtensionClient } from './ExtensionClient.js' +export { parseDrawtonomySvg } from './snapshot.js' // Exporter sub-module is also available via "@drawtonomy/sdk/exporter". -export * as exporter from './exporter' +export * as exporter from './exporter/index.js' diff --git a/packages/drawtonomy-sdk/src/snapshot.ts b/packages/drawtonomy-sdk/src/snapshot.ts index 435d94c..b4e2ae5 100644 --- a/packages/drawtonomy-sdk/src/snapshot.ts +++ b/packages/drawtonomy-sdk/src/snapshot.ts @@ -3,7 +3,7 @@ // DrawtonomySnapshot. The legacy attribute name `data-drawauto-snapshot` // is also accepted for backwards compatibility. -import type { DrawtonomySnapshot } from './types' +import type { DrawtonomySnapshot } from './types.js' /** * Decode a base64-encoded UTF-8 string. Mirrors the encoder used when the diff --git a/packages/drawtonomy-sdk/tsconfig.json b/packages/drawtonomy-sdk/tsconfig.json index f5b25e7..d299cdf 100644 --- a/packages/drawtonomy-sdk/tsconfig.json +++ b/packages/drawtonomy-sdk/tsconfig.json @@ -1,9 +1,12 @@ { "compilerOptions": { "target": "ES2020", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ES2020", "DOM"], + "module": "NodeNext", + "moduleResolution": "nodenext", + "lib": [ + "ES2020", + "DOM" + ], "declaration": true, "declarationMap": true, "sourceMap": true, @@ -13,5 +16,7 @@ "skipLibCheck": true, "isolatedModules": true }, - "include": ["src"] + "include": [ + "src" + ] }