vehicle-path2 1.0.14 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +168 -168
  2. package/dist/core/algorithms/pathFinding.d.ts +2 -2
  3. package/dist/core/algorithms/vehicleMovement.d.ts +29 -20
  4. package/dist/core/engine.d.ts +160 -0
  5. package/dist/core/index.d.ts +3 -2
  6. package/dist/core/types/api.d.ts +9 -0
  7. package/dist/core/types/movement.d.ts +2 -3
  8. package/dist/core/types/vehicle.d.ts +4 -2
  9. package/dist/core.cjs +1 -1
  10. package/dist/core.js +33 -541
  11. package/dist/index.d.ts +4 -34
  12. package/dist/utils/event-emitter.d.ts +4 -6
  13. package/dist/vehicle-path.cjs +1 -1
  14. package/dist/vehicle-path.js +729 -59
  15. package/package.json +83 -103
  16. package/dist/animation-loop-bZEm2pMN.js +0 -37
  17. package/dist/animation-loop-fC2LjxCd.cjs +0 -1
  18. package/dist/react/dsl-hooks/useInitialMovement.d.ts +0 -24
  19. package/dist/react/dsl-hooks/useMovementSequence.d.ts +0 -27
  20. package/dist/react/dsl-hooks/useSceneDefinition.d.ts +0 -22
  21. package/dist/react/hooks/useAnimation.d.ts +0 -47
  22. package/dist/react/hooks/useMovementQueue.d.ts +0 -53
  23. package/dist/react/hooks/useScene.d.ts +0 -78
  24. package/dist/react/hooks/useVehicleSimulation.d.ts +0 -128
  25. package/dist/react/hooks/useVehicles.d.ts +0 -55
  26. package/dist/react/index.d.ts +0 -48
  27. package/dist/react/providers/useVehicleEvents.d.ts +0 -78
  28. package/dist/react.cjs +0 -1
  29. package/dist/react.js +0 -18
  30. package/dist/useVehicleEvents-BZVmIugl.cjs +0 -3
  31. package/dist/useVehicleEvents-CabztfQ4.js +0 -940
  32. package/dist/utils/animation-loop.d.ts +0 -105
  33. package/dist/utils/dsl-parser.d.ts +0 -151
  34. package/dist/utils/index.d.ts +0 -15
  35. package/dist/utils/type-converters.d.ts +0 -40
  36. package/dist/utils/vehicle-helpers.d.ts +0 -8
  37. package/dist/utils.cjs +0 -1
  38. package/dist/utils.js +0 -17
  39. package/dist/vehicle-helpers-BgD4BTAJ.js +0 -275
  40. package/dist/vehicle-helpers-DrnYWjm3.cjs +0 -7
