@kent-tokyo/chematic 1.0.12 → 1.0.13

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
@@ -29,7 +29,8 @@ npm install @kent-tokyo/chematic
29
29
  deterministic input indices and partial/complete status; bounded malformed
30
30
  XYZ frames are grouped inline as rejected records when a later count-line
31
31
  boundary is recoverable (core file-backed readers remain fail-stop)
32
- - Bounded topology parsing for CML, ChemicalJSON (`mol_from_cjson`), MolJSON,
32
+ - Bounded topology parsing for CML (`mol_from_cml_strict` provides the opt-in
33
+ non-empty, balanced, single-root boundary), ChemicalJSON (`mol_from_cjson`), MolJSON,
33
34
  CDXML, MOL2, and PDB/mmCIF
34
35
  - PDBx/mmCIF, PQR, QCSchema JSON, ORCA input/output, Gaussian Cube, OpenDX,
35
36
  and LAMMPS data/dump I/O (JSON-based bindings; see `format_io.rs`)
@@ -167,12 +168,54 @@ portable across native and `wasm32-unknown-unknown`
167
168
  precision across every JS engine, only that the value is finite, non-negative,
168
169
  and enforced correctly on all of them.
169
170
 
171
+ ## V3000 SGROUP syntax view
172
+
173
+ `v3000_sgroups_json(block)` exposes bounded, typed SGROUP syntax without
174
+ expanding polymer or Markush semantics. It preserves source order for unknown
175
+ attributes and returns `kindToken` for unknown group kinds. Group IDs, parent
176
+ references, atom references, and grouped-field counts are validated before
177
+ JSON is returned.
178
+
179
+ ```js
180
+ const groups = JSON.parse(v3000_sgroups_json(v3000Block));
181
+ // [{ id, kind, parentId, atomIds, attributes, kindToken? }]
182
+ ```
183
+
184
+ This is a syntax-level API; it does not claim polymer expansion, Markush
185
+ interpretation, or cross-engine semantic compatibility.
186
+
170
187
  ## Bundle Size
171
188
 
172
- The optimized v1.0.10 candidate artifact was measured at **3.73 MB raw / 1.36 MB gzip**. Bundle size depends on features and toolchain; see [`benchmarks/2026-09-09-wasm-size-v1.0.10.md`](../../benchmarks/2026-09-09-wasm-size-v1.0.10.md) for exact tools, digest, and reproduction steps.
189
+ The optimized v1.0.12 artifact was measured at **3.93 MB raw / 1.43 MB gzip**. Bundle size depends on features and toolchain; see [`benchmarks/2026-09-11-official-rdkit-js-v1.0.12.md`](../../benchmarks/2026-09-11-official-rdkit-js-v1.0.12.md) for exact tools, digest, and reproduction steps.
173
190
 
174
191
  PNG rasterization (`tiny_skia`) is excluded from the WASM build — use SVG output instead. All SVG depiction APIs remain fully available.
175
192
 
193
+ ## Versioned document binding boundary
194
+
195
+ The `*_v1` document APIs provide a stable JSON boundary for downstream editors:
196
+
197
+ ```js
198
+ const parsed = JSON.parse(reaction_document_json_v1(JSON.stringify(document)));
199
+ const edited = JSON.parse(edit_reaction_document_json_v1(
200
+ JSON.stringify(parsed),
201
+ JSON.stringify({ kind: "set_step_condition", step_id: "step-1", key: "temperature", value: "25 C" }),
202
+ ));
203
+
204
+ const cdxmlEnvelope = JSON.parse(cdxml_document_json_v1(cdxml));
205
+ const cdxmlAgain = cdxml_document_from_json_v1(JSON.stringify(cdxmlEnvelope));
206
+ ```
207
+
208
+ `cdxml_document_json_v1` retains the exact `source` string and returns a
209
+ structural `document` summary with opaque objects and `diagnostics`. Use
210
+ `edit_cdxml_document_json_v1` for bounded page/object edits; it reparses the
211
+ result before returning. Errors are JSON-shaped with stable `code`, `path`, and
212
+ `message` fields (`malformed_input`, `resource_limit`,
213
+ `unsupported_construct`, `lossy_conversion`, or `serialization_error`).
214
+ `reaction_document_to_rxn_v1` and `cdxml_document_projection_json_v1` reject
215
+ lossy legacy projections with `lossy_conversion` diagnostics. These APIs do not claim
216
+ mechanism correctness, product prediction, complete stoichiometry, or full
217
+ ChemDraw/RXN compatibility.
218
+
176
219
  ## Building from source
