@kent-tokyo/chematic 0.4.30 → 0.7.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.
@@ -1199,7 +1199,33 @@ export function mmff94_charges_json(mol: MolHandle): string;
1199
1199
  export function mmff94_charges_typed_json(mol: MolHandle): string;
1200
1200
 
1201
1201
  /**
1202
- * Compute MMFF94 energy breakdown for current rule-based 3D geometry.
1202
+ * Compute MMFF94 energy breakdown for EXPLICIT, caller-supplied 3D
1203
+ * coordinates -- unlike `mmff94_energy_breakdown_json`, this reads the
1204
+ * geometry the caller actually has (e.g. from `pdb_coords_json`,
1205
+ * `generate_3d_coords_json`, `generate_3d_etkdg_coords_json`, or an
1206
+ * externally computed conformer) instead of silently generating a fresh
1207
+ * rule-based one, matching the Python binding's
1208
+ * `mol.mmff94_energy_breakdown(coords)` contract (issue #90).
1209
+ *
1210
+ * `coords_json` -- JSON array of `[x,y,z]` arrays (Å), one per heavy atom,
1211
+ * in the same atom order as `mol`.
1212
+ *
1213
+ * Returns JSON `{"bond":B,"angle":A,"stretch_bend":S,"torsion":T,"oop":O,
1214
+ * "vdw":V,"electrostatic":E,"total":X}` at full `f64` round-trip precision
1215
+ * (not rounded -- this API exists specifically for oracle comparison
1216
+ * against the Python binding, where 4-decimal rounding would mask
1217
+ * sub-1e-4 discrepancies), or `{"error":"<msg>"}` on malformed JSON, a
1218
+ * non-finite coordinate, or a coordinate-count/atom-count mismatch. Never
1219
+ * falls back to a generated conformer.
1220
+ */
1221
+ export function mmff94_energy_breakdown_from_coords_json(mol: MolHandle, coords_json: string): string;
1222
+
1223
+ /**
1224
+ * Computes energy on an internally generated conformer.
1225
+ * `MolHandle` stores topology only; coordinates previously read from PDB/XYZ
1226
+ * are not used by this function.
1227
+ * Use [`mmff94_energy_breakdown_from_coords_json`] for explicit coordinates.
1228
+ *
1203
1229
  * Returns JSON: {"bond":B,"angle":A,"torsion":T,"vdw":V,"elec":E,"total":X} or {"error":"..."}.
1204
1230
  */
1205
1231
  export function mmff94_energy_breakdown_json(mol: MolHandle): string;
@@ -1257,6 +1283,17 @@ export function mol_block_coords_json(mol_block: string): string;
1257
1283
  */
1258
1284
  export function mol_block_from_smiles(smiles: string): string;
1259
1285
 
1286
+ /**
1287
+ * Rejected wedge/hash stereocenters for a MOL V2000 block, as JSON.
1288
+ *
1289
+ * Companion to [`mol_from_sdf_block`]/[`mol_block_coords_json`] -- returns
1290
+ * `[{"atom_idx":N,"reason":"..."}]`, empty unless a wedge/hash bond was
1291
+ * present at some center and got rejected. See
1292
+ * `crates/chematic-py/src/formats.rs`'s `from_mol_block_with_diagnostics`
1293
+ * for the reason vocabulary (kept identical across bindings).
1294
+ */
1295
+ export function mol_block_stereo_diagnostics_json(mol_block: string): string;
1296
+
1260
1297
  /**
1261
1298
  * Only the first molecular fragment in the document is returned.
1262
1299
  * Returns a JS error if the document cannot be parsed.
@@ -1279,7 +1316,10 @@ export function mol_from_cml(cml: string): MolHandle;
1279
1316
  export function mol_from_moljson(json: string): MolHandle;
1280
1317
 
1281
1318
  /**
1282
- * Parse a PDB file and return a `MolHandle` (topology only; coordinates are discarded).
1319
+ * Parse a PDB file and return a `MolHandle` (topology only; coordinates are
1320
+ * discarded -- use [`pdb_coords_json`] to recover them in the SAME atom
1321
+ * order, and [`mmff94_energy_breakdown_from_coords_json`] to score them
1322
+ * without chematic regenerating a fresh conformer).
1283
1323
  *
1284
1324
  * Uses CONECT records for connectivity if present; otherwise infers bonds from
1285
1325
  * atom distances (the same heuristic as the internal `pdb_to_molecule` function).
@@ -1312,6 +1352,12 @@ export function mol_from_xyz(xyz: string): MolHandle;
1312
1352
  */