@@ -1,105 +0,0 @@
1
- /**
2
- * Animation Loop Utility
3
- *
4
- * A simple utility for creating animation loops with start/pause/stop controls.
5
- * Uses requestAnimationFrame for smooth animations.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { createAnimationLoop } from 'vehicle-path/utils'
10
- *
11
- * const { start, pause, stop, isRunning } = createAnimationLoop({
12
- * onTick: (deltaTime) => {
13
- * // Update animation state
14
- * tick(velocity)
15
- * },
16
- * onComplete: () => {
17
- * console.log('Animation complete!')
18
- * }
19
- * })
20
- *
21
- * // Start the animation
22
- * start()
23
- *
24
- * // Pause (can resume with start())
25
- * pause()
26
- *
27
- * // Stop completely (resets state)
28
- * stop()
29
- * ```
30
- */
31
- export interface AnimationLoopOptions {
32
- /**
33
- * Called on each animation frame
34
- * @param deltaTime - Time elapsed since last frame in milliseconds
35
- * @returns true to continue, false to complete the animation
36
- */
37
- onTick: (deltaTime: number) => boolean | void;
38
- /**
39
- * Called when the animation completes (onTick returns false)
40
- */
41
- onComplete?: () => void;
42
- /**
43
- * Called when the animation starts
44
- */
45
- onStart?: () => void;
46
- /**
47
- * Called when the animation pauses
48
- */
49
- onPause?: () => void;
50
- /**
51
- * Called when the animation stops
52
- */
53
- onStop?: () => void;
54
- }
55
- export interface AnimationLoopControls {
56
- /**
57
- * Start or resume the animation
58
- */
59
- start: () => void;
60
- /**
61
- * Pause the animation (can be resumed with start())
62
- */
63
- pause: () => void;
64
- /**
65
- * Stop the animation completely
66
- */
67
- stop: () => void;
68
- /**
69
- * Check if the animation is currently running
70
- */
71
- isRunning: () => boolean;
72
- /**
73
- * Check if the animation is paused
74
- */
75
- isPaused: () => boolean;
76
- }
77
- /**
78
- * Create an animation loop with start/pause/stop controls
79
- *
80
- * @param options - Animation loop configuration
81
- * @returns Control functions for the animation loop
82
- */
83
- export declare function createAnimationLoop(options: AnimationLoopOptions): AnimationLoopControls;
84
- /**
85
- * React hook for using animation loop with automatic cleanup
86
- *
87
- * @example
88
- * ```typescript
89
- * import { useAnimationLoop } from 'vehicle-path/utils'
90
- *
91
- * function MyComponent() {
92
- * const { start, pause, stop, isRunning } = useAnimationLoop({
93
- * onTick: (deltaTime) => tick(velocity),
94
- * onComplete: () => setFinished(true)
95
- * })
96
- *
97
- * return (
98
- * <button onClick={isRunning() ? pause : start}>
99
- * {isRunning() ? 'Pause' : 'Start'}
100
- * </button>
101
- * )
102
- * }
103
- * ```
104
- */
105
- export declare function useAnimationLoop(options: AnimationLoopOptions): AnimationLoopControls;
@@ -1,151 +0,0 @@
1
- /**
2
- * DSL Parser Utilities
3
- *
4
- * These utilities convert DSL text into API-compatible types that can be used
5
- * with the programmatic hooks (useScene, useVehicles, useMovement).
6
- *
7
- * @example
8
- * ```typescript
9
- * import { parseSceneDSL, parseVehiclesDSL, parseMovementDSL } from 'vehicle-path/utils'
10
- *
11
- * const sceneConfig = parseSceneDSL(`
12
- * line001 : (100, 100) -> (700, 100)
13
- * line002 : (700, 100) -> (700, 400)
14
- * line001 -> line002
15
- * `)
16
- * setScene(sceneConfig)
17
- *
18
- * const vehicles = parseVehiclesDSL(`
19
- * v1 start line001 0%
20
- * v2 start line002 50%
21
- * `)
22
- * vehicles.forEach(v => addVehicle(v))
23
- *
24
- * const movements = parseMovementDSL(`
25
- * v1 goto line002 100%
26
- * `)
27
- * movements.forEach(m => queueMovement(m.vehicleId, m))
28
- * ```
29
- */
30
- import type { SceneConfig, VehicleInput, GotoCommandInput } from '../core/types/api';
31
- /**
32
- * Parse result with errors for validation feedback
33
- */
34
- export interface ParseResult<T> {
35
- data: T;
36
- errors: string[];
37
- }
38
- /**
39
- * Movement command parsed from DSL (includes vehicleId for routing)
40
- */
41
- export interface MovementCommand extends GotoCommandInput {
42
- vehicleId: string;
43
- }
44
- /**
45
- * Parse scene DSL into SceneConfig for useScene.setScene()
46
- *
47
- * DSL Format:
48
- * ```
49
- * # Lines
50
- * line001 : (100, 100) -> (700, 100)
51
- * line002 : (700, 100) -> (700, 400)
52
- *
53
- * # Connections (curves)
54
- * line001 -> line002
55
- * line001 80% -> line002 20%
56
- * ```
57
- *
58
- * @param text - DSL text to parse
59
- * @returns ParseResult containing SceneConfig and any parsing errors
60
- */
61
- export declare function parseSceneDSL(text: string): ParseResult<SceneConfig>;
62
- /**
63
- * Parse vehicle DSL into VehicleInput[] for useVehicles.addVehicles()
64
- *
65
- * DSL Format:
66
- * ```
67
- * v1 start line001 0%
68
- * v2 start line002 50%
69
- * v3 start line001 100 # absolute offset
70
- * ```
71
- *
72
- * @param text - DSL text to parse
73
- * @returns ParseResult containing VehicleInput[] and any parsing errors
74
- */
75
- export declare function parseVehiclesDSL(text: string): ParseResult<VehicleInput[]>;
76
- /**
77
- * Parse movement DSL into MovementCommand[] for useMovement.queueMovement()
78
- *
79
- * DSL Format:
80
- * ```
81
- * v1 goto line001 100%
82
- * v2 goto line001 0% --payload {"orderId": "123"}
83
- * v1 goto line003 100% --payload {"message": "hello"}
84
- * ```
85
- *
86
- * @param text - DSL text to parse
87
- * @returns ParseResult containing MovementCommand[] and any parsing errors
88
- */
89
- export declare function parseMovementDSL(text: string): ParseResult<MovementCommand[]>;
90
- /**
91
- * Parse all DSL types from a single text block
92
- *
93
- * This is useful when you have a combined DSL that includes scene, vehicles, and movements.
94
- *
95
- * @param text - Combined DSL text to parse
96
- * @returns Object containing parsed scene, vehicles, and movements with errors
97
- */
98
- export declare function parseAllDSL(text: string): {
99
- scene: ParseResult<SceneConfig>;
100
- vehicles: ParseResult<VehicleInput[]>;
101
- movements: ParseResult<MovementCommand[]>;
102
- };
103
- /**
104
- * Generate scene DSL from SceneConfig
105
- *
106
- * @param config - SceneConfig from programmatic API
107
- * @returns DSL text representation
108
- *
109
- * @example
110
- * ```typescript
111
- * const dsl = generateSceneDSL({
112
- * lines: [{ id: 'line001', start: [100, 100], end: [500, 100] }],
113
- * connections: [{ from: 'line001', to: 'line002' }]
114
- * })
115
- * // Returns:
116
- * // line001 : (100, 100) -> (500, 100)
117
- * //
118
- * // line001 -> line002
119
- * ```
120
- */
121
- export declare function generateSceneDSL(config: SceneConfig): string;
122
- /**
123
- * Generate vehicles DSL from VehicleInput[]
124
- *
125
- * @param vehicles - Array of VehicleInput from programmatic API
126
- * @returns DSL text representation
127
- *
128
- * @example
129
- * ```typescript
130
- * const dsl = generateVehiclesDSL([
131
- * { id: 'v1', lineId: 'line001', position: 0.5, isPercentage: true }
132
- * ])
133
- * // Returns: "v1 start line001 50%"
134
- * ```
135
- */
136
- export declare function generateVehiclesDSL(vehicles: VehicleInput[]): string;
137
- /**
138
- * Generate movement DSL from MovementCommand[]
139
- *
140
- * @param commands - Array of MovementCommand from programmatic API
141
- * @returns DSL text representation
142
- *
143
- * @example
144
- * ```typescript
145
- * const dsl = generateMovementDSL([
146
- * { vehicleId: 'v1', targetLineId: 'line002', targetPosition: 1.0 }
147
- * ])
148
- * // Returns: "v1 goto line002 100%"
149
- * ```
150
- */
151
- export declare function generateMovementDSL(commands: MovementCommand[]): string;
@@ -1,15 +0,0 @@
1
- /**
2
- * Utils Layer - Optional utilities
3
- *
4
- * This layer contains utilities that are optional and can be replaced with
5
- * your own implementations. Includes DSL parser, event emitter, animation loop, etc.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { parseSceneDSL, VehicleEventEmitter, createAnimationLoop } from 'vehicle-path/utils'
10
- * ```
11
- */
12
- export { VehicleEventEmitter, type VehicleEventMap, type VehicleEventType, type VehicleEventCallback, type VehiclePositionUpdate, type Unsubscribe, type CommandStartInfo } from './event-emitter';
13
- export { parseSceneDSL, parseVehiclesDSL, parseMovementDSL, parseAllDSL, generateSceneDSL, generateVehiclesDSL, generateMovementDSL, type ParseResult, type MovementCommand } from './dsl-parser';
14
- export { createAnimationLoop, useAnimationLoop, type AnimationLoopOptions, type AnimationLoopControls } from './animation-loop';
15
- export { validateAndCreateVehicles, getNextStartVehicleId, getNextGotoVehicleId } from './vehicle-helpers';
@@ -1,40 +0,0 @@
1
- /**
2
- * Type Converters
3
- *
4
- * Convert API types to internal types. Used by hooks and loadFromDSL.
5
- */
6
- import type { SceneLineInput, SceneConnectionInput, CoordinateInput, VehicleInput } from '../core/types/api';
7
- import type { Line, Curve } from '../core/types/geometry';
8
- import type { VehicleStart, GotoCommand } from '../core/types/vehicle';
9
- /**
10
- * Convert coordinate input to Point
11
- */
12
- export declare function toPoint(coord: CoordinateInput): {
13
- x: number;
14
- y: number;
15
- };
16
- /**
17
- * Convert SceneLineInput to internal Line type
18
- */
19
- export declare function toLine(input: SceneLineInput): Line;
20
- /**
21
- * Convert SceneConnectionInput to internal Curve type
22
- * Note: Percentage values are stored as 0-1 (same as API format)
23
- */
24
- export declare function toCurve(input: SceneConnectionInput): Curve;
25
- /**
26
- * Convert VehicleInput to internal VehicleStart format
27
- * Note: Percentage values are stored as 0-1 (same as API format)
28
- */
29
- export declare function toVehicleStart(input: VehicleInput): VehicleStart;
30
- /**
31
- * Convert GotoCommand input (with optional fields) to internal GotoCommand format (all required)
32
- * Note: Percentage values are stored as 0-1 (same as API format)
33
- */
34
- export declare function toGotoCommand(cmd: {
35
- vehicleId: string;
36
- targetLineId: string;
37
- targetPosition?: number;
38
- isPercentage?: boolean;
39
- payload?: unknown;
40
- }): GotoCommand;
@@ -1,8 +0,0 @@
1
- import type { Line } from '../core/types/geometry';
2
- import type { Vehicle, VehicleStart, GotoCommand } from '../core/types/vehicle';
3
- export declare function validateAndCreateVehicles(vehicleStarts: VehicleStart[], lines: Line[], wheelbase?: number): {
4
- vehicles: Vehicle[];
5
- errors: string[];
6
- };
7
- export declare function getNextStartVehicleId(existingVehicles: VehicleStart[]): string;
8
- export declare function getNextGotoVehicleId(existingCommands: GotoCommand[], vehicles: Vehicle[]): string | null;
package/dist/utils.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./vehicle-helpers-DrnYWjm3.cjs"),t=require("./animation-loop-fC2LjxCd.cjs");exports.VehicleEventEmitter=e.VehicleEventEmitter;exports.generateMovementDSL=e.generateMovementDSL;exports.generateSceneDSL=e.generateSceneDSL;exports.generateVehiclesDSL=e.generateVehiclesDSL;exports.getNextGotoVehicleId=e.getNextGotoVehicleId;exports.getNextStartVehicleId=e.getNextStartVehicleId;exports.parseAllDSL=e.parseAllDSL;exports.parseMovementDSL=e.parseMovementDSL;exports.parseSceneDSL=e.parseSceneDSL;exports.parseVehiclesDSL=e.parseVehiclesDSL;exports.validateAndCreateVehicles=e.validateAndCreateVehicles;exports.createAnimationLoop=t.createAnimationLoop;exports.useAnimationLoop=t.useAnimationLoop;
package/dist/utils.js DELETED
@@ -1,17 +0,0 @@
1
- import { V as t, g as s, a as r, b as o, c as n, d as i, p as c, e as S, f as l, h as p, v as L } from "./vehicle-helpers-BgD4BTAJ.js";
2
- import { c as m, u as D } from "./animation-loop-bZEm2pMN.js";
3
- export {
4
- t as VehicleEventEmitter,
5
- m as createAnimationLoop,
6
- s as generateMovementDSL,
7
- r as generateSceneDSL,
8
- o as generateVehiclesDSL,
9
- n as getNextGotoVehicleId,
10
- i as getNextStartVehicleId,
11
- c as parseAllDSL,
12
- S as parseMovementDSL,
13
- l as parseSceneDSL,
14
- p as parseVehiclesDSL,
15
- D as useAnimationLoop,
16
- L as validateAndCreateVehicles
17
- };
@@ -1,275 +0,0 @@
1
- import { distance as g, getPointOnLineByOffset as $, calculateInitialFrontPosition as I } from "./core.js";
2
- class S {
3
- listeners = /* @__PURE__ */ new Map();
4
- /**
5
- * Subscribe to an event
6
- * @param event - The event type to listen for
7
- * @param callback - Function to call when event is emitted
8
- * @returns Unsubscribe function
9
- */
10
- on(e, t) {
11
- return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => {
12
- this.listeners.get(e)?.delete(t);
13
- };
14
- }
15
- /**
16
- * Emit an event to all subscribers
17
- * @param event - The event type to emit
18
- * @param data - The event data
19
- */
20
- emit(e, t) {
21
- this.listeners.get(e)?.forEach((s) => {
22
- try {
23
- s(t);
24
- } catch (o) {
25
- console.error(`Error in event listener for "${e}":`, o);
26
- }
27
- });
28
- }
29
- /**
30
- * Remove all listeners for a specific event, or all events if no event specified
31
- * @param event - Optional event type to clear listeners for
32
- */
33
- off(e) {
34
- e ? this.listeners.delete(e) : this.listeners.clear();
35
- }
36
- /**
37
- * Get the number of listeners for a specific event
38
- * @param event - The event type
39
- * @returns Number of listeners
40
- */
41
- listenerCount(e) {
42
- return this.listeners.get(e)?.size ?? 0;
43
- }
44
- }
45
- function P(i) {
46
- const e = [], t = [], s = [], o = i.trim().split(`
47
- `);
48
- let d = 0;
49
- for (const n of o) {
50
- d++;
51
- const r = n.trim();
52
- if (!r || r.startsWith("#")) continue;
53
- const a = r.match(/^(\w+)\s*:\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)\s*->\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);
54
- if (a) {
55
- e.push({
56
- id: a[1],
57
- start: [parseFloat(a[2]), parseFloat(a[3])],
58
- end: [parseFloat(a[4]), parseFloat(a[5])]
59
- });
60
- continue;
61
- }
62
- const c = r.match(/^(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))??\s*->\s*(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))?/);
63
- if (c) {
64
- const l = {
65
- from: c[1],
66
- to: c[4]
67
- };
68
- if (c[2]) {
69
- const f = parseFloat(c[2]), h = c[3] === "%";
70
- l.fromPosition = h ? f / 100 : f, l.fromIsPercentage = h;
71
- }
72
- if (c[5]) {
73
- const f = parseFloat(c[5]), h = c[6] === "%";
74
- l.toPosition = h ? f / 100 : f, l.toIsPercentage = h;
75
- }
76
- t.push(l);
77
- continue;
78
- }
79
- r.match(/^\w+\s+start\s+/) || r.match(/^\w+\s+goto\s+/) || s.push(`Line ${d}: Unable to parse "${r}"`);
80
- }
81
- return {
82
- data: {
83
- lines: e,
84
- connections: t.length > 0 ? t : void 0
85
- },
86
- errors: s
87
- };
88
- }
89
- function v(i) {
90
- const e = [], t = [], s = i.trim().split(`
91
- `);
92
- let o = 0;
93
- for (const d of s) {
94
- o++;
95
- const n = d.trim();
96
- if (!n || n.startsWith("#")) continue;
97
- const r = n.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
98
- if (r) {
99
- const a = parseFloat(r[3]), c = r[4] === "%";
100
- e.push({
101
- id: r[1],
102
- lineId: r[2],
103
- // API uses 0-1 for percentage, DSL uses 0-100
104
- position: c ? a / 100 : a,
105
- isPercentage: c
106
- });
107
- continue;
108
- }
109
- n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+goto\s+/) || n.match(/^\w+\s+start/) && t.push(`Line ${o}: Invalid vehicle start format "${n}"`);
110
- }
111
- return {
112
- data: e,
113
- errors: t
114
- };
115
- }
116
- function w(i) {
117
- const e = [], t = [], s = i.trim().split(`
118
- `);
119
- let o = 0;
120
- for (const d of s) {
121
- o++;
122
- const n = d.trim();
123
- if (!n || n.startsWith("#")) continue;
124
- const r = n.match(/^(\w+)\s+goto\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);
125
- if (r) {
126
- const a = n.slice(r[0].length);
127
- let c;
128
- const l = a.match(/--payload\s+(\{.*\})/);
129
- if (l)
130
- try {
131
- c = JSON.parse(l[1]);
132
- } catch {
133
- t.push(`Line ${o}: Invalid JSON payload "${l[1]}"`);
134
- }
135
- const f = parseFloat(r[3]), h = r[4] === "%";
136
- e.push({
137
- vehicleId: r[1],
138
- targetLineId: r[2],
139
- // API uses 0-1 for percentage, DSL uses 0-100
140
- // For absolute offsets, keep the raw value
141
- targetPosition: h ? f / 100 : f,
142
- isPercentage: h,
143
- payload: c
144
- });
145
- continue;
146
- }
147
- n.match(/^\w+\s*:\s*\(/) || n.match(/^\w+.*->\s*\w+/) || n.match(/^\w+\s+start\s+/) || n.match(/^\w+\s+goto/) && t.push(`Line ${o}: Invalid goto command format "${n}"`);
148
- }
149
- return {
150
- data: e,
151
- errors: t
152
- };
153
- }
154
- function y(i) {
155
- return {
156
- scene: P(i),
157
- vehicles: v(i),
158
- movements: w(i)
159
- };
160
- }
161
- function u(i) {
162
- return Array.isArray(i) ? { x: i[0], y: i[1] } : i;
163
- }
164
- function M(i) {
165
- const e = [];
166
- for (const t of i.lines) {
167
- const s = u(t.start), o = u(t.end);
168
- e.push(`${t.id} : (${Math.round(s.x)}, ${Math.round(s.y)}) -> (${Math.round(o.x)}, ${Math.round(o.y)})`);
169
- }
170
- if (i.lines.length > 0 && i.connections && i.connections.length > 0 && e.push(""), i.connections)
171
- for (const t of i.connections) {
172
- let s = t.from;
173
- t.fromPosition !== void 0 && (t.fromIsPercentage !== !1 ? s += ` ${t.fromPosition * 100}%` : s += ` ${t.fromPosition}`), s += " -> ", s += t.to, t.toPosition !== void 0 && (t.toIsPercentage !== !1 ? s += ` ${t.toPosition * 100}%` : s += ` ${t.toPosition}`), e.push(s);
174
- }
175
- return e.join(`
176
- `);
177
- }
178
- function x(i) {
179
- return i.map((e) => {
180
- const t = e.position ?? 0;
181
- return e.isPercentage !== !1 ? `${e.id} start ${e.lineId} ${t * 100}%` : `${e.id} start ${e.lineId} ${t}`;
182
- }).join(`
183
- `);
184
- }
185
- function V(i) {
186
- return i.map((e) => {
187
- const t = e.targetPosition ?? 1, s = e.isPercentage !== !1;
188
- let o = e.vehicleId;
189
- return o += ` goto ${e.targetLineId}`, s ? o += ` ${t * 100}%` : o += ` ${t}`, e.payload !== void 0 && (o += ` --payload ${JSON.stringify(e.payload)}`), o;
190
- }).join(`
191
- `);
192
- }
193
- function N(i, e, t = 0) {
194
- const s = [], o = [], d = /* @__PURE__ */ new Set();
195
- for (const n of i) {
196
- if (d.has(n.vehicleId)) {
197
- o.push(`Duplicate vehicle ID: ${n.vehicleId}`);
198
- continue;
199
- }
200
- d.add(n.vehicleId);
201
- const r = e.find((p) => p.id === n.lineId);
202
- if (!r) {
203
- o.push(`Vehicle ${n.vehicleId}: Line "${n.lineId}" not found`);
204
- continue;
205
- }
206
- const a = g(r.start, r.end), c = Math.max(0, a - t);
207
- let l;
208
- if (n.isPercentage) {
209
- if (n.offset < 0 || n.offset > 1) {
210
- o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} must be between 0 and 1 for percentage`);
211
- continue;
212
- }
213
- l = n.offset * c;
214
- } else {
215
- if (n.offset < 0 || n.offset > a) {
216
- o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} exceeds line length ${a.toFixed(2)}`);
217
- continue;
218
- }
219
- l = Math.min(n.offset, c);
220
- }
221
- const f = $(r, l, !1), h = {
222
- lineId: n.lineId,
223
- position: f,
224
- absoluteOffset: l
225
- }, m = I(
226
- n.lineId,
227
- l,
228
- t,
229
- r
230
- );
231
- s.push({
232
- id: n.vehicleId,
233
- lineId: n.lineId,
234
- offset: n.offset,
235
- isPercentage: n.isPercentage,
236
- state: "idle",
237
- rear: h,
238
- front: m
239
- });
240
- }
241
- return { vehicles: s, errors: o };
242
- }
243
- function b(i) {
244
- const e = i.map((s) => {
245
- const o = s.vehicleId.match(/^v(\d+)$/);
246
- return o ? parseInt(o[1]) : 0;
247
- }).filter((s) => s > 0);
248
- return `v${(e.length > 0 ? Math.max(...e) : 0) + 1}`;
249
- }
250
- function F(i, e) {
251
- if (e.length === 0) return null;
252
- if (i.length === 0)
253
- return e[0].id;
254
- const t = /* @__PURE__ */ new Map();
255
- for (const s of e)
256
- t.set(s.id, 0);
257
- for (const s of i) {
258
- const o = t.get(s.vehicleId) || 0;
259
- t.set(s.vehicleId, o + 1);
260
- }
261
- return e[0].id;
262
- }
263
- export {
264
- S as V,
265
- M as a,
266
- x as b,
267
- F as c,
268
- b as d,
269
- w as e,
270
- P as f,
271
- V as g,
272
- v as h,
273
- y as p,
274
- N as v
275
- };
@@ -1,7 +0,0 @@
1
- "use strict";const u=require("./core.cjs");class v{listeners=new Map;on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.get(e)?.delete(t)}}emit(e,t){this.listeners.get(e)?.forEach(s=>{try{s(t)}catch(o){console.error(`Error in event listener for "${e}":`,o)}})}off(e){e?this.listeners.delete(e):this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function p(i){const e=[],t=[],s=[],o=i.trim().split(`
2
- `);let d=0;for(const n of o){d++;const r=n.trim();if(!r||r.startsWith("#"))continue;const a=r.match(/^(\w+)\s*:\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)\s*->\s*\((-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)\)/);if(a){e.push({id:a[1],start:[parseFloat(a[2]),parseFloat(a[3])],end:[parseFloat(a[4]),parseFloat(a[5])]});continue}const c=r.match(/^(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))??\s*->\s*(\w+)(?:\s+(\d+(?:\.\d+)?)(%?))?/);if(c){const l={from:c[1],to:c[4]};if(c[2]){const f=parseFloat(c[2]),h=c[3]==="%";l.fromPosition=h?f/100:f,l.fromIsPercentage=h}if(c[5]){const f=parseFloat(c[5]),h=c[6]==="%";l.toPosition=h?f/100:f,l.toIsPercentage=h}t.push(l);continue}r.match(/^\w+\s+start\s+/)||r.match(/^\w+\s+goto\s+/)||s.push(`Line ${d}: Unable to parse "${r}"`)}return{data:{lines:e,connections:t.length>0?t:void 0},errors:s}}function g(i){const e=[],t=[],s=i.trim().split(`
3
- `);let o=0;for(const d of s){o++;const n=d.trim();if(!n||n.startsWith("#"))continue;const r=n.match(/^(\w+)\s+start\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);if(r){const a=parseFloat(r[3]),c=r[4]==="%";e.push({id:r[1],lineId:r[2],position:c?a/100:a,isPercentage:c});continue}n.match(/^\w+\s*:\s*\(/)||n.match(/^\w+.*->\s*\w+/)||n.match(/^\w+\s+goto\s+/)||n.match(/^\w+\s+start/)&&t.push(`Line ${o}: Invalid vehicle start format "${n}"`)}return{data:e,errors:t}}function I(i){const e=[],t=[],s=i.trim().split(`
4
- `);let o=0;for(const d of s){o++;const n=d.trim();if(!n||n.startsWith("#"))continue;const r=n.match(/^(\w+)\s+goto\s+(\w+)\s+(\d+(?:\.\d+)?)(%?)/);if(r){const a=n.slice(r[0].length);let c;const l=a.match(/--payload\s+(\{.*\})/);if(l)try{c=JSON.parse(l[1])}catch{t.push(`Line ${o}: Invalid JSON payload "${l[1]}"`)}const f=parseFloat(r[3]),h=r[4]==="%";e.push({vehicleId:r[1],targetLineId:r[2],targetPosition:h?f/100:f,isPercentage:h,payload:c});continue}n.match(/^\w+\s*:\s*\(/)||n.match(/^\w+.*->\s*\w+/)||n.match(/^\w+\s+start\s+/)||n.match(/^\w+\s+goto/)&&t.push(`Line ${o}: Invalid goto command format "${n}"`)}return{data:e,errors:t}}function L(i){return{scene:p(i),vehicles:g(i),movements:I(i)}}function m(i){return Array.isArray(i)?{x:i[0],y:i[1]}:i}function S(i){const e=[];for(const t of i.lines){const s=m(t.start),o=m(t.end);e.push(`${t.id} : (${Math.round(s.x)}, ${Math.round(s.y)}) -> (${Math.round(o.x)}, ${Math.round(o.y)})`)}if(i.lines.length>0&&i.connections&&i.connections.length>0&&e.push(""),i.connections)for(const t of i.connections){let s=t.from;t.fromPosition!==void 0&&(t.fromIsPercentage!==!1?s+=` ${t.fromPosition*100}%`:s+=` ${t.fromPosition}`),s+=" -> ",s+=t.to,t.toPosition!==void 0&&(t.toIsPercentage!==!1?s+=` ${t.toPosition*100}%`:s+=` ${t.toPosition}`),e.push(s)}return e.join(`
5
- `)}function w(i){return i.map(e=>{const t=e.position??0;return e.isPercentage!==!1?`${e.id} start ${e.lineId} ${t*100}%`:`${e.id} start ${e.lineId} ${t}`}).join(`
6
- `)}function M(i){return i.map(e=>{const t=e.targetPosition??1,s=e.isPercentage!==!1;let o=e.vehicleId;return o+=` goto ${e.targetLineId}`,s?o+=` ${t*100}%`:o+=` ${t}`,e.payload!==void 0&&(o+=` --payload ${JSON.stringify(e.payload)}`),o}).join(`
7
- `)}function V(i,e,t=0){const s=[],o=[],d=new Set;for(const n of i){if(d.has(n.vehicleId)){o.push(`Duplicate vehicle ID: ${n.vehicleId}`);continue}d.add(n.vehicleId);const r=e.find(P=>P.id===n.lineId);if(!r){o.push(`Vehicle ${n.vehicleId}: Line "${n.lineId}" not found`);continue}const a=u.distance(r.start,r.end),c=Math.max(0,a-t);let l;if(n.isPercentage){if(n.offset<0||n.offset>1){o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} must be between 0 and 1 for percentage`);continue}l=n.offset*c}else{if(n.offset<0||n.offset>a){o.push(`Vehicle ${n.vehicleId}: Offset ${n.offset} exceeds line length ${a.toFixed(2)}`);continue}l=Math.min(n.offset,c)}const f=u.getPointOnLineByOffset(r,l,!1),h={lineId:n.lineId,position:f,absoluteOffset:l},$=u.calculateInitialFrontPosition(n.lineId,l,t,r);s.push({id:n.vehicleId,lineId:n.lineId,offset:n.offset,isPercentage:n.isPercentage,state:"idle",rear:h,front:$})}return{vehicles:s,errors:o}}function y(i){const e=i.map(s=>{const o=s.vehicleId.match(/^v(\d+)$/);return o?parseInt(o[1]):0}).filter(s=>s>0);return`v${(e.length>0?Math.max(...e):0)+1}`}function D(i,e){if(e.length===0)return null;if(i.length===0)return e[0].id;const t=new Map;for(const s of e)t.set(s.id,0);for(const s of i){const o=t.get(s.vehicleId)||0;t.set(s.vehicleId,o+1)}return e[0].id}exports.VehicleEventEmitter=v;exports.generateMovementDSL=M;exports.generateSceneDSL=S;exports.generateVehiclesDSL=w;exports.getNextGotoVehicleId=D;exports.getNextStartVehicleId=y;exports.parseAllDSL=L;exports.parseMovementDSL=I;exports.parseSceneDSL=p;exports.parseVehiclesDSL=g;exports.validateAndCreateVehicles=V;