177
220
 
178
221
  ```sh
@@ -593,6 +593,11 @@ export function canonical_tautomer_with_blocked_atoms_json(mol: MolHandle, block
593
593
  */
594
594
  export function canonicalize_smiles_batch_json(smiles_batch: string, delimiter: string): string;
595
595
 
596
+ /**
597
+ * Validate a versioned CDXML JSON envelope and serialize its exact source.
598
+ */
599
+ export function cdxml_document_from_json_v1(document_json: string): string;
600
+
596
601
  /**
597
602
  * Parse a CDXML document while preserving page and presentation objects.
598
603
  * The returned JSON contains an opaque `raw_xml` for each object so unknown
@@ -600,6 +605,22 @@ export function canonicalize_smiles_batch_json(smiles_batch: string, delimiter:
600
605
  */
601
606
  export function cdxml_document_json(cdxml: string): string;
602
607
 
608
+ /**
609
+ * Return a loss-preserving, versioned JSON envelope for a CDXML document.
610
+ *
611
+ * `source` is retained for exact re-serialization; `document` is the stable
612
+ * structural summary used by editors. Unknown objects remain in the summary
613
+ * and are listed under `document.diagnostics`.
614
+ */
615
+ export function cdxml_document_json_v1(cdxml: string): string;
616
+
617
+ /**
618
+ * Project a CDXML document to its first molecular fragment only when no
619
+ * presentation data would be lost. Unknown/presentation objects are reported
620
+ * as an explicit lossy conversion instead of being silently dropped.
621
+ */
622
+ export function cdxml_document_projection_json_v1(cdxml: string): string;
623
+
603
624
  /**
604
625
  * Parse all molecular fragments from a CDXML string.
605
626
  *
@@ -872,6 +893,18 @@ export function ecfp_bitvec_custom(mol: MolHandle, radius: number, nbits: number
872
893
  */
873
894
  export function edit_cdxml_document_json(cdxml: string, edit_json: string): string;
874
895
 
896
+ /**
897
+ * Apply a bounded CDXML edit to a versioned JSON envelope and return the
898
+ * updated envelope. The source is reparsed after editing, so paths and
899
+ * diagnostics cannot drift from the returned document summary.
900
+ */
901
+ export function edit_cdxml_document_json_v1(document_json: string, edit_json: string): string;
902
+
903
+ /**
904
+ * Apply a bounded, stable-ID reaction-document edit and return canonical JSON.
905
+ */
906
+ export function edit_reaction_document_json_v1(document_json: string, edit_json: string): string;
907
+
875
908
  /**
876
909
  * Run `embed_ensemble_v2` on `mol`'s own atom order (never canonicalizes/
877
910
  * reparses, same convention as `embed_pipeline_v2_json`). See the module doc
@@ -1456,7 +1489,7 @@ export function minimize_mmff94_lbfgs_json(mol: MolHandle, max_iter: number): st
1456
1489
  * `coords_json` — JSON array of `[x,y,z]` arrays (Å), one per atom.
1457
1490
  * `max_iter` — maximum iterations (0 = default 500).
1458
1491
  *
1459
- * Returns JSON: `{"coords":[[x,y,z],...], "energy":float, "iterations":int, "converged":bool, "sound":bool, "worst_bond_length":float}`
1492
+ * Returns JSON: `{"coords":[[x,y,z],...], "energy":float, "iterations":int, "converged":bool, "sound":bool, "worst_bond_length":float, "rejected_unsound_step":bool}`
1460
1493
  * or `{"error":"<msg>"}` on failure. `sound` is all-finite coordinates and
1461
1494
  * no bond stretched past a sane covalent-bond length — independent of
1462
1495
  * `converged`, since steepest descent often reports `converged:false` on
@@ -1619,6 +1652,14 @@ export function mol_from_cjson(json: string): MolHandle;
1619
1652
  */
1620
1653
  export function mol_from_cml(cml: string): MolHandle;
1621
1654
 
1655
+ /**
1656
+ * Parse a structurally valid, non-empty CML string into a `MolHandle`.
1657
+ *
1658
+ * This opt-in strict boundary rejects missing/empty molecules and malformed
1659
+ * XML while `mol_from_cml` retains its historical lenient behavior.
1660
+ */
1661
+ export function mol_from_cml_strict(cml: string): MolHandle;
1662
+
1622
1663
  /**
1623
1664
  * Parse a Gaussian Cube file and return a `MolHandle` (topology only --
1624
1665
  * element list, no bonds; Cube carries no bond table). Use
@@ -2167,6 +2208,21 @@ export function rdkit_rdk_bitvec(mol: MolHandle): Uint8Array;
2167
2208
  */
2168
2209
  export function rdkit_torsion_bitvec(mol: MolHandle): Uint8Array;
2169
2210
 
2211
+ /**
2212
+ * Validate and deterministically serialize a rich reaction document JSON.
2213
+ *
2214
+ * This is the versioned JSON boundary for WASM consumers. It preserves IDs,
2215
+ * metadata, and provenance, and rejects malformed documents before returning
2216
+ * JSON. Use [`edit_reaction_document_json_v1`] for bounded ID-addressed edits.
2217
+ */
2218
+ export function reaction_document_json_v1(document_json: string): string;
2219
+
2220
+ /**
2221
+ * Convert a rich reaction document to legacy RXN V2000 with structured loss
2222
+ * reporting. A lossy projection is never returned as if it were complete.
2223
+ */
2224
+ export function reaction_document_to_rxn_v1(document_json: string): string;
2225
+
2170
2226
  /**
2171
2227
  * Check whether a reaction SMILES matches a reaction SMARTS query.
2172
2228
  *
@@ -2238,13 +2294,13 @@ export function rgroup_decompose_json(smiles_json: string, core_smarts: string):
2238
2294
  export function ring_families_json(mol: MolHandle): string;
2239
2295
 
2240
2296
  /**
2241
- * Parse and serialize a V3000 block while preserving opaque V3000 metadata.
2297
+ * Parse and serialize a V3000 block while preserving V3000 metadata.
2242
2298
  *
2243
2299
  * Unlike the topology-only [`mol_from_v3000_block`] + [`to_mol_v3000_block`]
2244
2300
  * pair, this explicit round-trip API retains `SGROUP` logical lines and
2245
- * `COLLECTION` stereo groups. SGROUP semantics remain opaque until the core
2246
- * molecule model grows a typed representation; the API therefore preserves
2247
- * bytes at the logical-line level without claiming polymer/query semantics.
2301
+ * `COLLECTION` stereo groups. SGROUP polymer/query expansion is still out of
2302
+ * scope, but the typed syntax view is available through
2303
+ * [`v3000_sgroups_json`].
2248
2304
  */
2249
2305
  export function roundtrip_mol_v3000_block(block: string): string;
2250
2306
 
@@ -2655,6 +2711,8 @@ export function topo_path_bitvec(mol: MolHandle): Uint8Array;
2655
2711
  */
2656
2712
  export function torsion_bitvec(mol: MolHandle): Uint8Array;
2657
2713
 
2714
+ export function v3000_sgroups_json(block: string): string;
2715
+
2658
2716
  /**
2659
2717
  * Validate a vendor-neutral NMR spectrum JSON document without parsing a
2660
2718
  * vendor-specific raw file or predicting peaks.
@@ -2806,7 +2864,10 @@ export interface InitOutput {
2806
2864
  readonly canonical_tautomer: (a: number) => number;
2807
2865
  readonly canonical_tautomer_with_blocked_atoms_json: (a: number, b: number, c: number) => [number, number];
2808
2866
  readonly canonicalize_smiles_batch_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2867
+ readonly cdxml_document_from_json_v1: (a: number, b: number) => [number, number, number, number];
2809
2868
  readonly cdxml_document_json: (a: number, b: number) => [number, number, number, number];
2869
+ readonly cdxml_document_json_v1: (a: number, b: number) => [number, number, number, number];
2870
+ readonly cdxml_document_projection_json_v1: (a: number, b: number) => [number, number, number, number];
2810
2871
  readonly cdxml_to_smiles_json: (a: number, b: number) => [number, number, number, number];
2811
2872
  readonly charge_parent_json: (a: number) => [number, number];
2812
2873
  readonly chematic_version: () => [number, number];
@@ -2859,6 +2920,8 @@ export interface InitOutput {
2859
2920
  readonly ecfp6_bitvec_with_chirality: (a: number, b: number) => [number, number];
2860
2921
  readonly ecfp_bitvec_custom: (a: number, b: number, c: number, d: number) => [number, number];
2861
2922
  readonly edit_cdxml_document_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2923
+ readonly edit_cdxml_document_json_v1: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2924
+ readonly edit_reaction_document_json_v1: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2862
2925
  readonly embed_ensemble_v2_json: (a: number, b: number, c: number) => [number, number];
2863
2926
  readonly embed_pipeline_v2_json: (a: number, b: number, c: number) => [number, number];
2864
2927
  readonly enumerate_library_2way: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
@@ -2936,6 +2999,7 @@ export interface InitOutput {
2936
2999
  readonly mol_from_cdxml: (a: number, b: number) => [number, number, number];
2937
3000
  readonly mol_from_cjson: (a: number, b: number) => [number, number, number];
2938
3001
  readonly mol_from_cml: (a: number, b: number) => [number, number, number];
3002
+ readonly mol_from_cml_strict: (a: number, b: number) => [number, number, number];
2939
3003
  readonly mol_from_cube: (a: number, b: number) => [number, number, number];
2940
3004
  readonly mol_from_extxyz: (a: number, b: number) => [number, number, number];
2941
3005
  readonly mol_from_mmcif: (a: number, b: number) => [number, number, number];
@@ -3072,6 +3136,8 @@ export interface InitOutput {
3072
3136
  readonly rdkit_path_bitvec: (a: number) => [number, number];
3073
3137
  readonly rdkit_rdk_bitvec: (a: number) => [number, number];
3074
3138
  readonly rdkit_torsion_bitvec: (a: number) => [number, number];
3139
+ readonly reaction_document_json_v1: (a: number, b: number) => [number, number, number, number];
3140
+ readonly reaction_document_to_rxn_v1: (a: number, b: number) => [number, number, number, number];
3075
3141
  readonly reaction_smarts_match: (a: number, b: number, c: number, d: number) => [number, number, number];
3076
3142
  readonly remove_hydrogens: (a: number) => number;
3077
3143
  readonly retro_disconnect_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
@@ -3129,6 +3195,7 @@ export interface InitOutput {
3129
3195
  readonly to_xyz: (a: number) => [number, number];
3130
3196
  readonly topo_path_bitvec: (a: number) => [number, number];
3131
3197
  readonly torsion_bitvec: (a: number) => [number, number];
3198
+ readonly v3000_sgroups_json: (a: number, b: number) => [number, number, number, number];
3132
3199
  readonly validate_nmr_spectrum_json: (a: number, b: number) => [number, number];
3133
3200
  readonly virtual_screen_ecfp4_json: (a: number, b: number, c: number, d: number, e: number) => [number, number];
3134
3201
  readonly whim_descriptors_json: (a: number) => [number, number];
package/chematic_wasm.js CHANGED
@@ -1401,6 +1401,32 @@ export function canonicalize_smiles_batch_json(smiles_batch, delimiter) {
1401
1401
  }
1402
1402
  }
1403
1403
 
1404
+ /**
1405
+ * Validate a versioned CDXML JSON envelope and serialize its exact source.
1406
+ * @param {string} document_json
1407
+ * @returns {string}
1408
+ */
1409
+ export function cdxml_document_from_json_v1(document_json) {
1410
+ let deferred3_0;
1411
+ let deferred3_1;
1412
+ try {
1413
+ const ptr0 = passStringToWasm0(document_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1414
+ const len0 = WASM_VECTOR_LEN;
1415
+ const ret = wasm.cdxml_document_from_json_v1(ptr0, len0);
1416
+ var ptr2 = ret[0];
1417
+ var len2 = ret[1];
1418
+ if (ret[3]) {
1419
+ ptr2 = 0; len2 = 0;
1420
+ throw takeFromExternrefTable0(ret[2]);
1421
+ }
1422
+ deferred3_0 = ptr2;
1423
+ deferred3_1 = len2;
1424
+ return getStringFromWasm0(ptr2, len2);
1425
+ } finally {
1426
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1427
+ }
1428
+ }
1429
+
1404
1430
  /**
1405
1431
  * Parse a CDXML document while preserving page and presentation objects.
1406
1432
  * The returned JSON contains an opaque `raw_xml` for each object so unknown
@@ -1429,6 +1455,64 @@ export function cdxml_document_json(cdxml) {
1429
1455
  }
1430
1456
  }
1431
1457
 
1458
+ /**
1459
+ * Return a loss-preserving, versioned JSON envelope for a CDXML document.
1460
+ *
1461
+ * `source` is retained for exact re-serialization; `document` is the stable
1462
+ * structural summary used by editors. Unknown objects remain in the summary
1463
+ * and are listed under `document.diagnostics`.
1464
+ * @param {string} cdxml
1465
+ * @returns {string}
1466
+ */
1467
+ export function cdxml_document_json_v1(cdxml) {
1468
+ let deferred3_0;
1469
+ let deferred3_1;
1470
+ try {
1471
+ const ptr0 = passStringToWasm0(cdxml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1472
+ const len0 = WASM_VECTOR_LEN;
1473
+ const ret = wasm.cdxml_document_json_v1(ptr0, len0);
1474
+ var ptr2 = ret[0];
1475
+ var len2 = ret[1];
1476
+ if (ret[3]) {
1477
+ ptr2 = 0; len2 = 0;
1478
+ throw takeFromExternrefTable0(ret[2]);
1479
+ }
1480
+ deferred3_0 = ptr2;
1481
+ deferred3_1 = len2;
1482
+ return getStringFromWasm0(ptr2, len2);
1483
+ } finally {
1484
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1485
+ }
1486
+ }
1487
+
1488
+ /**
1489
+ * Project a CDXML document to its first molecular fragment only when no
1490
+ * presentation data would be lost. Unknown/presentation objects are reported
1491
+ * as an explicit lossy conversion instead of being silently dropped.
1492
+ * @param {string} cdxml
1493
+ * @returns {string}
1494
+ */
1495
+ export function cdxml_document_projection_json_v1(cdxml) {
1496
+ let deferred3_0;
1497
+ let deferred3_1;
1498
+ try {
1499
+ const ptr0 = passStringToWasm0(cdxml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1500
+ const len0 = WASM_VECTOR_LEN;
1501
+ const ret = wasm.cdxml_document_projection_json_v1(ptr0, len0);
1502
+ var ptr2 = ret[0];
1503
+ var len2 = ret[1];
1504
+ if (ret[3]) {
1505
+ ptr2 = 0; len2 = 0;
1506
+ throw takeFromExternrefTable0(ret[2]);
1507
+ }
1508
+ deferred3_0 = ptr2;
1509
+ deferred3_1 = len2;
1510
+ return getStringFromWasm0(ptr2, len2);
1511
+ } finally {
1512
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
1513
+ }
1514
+ }
1515
+
1432
1516
  /**
1433
1517
  * Parse all molecular fragments from a CDXML string.
1434
1518
  *
@@ -2131,6 +2215,66 @@ export function edit_cdxml_document_json(cdxml, edit_json) {
2131
2215
  }
2132
2216
  }
2133
2217
 
2218
+ /**
2219
+ * Apply a bounded CDXML edit to a versioned JSON envelope and return the
2220
+ * updated envelope. The source is reparsed after editing, so paths and
2221
+ * diagnostics cannot drift from the returned document summary.
2222
+ * @param {string} document_json
2223
+ * @param {string} edit_json
2224
+ * @returns {string}
2225
+ */
2226
+ export function edit_cdxml_document_json_v1(document_json, edit_json) {
2227
+ let deferred4_0;
2228
+ let deferred4_1;
2229
+ try {
2230
+ const ptr0 = passStringToWasm0(document_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2231
+ const len0 = WASM_VECTOR_LEN;
2232
+ const ptr1 = passStringToWasm0(edit_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2233
+ const len1 = WASM_VECTOR_LEN;
2234
+ const ret = wasm.edit_cdxml_document_json_v1(ptr0, len0, ptr1, len1);
2235
+ var ptr3 = ret[0];
2236
+ var len3 = ret[1];
2237
+ if (ret[3]) {
2238
+ ptr3 = 0; len3 = 0;
2239
+ throw takeFromExternrefTable0(ret[2]);
2240
+ }
2241
+ deferred4_0 = ptr3;
2242
+ deferred4_1 = len3;
2243
+ return getStringFromWasm0(ptr3, len3);
2244
+ } finally {
2245
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
2246
+ }
2247
+ }
2248
+
2249
+ /**
2250
+ * Apply a bounded, stable-ID reaction-document edit and return canonical JSON.
2251
+ * @param {string} document_json
2252
+ * @param {string} edit_json
2253
+ * @returns {string}
2254
+ */
2255
+ export function edit_reaction_document_json_v1(document_json, edit_json) {
2256
+ let deferred4_0;
2257
+ let deferred4_1;
2258
+ try {
2259
+ const ptr0 = passStringToWasm0(document_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2260
+ const len0 = WASM_VECTOR_LEN;
2261
+ const ptr1 = passStringToWasm0(edit_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
2262
+ const len1 = WASM_VECTOR_LEN;
2263
+ const ret = wasm.edit_reaction_document_json_v1(ptr0, len0, ptr1, len1);
2264
+ var ptr3 = ret[0];
2265
+ var len3 = ret[1];
2266
+ if (ret[3]) {
2267
+ ptr3 = 0; len3 = 0;
2268
+ throw takeFromExternrefTable0(ret[2]);
2269
+ }
2270
+ deferred4_0 = ptr3;
2271
+ deferred4_1 = len3;
2272
+ return getStringFromWasm0(ptr3, len3);
2273
+ } finally {
2274
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
2275
+ }
2276
+ }
2277
+
2134
2278
  /**
2135
2279
  * Run `embed_ensemble_v2` on `mol`'s own atom order (never canonicalizes/
2136
2280
  * reparses, same convention as `embed_pipeline_v2_json`). See the module doc
@@ -3580,7 +3724,7 @@ export function minimize_mmff94_lbfgs_json(mol, max_iter) {
3580
3724
  * `coords_json` — JSON array of `[x,y,z]` arrays (Å), one per atom.
3581
3725
  * `max_iter` — maximum iterations (0 = default 500).
3582
3726
  *
3583
- * Returns JSON: `{"coords":[[x,y,z],...], "energy":float, "iterations":int, "converged":bool, "sound":bool, "worst_bond_length":float}`
3727
+ * Returns JSON: `{"coords":[[x,y,z],...], "energy":float, "iterations":int, "converged":bool, "sound":bool, "worst_bond_length":float, "rejected_unsound_step":bool}`
3584
3728
  * or `{"error":"<msg>"}` on failure. `sound` is all-finite coordinates and
3585
3729
  * no bond stretched past a sane covalent-bond length — independent of
3586
3730
  * `converged`, since steepest descent often reports `converged:false` on
@@ -4006,6 +4150,24 @@ export function mol_from_cml(cml) {
4006
4150
  return MolHandle.__wrap(ret[0]);
4007
4151
  }
4008
4152
 
4153
+ /**
4154
+ * Parse a structurally valid, non-empty CML string into a `MolHandle`.
4155
+ *
4156
+ * This opt-in strict boundary rejects missing/empty molecules and malformed
4157
+ * XML while `mol_from_cml` retains its historical lenient behavior.
4158
+ * @param {string} cml
4159
+ * @returns {MolHandle}
4160
+ */
4161
+ export function mol_from_cml_strict(cml) {
4162
+ const ptr0 = passStringToWasm0(cml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4163
+ const len0 = WASM_VECTOR_LEN;
4164
+ const ret = wasm.mol_from_cml_strict(ptr0, len0);
4165
+ if (ret[2]) {
4166
+ throw takeFromExternrefTable0(ret[1]);
4167
+ }
4168
+ return MolHandle.__wrap(ret[0]);
4169
+ }
4170
+
4009
4171
  /**
4010
4172
  * Parse a Gaussian Cube file and return a `MolHandle` (topology only --
4011
4173
  * element list, no bonds; Cube carries no bond table). Use
@@ -5478,6 +5640,63 @@ export function rdkit_torsion_bitvec(mol) {
5478
5640
  return v1;
5479
5641
  }
5480
5642
 
5643
+ /**
5644
+ * Validate and deterministically serialize a rich reaction document JSON.
5645
+ *
5646
+ * This is the versioned JSON boundary for WASM consumers. It preserves IDs,
5647
+ * metadata, and provenance, and rejects malformed documents before returning
5648
+ * JSON. Use [`edit_reaction_document_json_v1`] for bounded ID-addressed edits.
5649
+ * @param {string} document_json
5650
+ * @returns {string}
5651
+ */
5652
+ export function reaction_document_json_v1(document_json) {
5653
+ let deferred3_0;
5654
+ let deferred3_1;
5655
+ try {
5656
+ const ptr0 = passStringToWasm0(document_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
5657
+ const len0 = WASM_VECTOR_LEN;
5658
+ const ret = wasm.reaction_document_json_v1(ptr0, len0);
5659
+ var ptr2 = ret[0];
5660
+ var len2 = ret[1];
5661
+ if (ret[3]) {
5662
+ ptr2 = 0; len2 = 0;
5663
+ throw takeFromExternrefTable0(ret[2]);
5664
+ }
5665
+ deferred3_0 = ptr2;
5666
+ deferred3_1 = len2;
5667
+ return getStringFromWasm0(ptr2, len2);
5668
+ } finally {
5669
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
5670
+ }
5671
+ }
5672
+
5673
+ /**
5674
+ * Convert a rich reaction document to legacy RXN V2000 with structured loss
5675
+ * reporting. A lossy projection is never returned as if it were complete.
5676
+ * @param {string} document_json
5677
+ * @returns {string}
5678
+ */
5679
+ export function reaction_document_to_rxn_v1(document_json) {
5680
+ let deferred3_0;
5681
+ let deferred3_1;
5682
+ try {
5683
+ const ptr0 = passStringToWasm0(document_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
5684
+ const len0 = WASM_VECTOR_LEN;
5685
+ const ret = wasm.reaction_document_to_rxn_v1(ptr0, len0);
5686
+ var ptr2 = ret[0];
5687
+ var len2 = ret[1];
5688
+ if (ret[3]) {
5689
+ ptr2 = 0; len2 = 0;
5690
+ throw takeFromExternrefTable0(ret[2]);
5691
+ }
5692
+ deferred3_0 = ptr2;
5693
+ deferred3_1 = len2;
5694
+ return getStringFromWasm0(ptr2, len2);
5695
+ } finally {
5696
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
5697
+ }
5698
+ }
5699
+
5481
5700
  /**
5482
5701
  * Check whether a reaction SMILES matches a reaction SMARTS query.
5483
5702
  *
@@ -5636,13 +5855,13 @@ export function ring_families_json(mol) {
5636
5855
  }
5637
5856
 
5638
5857
  /**
5639
- * Parse and serialize a V3000 block while preserving opaque V3000 metadata.
5858
+ * Parse and serialize a V3000 block while preserving V3000 metadata.
5640
5859
  *
5641
5860
  * Unlike the topology-only [`mol_from_v3000_block`] + [`to_mol_v3000_block`]
5642
5861
  * pair, this explicit round-trip API retains `SGROUP` logical lines and
5643
- * `COLLECTION` stereo groups. SGROUP semantics remain opaque until the core
5644
- * molecule model grows a typed representation; the API therefore preserves
5645
- * bytes at the logical-line level without claiming polymer/query semantics.
5862
+ * `COLLECTION` stereo groups. SGROUP polymer/query expansion is still out of
5863
+ * scope, but the typed syntax view is available through
5864
+ * [`v3000_sgroups_json`].
5646
5865
  * @param {string} block
5647
5866
  * @returns {string}
5648
5867
  */
@@ -6919,6 +7138,31 @@ export function torsion_bitvec(mol) {
6919
7138
  return v1;
6920
7139
  }
6921
7140
 
7141
+ /**
7142
+ * @param {string} block
7143
+ * @returns {string}
7144
+ */
7145
+ export function v3000_sgroups_json(block) {
7146
+ let deferred3_0;
7147
+ let deferred3_1;
7148
+ try {
7149
+ const ptr0 = passStringToWasm0(block, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
7150
+ const len0 = WASM_VECTOR_LEN;
7151
+ const ret = wasm.v3000_sgroups_json(ptr0, len0);
7152
+ var ptr2 = ret[0];
7153
+ var len2 = ret[1];
7154
+ if (ret[3]) {
7155
+ ptr2 = 0; len2 = 0;
7156
+ throw takeFromExternrefTable0(ret[2]);
7157
+ }
7158
+ deferred3_0 = ptr2;
7159
+ deferred3_1 = len2;
7160
+ return getStringFromWasm0(ptr2, len2);
7161
+ } finally {
7162
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
7163
+ }
7164
+ }
7165
+
6922
7166
  /**
6923
7167
  * Validate a vendor-neutral NMR spectrum JSON document without parsing a
6924
7168
  * vendor-specific raw file or predicting peaks.
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Kentaro Tanabe (kent-tokyo) <kent-tokyo@users.noreply.github.com>"
6
6
  ],
7
7
  "description": "WebAssembly bindings for chematic — use chematic from JavaScript/TypeScript",
8
- "version": "1.0.12",
8
+ "version": "1.0.13",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",