1313
1353
  export function mol_next_atom_idx(mol: MolHandle): number;
1314
1354
 
1355
+ /**
1356
+ * Rejected wedge/hash stereocenters for a MOL V3000 block, as JSON. Same
1357
+ * shape as [`mol_block_stereo_diagnostics_json`] but for V3000 input.
1358
+ */
1359
+ export function mol_v3000_stereo_diagnostics_json(block: string): string;
1360
+
1315
1361
  /**
1316
1362
  * Return a new `MolHandle` with one atom appended.
1317
1363
  *
@@ -1450,6 +1496,19 @@ export function parse_cxsmiles_json(s: string): string;
1450
1496
  */
1451
1497
  export function parse_smiles(s: string): MolHandle;
1452
1498
 
1499
+ /**
1500
+ * Extract the atomic coordinates from a PDB block, in the SAME atom order
1501
+ * `mol_from_pdb` returns topology for (both read the identical underlying
1502
+ * parse via `parse_pdb_molecule_and_coords`, so atom-index correspondence
1503
+ * between the two calls is structural, not just conventional -- issue #90).
1504
+ *
1505
+ * Returns JSON `[[x,y,z],...]` (full `f64` precision, not rounded -- for
1506
+ * oracle comparison against the Python binding) or `{"error":"<msg>"}` --
1507
+ * including when a coordinate field parsed to a non-finite value (see
1508
+ * `coords_all_finite`'s doc comment), rather than emitting invalid JSON.
1509
+ */
1510
+ export function pdb_coords_json(pdb: string): string;
1511
+
1453
1512
  /**
1454
1513
  * PEOE_VSA descriptors (14 bins) as a JSON array.
1455
1514
  */
@@ -1500,6 +1559,54 @@ export function predict_pka_json(smiles: string): string;
1500
1559
  */
1501
1560
  export function random_smiles_json(smiles: string, count: number, seed: bigint): string;
1502
1561
 
