scjson 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  This directory contains the JavaScript implementation of **scjson**, a format for representing SCXML state machines in JSON. The package provides a command line interface to convert between `.scxml` and `.scjson` files and to validate documents against the project's schema.
4
4
 
5
+ For details on how SCXML elements are inferred during conversion see [INFERENCE.md](https://github.com/SoftOboros/scjson/blob/main/INFERENCE.md).
6
+
5
7
  The package includes typescript types for the functions and default functions to return each.
6
8
 
7
9
  ## Installation
@@ -74,6 +76,14 @@ const { xmlToJson, jsonToXml } = require('scjson');
74
76
  import { xmlToJson, jsonToXml }from "scjson/browser"
75
77
  ```
76
78
 
79
+ ## Shared Converters
80
+ Both the Node and browser builds use the same conversion logic exposed in
81
+ `scjson/converters`. You can import these helpers directly if you need access to
82
+ the utility functions used by the CLI and browser modules.
83
+ ```js
84
+ import { xmlToJson, jsonToXml } from 'scjson/converters';
85
+ ```
86
+
77
87
  ## Axios Endpoint Example
78
88
  ```typescript
79
89
  import axios from "axios"
@@ -122,6 +132,177 @@ export const sendNewScxml = () => {
122
132
 
123
133
  ```
124
134
 
135
+ ## Known Issues
136
+ None at this time.
137
+
138
+ Operational conformance testing is performed via [uber_test.py](https://github.com/SoftOboros/scjson/blob/engine/py/uber_test.py)
139
+ ```bash
140
+ /py# python uber_test.py -l javascript 2>&1 | tee test.log
141
+ ```
142
+ Note: [uber_test.py](https://github.com/SoftOboros/scjson/blob/main/py/uber_test.py) applies all scxml files in [Zhornyak's ScxmlEditor-Tutorial](https://alexzhornyak.github.io/ScxmlEditor-Tutorial/) which provides a robest set of scxml test vectors useful for standard compliance verification. This is the only file in the test suite which fails to verify round-trip.
143
+
144
+
145
+ ### `scjson/props`
146
+
147
+ ### Enums
148
+
149
+ Each enumeration represents a restricted string set used by SCXML. The values
150
+ shown below mirror those defined in the SCJSON schema.
151
+
152
+ enums use this pattern to all static and dynamic portions to be treated separately,
153
+ but mapped to the same name.
154
+ ```typescript
155
+ export const BooleanDatatypeProps = {
156
+ False: "false",
157
+ True: "true",
158
+ } as const;
159
+
160
+ export type BooleanDatatypeProps = typeof BooleanDatatypeProps[keyof typeof BooleanDatatypeProps];
161
+ ```
162
+
163
+ - `AssignTypeDatatypeProps` – how the `<assign>` element manipulates the datamodel.
164
+ Values: `replacechildren`, `firstchild`, `lastchild`, `previoussibling`,
165
+ `nextsibling`, `replace`, `delete`, `addattribute`.
166
+ - `BindingDatatypeProps` – determines if datamodel variables are bound `early` or
167
+ `late` during execution.
168
+ - `BooleanDatatypeProps` – boolean attribute values `true` or `false`.
169
+ - `ExmodeDatatypeProps` – processor execution mode, either `lax` or `strict`.
170
+ - `HistoryTypeDatatypeProps` – type of `<history>` state: `shallow` or `deep`.
171
+ - `TransitionTypeDatatypeProps` – whether a `<transition>` is `internal` or
172
+ `external`.
173
+
174
+ ### Common Types
175
+
176
+ Several generated classes share generic helper fields:
177
+
178
+ - `other_attributes`: `Record<str, str>` capturing additional XML attributes from
179
+ foreign namespaces.
180
+ - `other_element`: `list[object]` allowing untyped child nodes from other
181
+ namespaces to be preserved.
182
+ - `content`: `list[object]` used when elements permit mixed or wildcard
183
+ content.
184
+
185
+
186
+ ### Document / Object Types
187
+ Plain typescript types without runtime validation.
188
+
189
+ - `AssignProps` `AssignArray` – update a datamodel location with an expression or value.
190
+ - `CancelProps` `CancelArray` – cancel a pending `<send>` operation.
191
+ - `ContentProps` `ContentArray` – inline payload used by `<send>` and `<invoke>`.
192
+ - `DataProps` `DataArray` – represents a single datamodel variable.
193
+ - `DatamodelProps` `DatamodelArray` – container for one or more `<data>` elements.
194
+ - `DonedataProps` `DonedataArray` – payload returned when a `<final>` state is reached.
195
+ - `ElseProps` – fallback branch for `<if>` conditions.
196
+ - `ElseifProps` – conditional branch following an `<if>`.
197
+ - `FinalProps` `FinalArray` – marks a terminal state in the machine.
198
+ - `FinalizeProps` `FinalizeArray` – executed after an `<invoke>` completes.
199
+ - `ForeachProps` `ForeachArray` – iterate over items within executable content.
200
+ - `HistoryProps` `HistoryArray` – pseudostate remembering previous active children.
201
+ - `IfProps` `IfArray` – conditional execution block.
202
+ - `InitialProps` `InitialArray` – starting state within a compound state.
203
+ - `InvokeProps` `InvokeArray` – run an external process or machine.
204
+ - `LogProps` `LogArray` – diagnostic output statement.
205
+ - `OnentryProps` `OnentryArray` – actions performed when entering a state.
206
+ - `OnexitProps` `OnexitArray` – actions performed when leaving a state.
207
+ - `ParallelProps` `ParallelArray` – coordinates concurrent regions.
208
+ - `ParamProps` `ParamArray` – parameter passed to `<invoke>` or `<send>`.
209
+ - `RaiseProps` `RaiseArray` – raise an internal event.
210
+ - `ScriptProps` `ScriptArray` – inline executable script.
211
+ - `ScxmlProps` – root element of an SCJSON document.
212
+ - `SendProps` `SendArray` – dispatch an external event.
213
+ - `StateProps` `StateArray` – basic state node.
214
+ - `TransitionProps` `TransitionArray` – edge between states triggered by events.
215
+
216
+ ### Object Management
217
+ - Kind - unique marker for each of the types.
218
+ ```typescript
219
+ export type Kind = "number" | "string" | "record<string, object>" | "number[]" | "string[]"
220
+ | "record<string, object>[]" | "assign" | "assigntypedatatype" | "bindingdatatype" | "booleandatatype"
221
+ | "cancel" | "content" | "data" | "datamodel" | "donedata" | "else" | "elseif"
222
+ | "exmodedatatype" | "final" | "finalize" | "foreach" | "history" | "historytypedatatype" | "if"
223
+ | "initial" | "invoke" | "log" | "onentry" | "onexit" | "parallel" | "param" | "raise"
224
+ | "script" | "scxml" | "send" | "state" | "transition" | "transitiontypedatatype"
225
+ | "assignarray" | "cancelarray" | "contentarray" | "dataarray" | "datamodelarray"
226
+ | "donedataarray" | "finalarray" | "finalizearray" | "foreacharray" | "historyarray" | "ifarray"
227
+ | "initialarray" | "invokearray" | "logarray" | "onentryarray" | "onexitarray" | "parallelarray"
228
+ | "paramarray" | "raisearray" | "scriptarray" | "sendarray" | "statearray" | "transitionarray";
229
+ ```
230
+ - PropsUnion - a union of the types used in the scxml data model
231
+ ```typescript
232
+ export type PropsUnion = null | string | number | Record<string, object> | string[] | number[]
233
+ | Record<string, object>[] | AssignProps | AssignTypeDatatypeProps | BindingDatatypeProps
234
+ | BooleanDatatypeProps | CancelProps | ContentProps | DataProps | DatamodelProps | DonedataProps
235
+ | ElseProps | ElseifProps | ExmodeDatatypeProps | FinalProps | FinalizeProps | ForeachProps
236
+ | HistoryProps | HistoryTypeDatatypeProps | IfProps | InitialProps | InvokeProps | LogProps
237
+ | OnentryProps | OnexitProps | ParallelProps | ParamProps | RaiseProps | ScriptProps
238
+ | ScxmlProps | SendProps | StateProps | TransitionProps | TransitionTypeDatatypeProps
239
+ | AssignArray | CancelArray | ContentArray | DataArray | DatamodelArray | DonedataArray
240
+ | FinalArray | FinalizeArray | ForeachArray | HistoryArray | IfArray | InitialArray
241
+ | InvokeArray | LogArray | OnentryArray | OnexitArray | ParallelArray | ParamArray
242
+ | RaiseArray | ScriptArray | SendArray | StateArray | TransitionArray;
243
+ ```
244
+ - KindMap - maps string name to type for the objects used in the scxml data model
245
+ ```typescript
246
+ export type KindMap = {
247
+ assign: AssignProps
248
+ assignarray: AssignArray
249
+ assigntypedatatype: AssignTypeDatatypeProps
250
+ bindingdatatype: BindingDatatypeProps
251
+ booleandatatype: BooleanDatatypeProps
252
+ cancel: CancelProps
253
+ cancelarray: CancelArray
254
+ content: ContentProps
255
+ contentarray: ContentArray
256
+ data: DataProps
257
+ dataarray: DataArray
258
+ datamodel: DatamodelProps
259
+ datamodelarray: DatamodelArray
260
+ donedata: DonedataProps
261
+ donedataarray: DonedataArray
262
+ else: ElseProps
263
+ elseif: ElseifProps
264
+ exmodedatatype: ExmodeDatatypeProps
265
+ final: FinalProps
266
+ finalarray: FinalArray
267
+ finalize: FinalizeProps
268
+ finalizearray: FinalizeArray
269
+ foreach: ForeachProps
270
+ foreacharray: ForeachArray
271
+ history: HistoryProps
272
+ historyarray: HistoryArray
273
+ historytypedatatype: HistoryTypeDatatypeProps
274
+ if: IfProps
275
+ ifarray: IfArray
276
+ initial: InitialProps
277
+ initialarray: InitialArray
278
+ invoke: InvokeProps
279
+ invokearray: InvokeArray
280
+ log: LogProps
281
+ logarray: LogArray
282
+ onentry: OnentryProps
283
+ onentryarray: OnentryArray
284
+ onexit: OnexitProps
285
+ onexitarray: OnexitArray
286
+ parallel: ParallelProps
287
+ parallelarray: ParallelArray
288
+ param: ParamProps
289
+ paramarray: ParamArray
290
+ raise: RaiseProps
291
+ raisearray: RaiseArray
292
+ script: ScriptProps
293
+ scriptarray: ScriptArray
294
+ scxml: ScxmlProps
295
+ send: SendProps
296
+ sendarray: SendArray
297
+ state: StateProps
298
+ statearray: StateArray
299
+ transition: TransitionProps
300
+ transitionarray: TransitionArray
301
+ transitiontypedatatype: TransitionTypeDatatypeProps
302
+ }
303
+ ```
304
+
305
+
125
306
  ### Other Resources
126
307
  github: [https://github.com/SoftOboros/scjson]
127
308
  ```bash
@@ -132,9 +313,14 @@ git clone git@github.com:SoftOboros/scjson.git
132
313
  gh repo clone SoftOboros/scjson
133
314
  ```
134
315
 
135
- pypi: [https://www.npmjs.com/package/scjson]
316
+ pypi: [https://pypi.org/project/scjson/]
136
317
  ```bash
137
- npm install scjson
318
+ pip install scjson
319
+ ```
320
+
321
+ cargo: [https://crates.io/crates/scjson]
322
+ ```bash
323
+ cargo install scjson
138
324
  ```
139
325
 
140
326
  dockerhub: [https://hub.docker.com/r/iraa/scjson]
@@ -144,4 +330,4 @@ docker pull iraa/scjson:latest
144
330
  ```
145
331
 
146
332
 
147
- All source code in this directory is released under the BSD\u00A01-Clause license. See `LICENSE` and `LEGAL.md` for details.
333
+ All source code in this directory is released under the BSD\u00A01-Clause license. See [LICENSE](./LICENSE) and [LEGAL.md](./LEGAL.md) for details.
package/bin/scjson.js CHANGED
@@ -7,5 +7,5 @@
7
7
  * Licensed under the BSD 1-Clause License.
8
8
  */
9
9
 
10
- const { program } = require('../index.js');
10
+ const { program } = require('../dist/index.js');
11
11
  program.parse(process.argv);
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Agent Name: js-browser-cjs
4
+ *
5
+ * Part of the scjson project.
6
+ * Developed by Softoboros Technology Inc.
7
+ * Licensed under the BSD 1-Clause License.
8
+ */
9
+ /**
10
+ * @file CommonJS wrapper exporting the core converters.
11
+ */
12
+ module.exports = require('./converters.js');
@@ -0,0 +1,2 @@
1
+ declare const _exports: typeof import("./converters.js");
2
+ export = _exports;
@@ -0,0 +1,6 @@
1
+ export const xmlToJson: typeof core.xmlToJson;
2
+ export const jsonToXml: typeof core.jsonToXml;
3
+ export const removeEmpty: typeof core.removeEmpty;
4
+ export const normaliseKeys: typeof core.normaliseKeys;
5
+ export const ensureArrays: typeof core.ensureArrays;
6
+ import core from './converters.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Agent Name: js-browser
3
+ *
4
+ * Part of the scjson project.
5
+ * Developed by Softoboros Technology Inc.
6
+ * Licensed under the BSD 1-Clause License.
7
+ */
8
+ /**
9
+ * @file Browser friendly utilities re-exporting the core converters.
10
+ */
11
+ import core from './converters.js';
12
+ export const { xmlToJson, jsonToXml, removeEmpty, normaliseKeys, ensureArrays } = core;
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Convert an SCXML string to scjson.
3
+ *
4
+ * @param {string} xmlStr - XML input.
5
+ * @param {boolean} [omitEmpty=true] - Remove empty values when true.
6
+ * @returns {{result: string, valid: boolean, errors: object[]|null}} Conversion outcome.
7
+ *
8
+ * Removes the XML namespace attribute and injects default values
9
+ * expected by the schema.
10
+ */
11
+ export function xmlToJson(xmlStr: string, omitEmpty?: boolean): {
12
+ result: string;
13
+ valid: boolean;
14
+ errors: object[] | null;
15
+ };
16
+ /**
17
+ * Convert a scjson string to SCXML.
18
+ *
19
+ * Removes empty objects so that the generated XML does not include spurious
20
+ * `<content/>` elements. Nested SCXML documents are also normalised after
21
+ * restoring attribute names to ensure no stray wrapper nodes remain. The
22
+ * function validates the input against the SCJSON schema before conversion.
23
+ *
24
+ * @param {string} jsonStr - JSON input.
25
+ * @returns {{result: string, valid: boolean, errors: object[]|null}} Conversion outcome.
26
+ */
27
+ export function jsonToXml(jsonStr: string): {
28
+ result: string;
29
+ valid: boolean;
30
+ errors: object[] | null;
31
+ };
32
+ /**
33
+ * Remove nulls and empty containers from values recursively.
34
+ *
35
+ * Certain keys like ``final`` must always be preserved even when they
36
+ * would otherwise be considered empty. The caller provides the key so we
37
+ * can decide whether to keep an empty object.
38
+ *
39
+ * @param {*} value - Candidate value.
40
+ * @param {string} [key] - Key name associated with ``value`` in the parent.
41
+ * @returns {*} Sanitised value.
42
+ */
43
+ export function removeEmpty(value: any, key?: string): any;
44
+ /**
45
+ * Recursively rename XML parser keys to match the scjson schema.
46
+ *
47
+ * - Attribute names prefixed with ``@_`` are stripped of the prefix.
48
+ * - Text content keys ``#text`` are converted to a ``content`` array.
49
+ *
50
+ * @param {object|Array} value - Parsed value to normalise.
51
+ * @returns {object|Array} Normalised value.
52
+ */
53
+ export function normaliseKeys(value: object | any[]): object | any[];
54
+ /**
55
+ * Recursively normalise values that should be arrays.
56
+ *
57
+ * @param {object} obj - Parsed object to adjust in place.
58
+ */
59
+ export function ensureArrays(obj: object, parent: any): void;
60
+ /**
61
+ * Normalise script elements after parsing.
62
+ *
63
+ * Ensures that each ``script`` entry is an object with a ``content`` array
64
+ * as required by the schema.
65
+ *
66
+ * @param {object|Array} value - Parsed object to adjust in place.
67
+ */
68
+ export function fixScripts(value: object | any[]): void;
69
+ /**
70
+ * Normalise nested SCXML documents within invoke content.
71
+ *
72
+ * XML parser output represents nested ``<scxml>`` elements as a key
73
+ * named ``scxml`` inside the ``content`` element. The reference
74
+ * Python implementation instead stores the nested machine under a
75
+ * ``content`` array. This helper replicates that behaviour.
76
+ *
77
+ * @param {object|Array} value - Parsed object to adjust in place.
78
+ */
79
+ export function fixNestedScxml(value: object | any[]): void;
80
+ /**
81
+ * Apply default values for assign elements.
82
+ *
83
+ * The scjson schema expects ``assign`` elements to include a
84
+ * ``type_value`` attribute with a default of ``replacechildren``.
85
+ * This helper ensures the attribute is present when not specified in
86
+ * the original XML.
87
+ *
88
+ * @param {object|Array} value - Parsed object to adjust in place.
89
+ */
90
+ export function fixAssignDefaults(value: object | any[]): void;
91
+ /**
92
+ * Apply default values for send elements.
93
+ *
94
+ * The SCXML specification defines ``type="scxml"`` and ``delay="0s"``
95
+ * as defaults. This mirrors the behaviour of the Python converter so
96
+ * round-trip conversions remain consistent.
97
+ *
98
+ * @param {object|Array} value - Parsed object to adjust in place.
99
+ */
100
+ export function fixSendDefaults(value: object | any[]): void;
101
+ /**
102
+ * Normalise inline content elements under ``send``.
103
+ *
104
+ * ``<content>`` children inside ``<send>`` should always be objects with a
105
+ * ``content`` array according to the scjson schema. The fast-xml-parser library
106
+ * collapses simple text nodes to strings which leads to mismatches when
107
+ * compared with the Python implementation. This helper wraps such strings in an
108
+ * object structure.
109
+ *
110
+ * @param {object|Array} value - Parsed object to adjust in place.
111
+ */
112
+ export function fixSendContent(value: object | any[]): void;
113
+ /**
114
+ * Normalise inline content elements under ``donedata``.
115
+ *
116
+ * ``<content>`` children inside ``<donedata>`` should always be objects with a
117
+ * ``content`` array so that round-trips match the reference Python
118
+ * implementation. Strings are wrapped in an object accordingly.
119
+ *
120
+ * @param {object|Array} value - Parsed object to adjust in place.
121
+ */
122
+ export function fixDonedataContent(value: object | any[]): void;
123
+ /**
124
+ * Convert a canonical content object back into XML element format.
125
+ *
126
+ * ``jsonToXml`` relies on this helper to rebuild inline XML stored under
127
+ * ``<data>`` elements. Objects with ``qname``, ``attributes``, and ``children``
128
+ * fields are translated to the structure expected by ``fast-xml-parser``.
129
+ *
130
+ * @param {object} node - Canonical content object.
131
+ * @returns {object} XML builder structure keyed by element name.
132
+ */
133
+ export function restoreDataNode(node: object): object;
134
+ /**
135
+ * Collapse nested ``content`` wrappers created during parsing.
136
+ *
137
+ * A ``content`` array may contain a single object with its own
138
+ * ``content`` array when the original XML element only held text.
139
+ * This helper flattens that structure so that round-tripping through
140
+ * XML does not introduce spurious elements.
141
+ *
142
+ * @param {object|Array} value - Parsed object to adjust in place.
143
+ */
144
+ export function flattenContent(value: object | any[]): void;
145
+ /**
146
+ * Split whitespace-separated token attributes.
147
+ *
148
+ * Attributes such as ``initial`` and ``target`` can contain multiple
149
+ * identifiers separated by spaces. This function mirrors the Python
150
+ * implementation by splitting those values into arrays before further
151
+ * normalisation.
152
+ *
153
+ * @param {object|Array} value - Parsed value to adjust in place.
154
+ */
155
+ export function splitTokenAttrs(value: object | any[], parent: any): void;
156
+ /**
157
+ * Convert ``else`` elements to the ``else_value`` schema key.
158
+ *
159
+ * Empty ``<else/>`` tags become an object literal so they survive
160
+ * subsequent calls to :func:`removeEmpty`.
161
+ *
162
+ * @param {object|Array} value - Parsed object to adjust in place.
163
+ */
164
+ export function fixEmptyElse(value: object | any[]): void;
165
+ /**
166
+ * Remove transition elements directly under the <scxml> root.
167
+ *
168
+ * The reference Python implementation ignores these top level
169
+ * transitions entirely. To maintain parity we drop them during
170
+ * conversion.
171
+ *
172
+ * @param {object} obj - Parsed SCXML object.
173
+ */
174
+ export function stripRootTransitions(obj: object): void;
175
+ /**
176
+ * Remove namespace URIs from ``qname`` fields.
177
+ *
178
+ * @param {object|Array} value - Parsed object to adjust in place.
179
+ */
180
+ export function stripQnameNs(value: object | any[]): void;
181
+ /**
182
+ * Reorder SCXML object keys to match canonical output.
183
+ *
184
+ * ``datamodel`` elements and the attributes ``version`` and
185
+ * ``datamodel_attribute`` are appended to the end of their
186
+ * respective objects so that JSON generated by this converter
187
+ * matches the reference Python implementation.
188
+ *
189
+ * @param {object|Array} value - Parsed object to adjust in place.
190
+ */
191
+ export function reorderScxml(value: object | any[]): void;