1562
+ /**
1563
+ * RDKit-bit-exact ECFP4 (radius=2, 2048 bits, `useChirality=false`, `useBondTypes=true`,
1564
+ * RDKit's default atom invariant) as a bit-packed byte vector (256 bytes = 2048 bits).
1565
+ *
1566
+ * Bit-for-bit identical to
1567
+ * `rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048).GetFingerprint(mol)`
1568
+ * for every input this preprocessing handles. **Not** the same bits as `ecfp4_bitvec`
1569
+ * (that path uses chematic's own FNV-1a hash and is not RDKit-bit-compatible by
1570
+ * design -- the two are never silently interchanged).
1571
+ *
1572
+ * Returns a JS error (its string carrying `RdkitMorganError`'s `Display` text, e.g.
1573
+ * `"rdkit-exact ecfp4: aromaticity: ..."`) if RDKit-parity aromaticity preprocessing
1574
+ * fails, never a silent fallback to `ecfp4_bitvec`'s Hückel-based engine -- the two
1575
+ * engines are not bit-compatible, so a silent substitution would look successful
1576
+ * while actually returning the wrong hash. See `docs/ecfp4_bitexact_api_rfc.md`.
1577
+ */
1578
+ export function rdkit_ecfp4_bitvec(mol: MolHandle): Uint8Array;
1579
+
1580
+ /**
1581
+ * Same fingerprint as `rdkit_ecfp4_bitvec`, plus the raw (unfolded) data behind it, as
1582
+ * JSON: `{"fingerprint":[u8,...],"sparseCounts":{"rawId":count,...},
1583
+ * "rawBitInfo":{"rawId":[[atomIdx,radius],...],...},
1584
+ * "foldedBitInfo":{"bit":[[atomIdx,radius],...],...}}`.
1585
+ *
1586
+ * Returns a JS error on the same preprocessing failures as `rdkit_ecfp4_bitvec`.
1587
+ */
1588
+ export function rdkit_ecfp4_detail_json(mol: MolHandle): string;
1589
+
1590
+ /**
1591
+ * RDKit-bit-exact Morgan/ECFP fingerprint at a caller-chosen radius/bit-width, as a
1592
+ * bit-packed byte vector (`nbits / 8` bytes, LSB-first).
1593
+ *
1594
+ * `radius` must be 0, 1, 2 (`rdkit_ecfp4_bitvec`'s ECFP4), or 3. `nbits` must be one
1595
+ * of 128, 256, 512, 1024, or 2048. Each of these 20 combinations is independently
1596
+ * re-verified against a live RDKit oracle (not assumed to generalize from
1597
+ * radius=2/2048 bits alone) -- see `validation/ecfp4_rdkit_stable_api_fixtures.json`.
1598
+ * An unsupported value returns a JS error rather than being silently coerced to the
1599
+ * nearest supported one.
1600
+ */
1601
+ export function rdkit_ecfp_config_bitvec(mol: MolHandle, radius: number, nbits: number): Uint8Array;
1602
+
1603
+ /**
1604
+ * Same fingerprint as `rdkit_ecfp_config_bitvec`, plus the raw (unfolded) data -- see
1605
+ * `rdkit_ecfp4_detail_json` for the JSON shape (identical, generalized to this
1606
+ * function's `radius`/`nbits`).
1607
+ */
1608
+ export function rdkit_ecfp_config_detail_json(mol: MolHandle, radius: number, nbits: number): string;
1609
+
1503
1610
  /**
1504
1611
  * Return a copy of the molecule with all explicit hydrogen atoms removed.
1505
1612
  */
@@ -1588,11 +1695,15 @@ export function sdf_from_records_json(smiles_json: string, names_json: string, p
1588
1695
  *
1589
1696
  * Each record has the shape:
1590
1697
  * ```json
1591
- * {"smiles":"CC(=O)O","name":"aspirin","properties":{"MW":"180.2","Activity":"high"}}
1698
+ * {"smiles":"CC(=O)O","name":"aspirin","properties":{"MW":"180.2","Activity":"high"},"stereo_diagnostics":[]}
1592
1699
  * ```
1593
1700
  *
1594
1701
  * Invalid records are represented as `null`. SD data fields are included in
1595
- * `properties`; multi-line values are joined with `\n`.
1702
+ * `properties`; multi-line values are joined with `\n`. `stereo_diagnostics`
1703
+ * is a list of `{"atom_idx":N,"reason":"..."}` objects, one per rejected
1704
+ * wedge/hash center (see [`mol_block_stereo_diagnostics_json`] for the
1705
+ * reason vocabulary) -- empty unless a wedge/hash bond was present at some
1706
+ * center and got rejected.
1596
1707
  */
1597
1708
  export function sdf_to_records_json(sdf: string): string;
1598
1709
 
@@ -1987,12 +2098,14 @@ export interface InitOutput {
1987
2098
  readonly minimize_uff_json: (a: number, b: number, c: number, d: number, e: number) => [number, number];
1988
2099
  readonly mmff94_charges_json: (a: number) => [number, number];
1989
2100
  readonly mmff94_charges_typed_json: (a: number) => [number, number];
2101
+ readonly mmff94_energy_breakdown_from_coords_json: (a: number, b: number, c: number) => [number, number];
1990
2102
  readonly mmff94_energy_breakdown_json: (a: number) => [number, number];
1991
2103
  readonly mmff94_partial_charges_json: (a: number) => [number, number];
1992
2104
  readonly mmp_pairs_json: (a: number, b: number) => [number, number, number, number];
1993
2105
  readonly mol2_to_smiles: (a: number, b: number) => [number, number];
1994
2106
  readonly mol_block_coords_json: (a: number, b: number) => [number, number, number, number];
1995
2107
  readonly mol_block_from_smiles: (a: number, b: number) => [number, number, number, number];
2108
+ readonly mol_block_stereo_diagnostics_json: (a: number, b: number) => [number, number, number, number];
1996
2109
  readonly mol_from_cdxml: (a: number, b: number) => [number, number, number];
1997
2110
  readonly mol_from_cml: (a: number, b: number) => [number, number, number];
1998
2111
  readonly mol_from_moljson: (a: number, b: number) => [number, number, number];
@@ -2001,6 +2114,7 @@ export interface InitOutput {
2001
2114
  readonly mol_from_v3000_block: (a: number, b: number) => [number, number, number];
2002
2115
  readonly mol_from_xyz: (a: number, b: number) => [number, number, number];
2003
2116
  readonly mol_next_atom_idx: (a: number) => number;
2117
+ readonly mol_v3000_stereo_diagnostics_json: (a: number, b: number) => [number, number, number, number];
2004
2118
  readonly mol_with_atom_added: (a: number, b: number, c: number) => [number, number, number];
2005
2119
  readonly mol_with_atom_charge: (a: number, b: number, c: number) => [number, number, number];
2006
2120
  readonly mol_with_atom_element: (a: number, b: number, c: number, d: number) => [number, number, number];
@@ -2091,12 +2205,17 @@ export interface InitOutput {
2091
2205
  readonly parse_cxsmarts_json: (a: number, b: number) => [number, number, number, number];
2092
2206
  readonly parse_cxsmiles_json: (a: number, b: number) => [number, number, number, number];
2093
2207
  readonly parse_smiles: (a: number, b: number) => [number, number, number];
2208
+ readonly pdb_coords_json: (a: number, b: number) => [number, number];
2094
2209
  readonly peoe_vsa_json: (a: number) => [number, number];
2095
2210
  readonly pharmacophore_features_json: (a: number) => [number, number];
2096
2211
  readonly pharmacophore_fp_2d_summary: (a: number) => [number, number];
2097
2212
  readonly pharmacophore_fp_3d_summary: (a: number) => [number, number];
2098
2213
  readonly predict_pka_json: (a: number, b: number) => [number, number];
2099
2214
  readonly random_smiles_json: (a: number, b: number, c: number, d: bigint) => [number, number, number, number];
2215
+ readonly rdkit_ecfp4_bitvec: (a: number) => [number, number, number, number];
2216
+ readonly rdkit_ecfp4_detail_json: (a: number) => [number, number, number, number];
2217
+ readonly rdkit_ecfp_config_bitvec: (a: number, b: number, c: number) => [number, number, number, number];
2218
+ readonly rdkit_ecfp_config_detail_json: (a: number, b: number, c: number) => [number, number, number, number];
2100
2219
  readonly remove_hydrogens: (a: number) => number;
2101
2220
  readonly rgroup_decompose_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
2102
2221
  readonly ring_families_json: (a: number) => [number, number, number, number];
package/chematic_wasm.js CHANGED
@@ -2970,7 +2970,50 @@ export function mmff94_charges_typed_json(mol) {
2970
2970
  }
2971
2971
 
2972
2972
  /**
2973
- * Compute MMFF94 energy breakdown for current rule-based 3D geometry.
2973
+ * Compute MMFF94 energy breakdown for EXPLICIT, caller-supplied 3D
2974
+ * coordinates -- unlike `mmff94_energy_breakdown_json`, this reads the
2975
+ * geometry the caller actually has (e.g. from `pdb_coords_json`,
2976
+ * `generate_3d_coords_json`, `generate_3d_etkdg_coords_json`, or an
2977
+ * externally computed conformer) instead of silently generating a fresh
2978
+ * rule-based one, matching the Python binding's
2979
+ * `mol.mmff94_energy_breakdown(coords)` contract (issue #90).
2980
+ *
2981
+ * `coords_json` -- JSON array of `[x,y,z]` arrays (Å), one per heavy atom,
2982
+ * in the same atom order as `mol`.
2983
+ *
2984
+ * Returns JSON `{"bond":B,"angle":A,"stretch_bend":S,"torsion":T,"oop":O,
2985
+ * "vdw":V,"electrostatic":E,"total":X}` at full `f64` round-trip precision
2986
+ * (not rounded -- this API exists specifically for oracle comparison
2987
+ * against the Python binding, where 4-decimal rounding would mask
2988
+ * sub-1e-4 discrepancies), or `{"error":"<msg>"}` on malformed JSON, a
2989
+ * non-finite coordinate, or a coordinate-count/atom-count mismatch. Never
2990
+ * falls back to a generated conformer.
2991
+ * @param {MolHandle} mol
2992
+ * @param {string} coords_json
2993
+ * @returns {string}
2994
+ */
2995
+ export function mmff94_energy_breakdown_from_coords_json(mol, coords_json) {
2996
+ let deferred2_0;
2997
+ let deferred2_1;
2998
+ try {
2999
+ _assertClass(mol, MolHandle);
3000
+ const ptr0 = passStringToWasm0(coords_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3001
+ const len0 = WASM_VECTOR_LEN;
3002
+ const ret = wasm.mmff94_energy_breakdown_from_coords_json(mol.__wbg_ptr, ptr0, len0);
3003
+ deferred2_0 = ret[0];
3004
+ deferred2_1 = ret[1];
3005
+ return getStringFromWasm0(ret[0], ret[1]);
3006
+ } finally {
3007
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
3008
+ }
3009
+ }
3010
+
3011
+ /**
3012
+ * Computes energy on an internally generated conformer.
3013
+ * `MolHandle` stores topology only; coordinates previously read from PDB/XYZ
3014
+ * are not used by this function.
3015
+ * Use [`mmff94_energy_breakdown_from_coords_json`] for explicit coordinates.
3016
+ *
2974
3017
  * Returns JSON: {"bond":B,"angle":A,"torsion":T,"vdw":V,"elec":E,"total":X} or {"error":"..."}.
2975
3018
  * @param {MolHandle} mol
2976
3019
  * @returns {string}
@@ -3134,6 +3177,38 @@ export function mol_block_from_smiles(smiles) {
3134
3177
  }
3135
3178
  }
3136
3179
 
3180
+ /**
3181
+ * Rejected wedge/hash stereocenters for a MOL V2000 block, as JSON.
3182
+ *
3183
+ * Companion to [`mol_from_sdf_block`]/[`mol_block_coords_json`] -- returns
3184
+ * `[{"atom_idx":N,"reason":"..."}]`, empty unless a wedge/hash bond was
3185
+ * present at some center and got rejected. See
3186
+ * `crates/chematic-py/src/formats.rs`'s `from_mol_block_with_diagnostics`
3187
+ * for the reason vocabulary (kept identical across bindings).
3188
+ * @param {string} mol_block
3189
+ * @returns {string}
3190
+ */
3191
+ export function mol_block_stereo_diagnostics_json(mol_block) {
3192
+ let deferred3_0;
3193
+ let deferred3_1;
3194
+ try {
3195
+ const ptr0 = passStringToWasm0(mol_block, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3196
+ const len0 = WASM_VECTOR_LEN;
3197
+ const ret = wasm.mol_block_stereo_diagnostics_json(ptr0, len0);
3198
+ var ptr2 = ret[0];
3199
+ var len2 = ret[1];
3200
+ if (ret[3]) {
3201
+ ptr2 = 0; len2 = 0;
3202
+ throw takeFromExternrefTable0(ret[2]);
3203
+ }
3204
+ deferred3_0 = ptr2;
3205
+ deferred3_1 = len2;
3206
+ return getStringFromWasm0(ptr2, len2);
3207
+ } finally {
3208
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
3209
+ }
3210
+ }
3211
+
3137
3212
  /**
3138
3213
  * Only the first molecular fragment in the document is returned.
3139
3214
  * Returns a JS error if the document cannot be parsed.
@@ -3186,7 +3261,10 @@ export function mol_from_moljson(json) {
3186
3261
  }
3187
3262
 
3188
3263
  /**
3189
- * Parse a PDB file and return a `MolHandle` (topology only; coordinates are discarded).
3264
+ * Parse a PDB file and return a `MolHandle` (topology only; coordinates are
3265
+ * discarded -- use [`pdb_coords_json`] to recover them in the SAME atom
3266
+ * order, and [`mmff94_energy_breakdown_from_coords_json`] to score them
3267
+ * without chematic regenerating a fresh conformer).
3190
3268
  *
3191
3269
  * Uses CONECT records for connectivity if present; otherwise infers bonds from
3192
3270
  * atom distances (the same heuristic as the internal `pdb_to_molecule` function).
@@ -3262,6 +3340,33 @@ export function mol_next_atom_idx(mol) {
3262
3340
  return ret >>> 0;
3263
3341
  }
3264
3342
 
3343
+ /**
3344
+ * Rejected wedge/hash stereocenters for a MOL V3000 block, as JSON. Same
3345
+ * shape as [`mol_block_stereo_diagnostics_json`] but for V3000 input.
3346
+ * @param {string} block
3347
+ * @returns {string}
3348
+ */
3349
+ export function mol_v3000_stereo_diagnostics_json(block) {
3350
+ let deferred3_0;
3351
+ let deferred3_1;
3352
+ try {
3353
+ const ptr0 = passStringToWasm0(block, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3354
+ const len0 = WASM_VECTOR_LEN;
3355
+ const ret = wasm.mol_v3000_stereo_diagnostics_json(ptr0, len0);
3356
+ var ptr2 = ret[0];
3357
+ var len2 = ret[1];
3358
+ if (ret[3]) {
3359
+ ptr2 = 0; len2 = 0;
3360
+ throw takeFromExternrefTable0(ret[2]);
3361
+ }
3362
+ deferred3_0 = ptr2;
3363
+ deferred3_1 = len2;
3364
+ return getStringFromWasm0(ptr2, len2);
3365
+ } finally {
3366
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
3367
+ }
3368
+ }
3369
+
3265
3370
  /**
3266
3371
  * Return a new `MolHandle` with one atom appended.
3267
3372
  *
@@ -3656,6 +3761,34 @@ export function parse_smiles(s) {
3656
3761
  return MolHandle.__wrap(ret[0]);
3657
3762
  }
3658
3763
 
3764
+ /**
3765
+ * Extract the atomic coordinates from a PDB block, in the SAME atom order
3766
+ * `mol_from_pdb` returns topology for (both read the identical underlying
3767
+ * parse via `parse_pdb_molecule_and_coords`, so atom-index correspondence
3768
+ * between the two calls is structural, not just conventional -- issue #90).
3769
+ *
3770
+ * Returns JSON `[[x,y,z],...]` (full `f64` precision, not rounded -- for
3771
+ * oracle comparison against the Python binding) or `{"error":"<msg>"}` --
3772
+ * including when a coordinate field parsed to a non-finite value (see
3773
+ * `coords_all_finite`'s doc comment), rather than emitting invalid JSON.
3774
+ * @param {string} pdb
3775
+ * @returns {string}
3776
+ */
3777
+ export function pdb_coords_json(pdb) {
3778
+ let deferred2_0;
3779
+ let deferred2_1;
3780
+ try {
3781
+ const ptr0 = passStringToWasm0(pdb, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
3782
+ const len0 = WASM_VECTOR_LEN;
3783
+ const ret = wasm.pdb_coords_json(ptr0, len0);
3784
+ deferred2_0 = ret[0];
3785
+ deferred2_1 = ret[1];
3786
+ return getStringFromWasm0(ret[0], ret[1]);
3787
+ } finally {
3788
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
3789
+ }
3790
+ }
3791
+
3659
3792
  /**
3660
3793
  * PEOE_VSA descriptors (14 bins) as a JSON array.
3661
3794
  * @param {MolHandle} mol
@@ -3800,6 +3933,120 @@ export function random_smiles_json(smiles, count, seed) {
3800
3933
  }
3801
3934
  }
3802
3935
 
3936
+ /**
3937
+ * RDKit-bit-exact ECFP4 (radius=2, 2048 bits, `useChirality=false`, `useBondTypes=true`,
3938
+ * RDKit's default atom invariant) as a bit-packed byte vector (256 bytes = 2048 bits).
3939
+ *
3940
+ * Bit-for-bit identical to
3941
+ * `rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048).GetFingerprint(mol)`
3942
+ * for every input this preprocessing handles. **Not** the same bits as `ecfp4_bitvec`
3943
+ * (that path uses chematic's own FNV-1a hash and is not RDKit-bit-compatible by
3944
+ * design -- the two are never silently interchanged).
3945
+ *
3946
+ * Returns a JS error (its string carrying `RdkitMorganError`'s `Display` text, e.g.
3947
+ * `"rdkit-exact ecfp4: aromaticity: ..."`) if RDKit-parity aromaticity preprocessing
3948
+ * fails, never a silent fallback to `ecfp4_bitvec`'s Hückel-based engine -- the two
3949
+ * engines are not bit-compatible, so a silent substitution would look successful
3950
+ * while actually returning the wrong hash. See `docs/ecfp4_bitexact_api_rfc.md`.
3951
+ * @param {MolHandle} mol
3952
+ * @returns {Uint8Array}
3953
+ */
3954
+ export function rdkit_ecfp4_bitvec(mol) {
3955
+ _assertClass(mol, MolHandle);
3956
+ const ret = wasm.rdkit_ecfp4_bitvec(mol.__wbg_ptr);
3957
+ if (ret[3]) {
3958
+ throw takeFromExternrefTable0(ret[2]);
3959
+ }
3960
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
3961
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
3962
+ return v1;
3963
+ }
3964
+
3965
+ /**
3966
+ * Same fingerprint as `rdkit_ecfp4_bitvec`, plus the raw (unfolded) data behind it, as
3967
+ * JSON: `{"fingerprint":[u8,...],"sparseCounts":{"rawId":count,...},
3968
+ * "rawBitInfo":{"rawId":[[atomIdx,radius],...],...},
3969
+ * "foldedBitInfo":{"bit":[[atomIdx,radius],...],...}}`.
3970
+ *
3971
+ * Returns a JS error on the same preprocessing failures as `rdkit_ecfp4_bitvec`.
3972
+ * @param {MolHandle} mol
3973
+ * @returns {string}
3974
+ */
3975
+ export function rdkit_ecfp4_detail_json(mol) {
3976
+ let deferred2_0;
3977
+ let deferred2_1;
3978
+ try {
3979
+ _assertClass(mol, MolHandle);
3980
+ const ret = wasm.rdkit_ecfp4_detail_json(mol.__wbg_ptr);
3981
+ var ptr1 = ret[0];
3982
+ var len1 = ret[1];
3983
+ if (ret[3]) {
3984
+ ptr1 = 0; len1 = 0;
3985
+ throw takeFromExternrefTable0(ret[2]);
3986
+ }
3987
+ deferred2_0 = ptr1;
3988
+ deferred2_1 = len1;
3989
+ return getStringFromWasm0(ptr1, len1);
3990
+ } finally {
3991
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
3992
+ }
3993
+ }
3994
+
3995
+ /**
3996
+ * RDKit-bit-exact Morgan/ECFP fingerprint at a caller-chosen radius/bit-width, as a
3997
+ * bit-packed byte vector (`nbits / 8` bytes, LSB-first).
3998
+ *
3999
+ * `radius` must be 0, 1, 2 (`rdkit_ecfp4_bitvec`'s ECFP4), or 3. `nbits` must be one
4000
+ * of 128, 256, 512, 1024, or 2048. Each of these 20 combinations is independently
4001
+ * re-verified against a live RDKit oracle (not assumed to generalize from
4002
+ * radius=2/2048 bits alone) -- see `validation/ecfp4_rdkit_stable_api_fixtures.json`.
4003
+ * An unsupported value returns a JS error rather than being silently coerced to the
4004
+ * nearest supported one.
4005
+ * @param {MolHandle} mol
4006
+ * @param {number} radius
4007
+ * @param {number} nbits
4008
+ * @returns {Uint8Array}
4009
+ */
4010
+ export function rdkit_ecfp_config_bitvec(mol, radius, nbits) {
4011
+ _assertClass(mol, MolHandle);
4012
+ const ret = wasm.rdkit_ecfp_config_bitvec(mol.__wbg_ptr, radius, nbits);
4013
+ if (ret[3]) {
4014
+ throw takeFromExternrefTable0(ret[2]);
4015
+ }
4016
+ var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
4017
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
4018
+ return v1;
4019
+ }
4020
+
4021
+ /**
4022
+ * Same fingerprint as `rdkit_ecfp_config_bitvec`, plus the raw (unfolded) data -- see
4023
+ * `rdkit_ecfp4_detail_json` for the JSON shape (identical, generalized to this
4024
+ * function's `radius`/`nbits`).
4025
+ * @param {MolHandle} mol
4026
+ * @param {number} radius
4027
+ * @param {number} nbits
4028
+ * @returns {string}
4029
+ */
4030
+ export function rdkit_ecfp_config_detail_json(mol, radius, nbits) {
4031
+ let deferred2_0;
4032
+ let deferred2_1;
4033
+ try {
4034
+ _assertClass(mol, MolHandle);
4035
+ const ret = wasm.rdkit_ecfp_config_detail_json(mol.__wbg_ptr, radius, nbits);
4036
+ var ptr1 = ret[0];
4037
+ var len1 = ret[1];
4038
+ if (ret[3]) {
4039
+ ptr1 = 0; len1 = 0;
4040
+ throw takeFromExternrefTable0(ret[2]);
4041
+ }
4042
+ deferred2_0 = ptr1;
4043
+ deferred2_1 = len1;
4044
+ return getStringFromWasm0(ptr1, len1);
4045
+ } finally {
4046
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
4047
+ }
4048
+ }
4049
+
3803
4050
  /**
3804
4051
  * Return a copy of the molecule with all explicit hydrogen atoms removed.
3805
4052
  * @param {MolHandle} mol
@@ -4013,11 +4260,15 @@ export function sdf_from_records_json(smiles_json, names_json, props_json) {
4013
4260
  *
4014
4261
  * Each record has the shape:
4015
4262
  * ```json
4016
- * {"smiles":"CC(=O)O","name":"aspirin","properties":{"MW":"180.2","Activity":"high"}}
4263
+ * {"smiles":"CC(=O)O","name":"aspirin","properties":{"MW":"180.2","Activity":"high"},"stereo_diagnostics":[]}
4017
4264
  * ```
4018
4265
  *
4019
4266
  * Invalid records are represented as `null`. SD data fields are included in
4020
- * `properties`; multi-line values are joined with `\n`.
4267
+ * `properties`; multi-line values are joined with `\n`. `stereo_diagnostics`
4268
+ * is a list of `{"atom_idx":N,"reason":"..."}` objects, one per rejected
4269
+ * wedge/hash center (see [`mol_block_stereo_diagnostics_json`] for the
4270
+ * reason vocabulary) -- empty unless a wedge/hash bond was present at some
4271
+ * center and got rejected.
4021
4272
  * @param {string} sdf
4022
4273
  * @returns {string}
4023
4274
  */
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "kent-tokyo <kent-tokyo@users.noreply.github.com>"
6
6
  ],
7
7
  "description": "WebAssembly bindings for chematic — use chematic from JavaScript/TypeScript",
8
- "version": "0.4.30",
8
+ "version": "0.7.0",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",