@kent-tokyo/chematic 1.0.13 → 1.0.14

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
@@ -4,6 +4,10 @@ WebAssembly bindings for [chematic](https://github.com/kent-tokyo/chematic), a p
4
4
 
5
5
  Published to npm as [`@kent-tokyo/chematic`](https://www.npmjs.com/package/@kent-tokyo/chematic).
6
6
 
7
+ The current workspace line is 1.0.14. The binding keeps bounded parsing,
8
+ typed failures, and opt-in `embed_pipeline_v2_json`; 3D/MMFF94 behavior remains
9
+ Experimental and is not a claim of full RDKit parity.
10
+
7
11
  ## Installation
8
12
 
9
13
  ```sh
@@ -100,6 +104,11 @@ console.log(mol.labute_asa()); // Labute approx. surface area
100
104
  const charges = JSON.parse(gasteiger_charges_json(mol));
101
105
  console.log(charges); // [-0.08, 0.12, -0.43, ...]
102
106
 
107
+ // Explicit RDKit-compatibility descriptor profile (kept separate from the
108
+ // historical native get_descriptors_json() profile)
109
+ const rdkitDescriptors = JSON.parse(get_rdkit_descriptors_json(mol));
110
+ console.log(rdkitDescriptors.aromatic_ring_count);
111
+
103
112
  // VSA descriptor bins
104
113
  const slogpVsa = JSON.parse(slogp_vsa_json(mol));
105
114
  const smrVsa = JSON.parse(smr_vsa_json(mol));
@@ -168,6 +177,17 @@ portable across native and `wasm32-unknown-unknown`
168
177
  precision across every JS engine, only that the value is finite, non-negative,
169
178
  and enforced correctly on all of them.
170
179
 
180
+ `nearest_neighbors_json` keeps its historical chematic-native ECFP4 profile.
181
+ For the separately named RDKit-compatible Morgan profile, use
182
+ `rdkit_nearest_neighbors_json(querySmiles, dbSmilesJson, k)`. It returns the
183
+ same `{index, tanimoto}` shape and reports preprocessing failures without
184
+ silently falling back to native ECFP4.
185
+
186
+ For repeated queries, construct `new RdkitSearchIndex(dbSmilesJson)` once and
187
+ call `index.search_json(querySmiles, k)`. The prepared index is intended for
188
+ chunked libraries up to the WASM batch limit and applies the same fail-closed
189
+ RDKit-compatible profile without rebuilding database fingerprints per query.
190
+
171
191
  ## V3000 SGROUP syntax view
172
192
 
173
193
  `v3000_sgroups_json(block)` exposes bounded, typed SGROUP syntax without
@@ -409,6 +409,10 @@ export class MolHandle {
409
409
  * Most basic pKa in the molecule, or NaN if no basic site.
410
410
  */
411
411
  pka_base_value(): number;
412
+ /**
413
+ * Atom indices of potential tetrahedral stereocenters.
414
+ */
415
+ potential_stereocenter_indices(): Uint32Array;
412
416
  /**
413
417
  * Quantitative Estimate of Drug-likeness (QED); range [0, 1].
414
418
  */
@@ -462,6 +466,47 @@ export class MolHandle {
462
466
  zagreb_index_m1(): number;
463
467
  }
464
468
 
469
+ /**
470
+ * Reusable prepared index for the RDKit-compatible Morgan profile.
471
+ *
472
+ * Build one index per input chunk (the WASM batch limit is 1,024 molecules),
473
+ * then call [`RdkitSearchIndex::search_json`] for multiple queries without
474
+ * reparsing or refingerprinting the database.
475
+ */
476
+ export class RdkitSearchIndex {
477
+ free(): void;
478
+ [Symbol.dispose](): void;
479
+ /**
480
+ * Whether the prepared index contains no molecules.
481
+ */
482
+ is_empty(): boolean;
483
+ /**
484
+ * Number of molecules in this chunk.
485
+ */
486
+ len(): number;
487
+ /**
488
+ * Build an index from a JSON array of SMILES strings.
489
+ */
490
+ constructor(db_smiles_json: string);
491
+ /**
492
+ * Search the prepared index with a query SMILES.
493
+ */
494
+ search_json(query_smiles: string, k: number): string;
495
+ /**
496
+ * Search without the historical six-decimal JSON score truncation.
497
+ *
498
+ * This opt-in endpoint is for exact parity measurements. Callers that
499
+ * need the stable historical wire format should continue using
500
+ * RdkitSearchIndex::search_json.
501
+ */
502
+ search_json_precise(query_smiles: string, k: number): string;
503
+ /**
504
+ * Search with an inclusive Tanimoto threshold and precise JSON scores.
505
+ * A threshold of `0.0` includes zero-score candidates.
506
+ */
507
+ search_json_threshold_precise(query_smiles: string, threshold: number, k: number): string;
508
+ }
509
+
465
510
  /**
466
511
  * Return a copy of the molecule with all implicit hydrogens converted to explicit H atoms.
467
512
  */
@@ -1190,6 +1235,17 @@ export function get_descriptors_json(mol: MolHandle): string;
1190
1235
  */
1191
1236
  export function get_dihedral_json(smiles: string, a: number, b: number, c: number, d: number): any;
1192
1237
 
1238
+ /**
1239
+ * RDKit-compatibility descriptor profile as JSON.
1240
+ *
1241
+ * This is deliberately separate from [`get_descriptors_json`]: the latter is
1242
+ * the historical native profile, while this profile uses the opt-in RDKit
1243
+ * molecular-weight, HBA, and aromatic-ring implementations. Keeping the
1244
+ * boundary explicit prevents a compatibility correction from silently
1245
+ * changing the browser's native descriptor contract.
1246
+ */
1247
+ export function get_rdkit_descriptors_json(mol: MolHandle): string;
1248
+
1193
1249
  /**
1194
1250
  * Compute GETAWAY descriptors (GEometry, Topology and Atom-Weights AssemblY) from 3D coords.
1195
1251
  *
@@ -2186,6 +2242,17 @@ export function rdkit_ecfp_config_chiral_detail_json(mol: MolHandle, radius: num
2186
2242
  */
2187
2243
  export function rdkit_ecfp_config_detail_json(mol: MolHandle, radius: number, nbits: number): string;
2188
2244
 
2245
+ /**
2246
+ * Find the k nearest neighbours using the RDKit-compatible Morgan/ECFP4
2247
+ * profile. This is intentionally separate from [`nearest_neighbors_json`],
2248
+ * whose historical contract uses chematic's native ECFP4 profile.
2249
+ *
2250
+ * Returns JSON with the original database indices and six-decimal Tanimoto
2251
+ * scores. Any RDKit-profile preprocessing failure is returned as an error;
2252
+ * this API never falls back to the native profile.
2253
+ */
2254
+ export function rdkit_nearest_neighbors_json(query_smiles: string, db_smiles_json: string, k: number): string;
2255
+
2189
2256
  /**
2190
2257
  * Compute the RDKit-compatible Daylight-like path fingerprint as a bit-packed
2191
2258
  * byte vector (256 bytes = 2048 bits). This is the WASM counterpart of the
@@ -2850,6 +2917,7 @@ export interface InitOutput {
2850
2917
  readonly __wbg_depictoptions_free: (a: number, b: number) => void;
2851
2918
  readonly __wbg_mhfplshhandle_free: (a: number, b: number) => void;
2852
2919
  readonly __wbg_molhandle_free: (a: number, b: number) => void;
2920
+ readonly __wbg_rdkitsearchindex_free: (a: number, b: number) => void;
2853
2921
  readonly add_hydrogens: (a: number) => number;
2854
2922
  readonly admet_profile_json: (a: number, b: number) => [number, number];
2855
2923
  readonly atom_pair_bitvec: (a: number) => [number, number];
@@ -2951,6 +3019,7 @@ export interface InitOutput {
2951
3019
  readonly get_bond_length_json: (a: number, b: number, c: number, d: number) => number;
2952
3020
  readonly get_descriptors_json: (a: number) => [number, number];
2953
3021
  readonly get_dihedral_json: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
3022
+ readonly get_rdkit_descriptors_json: (a: number) => [number, number];
2954
3023
  readonly getaway_descriptors_json: (a: number) => [number, number];
2955
3024
  readonly hdf_json: (a: number, b: number, c: number, d: bigint) => [number, number];
2956
3025
  readonly identify_functional_groups: (a: number) => [number, number];
@@ -3082,6 +3151,7 @@ export interface InitOutput {
3082
3151
  readonly molhandle_pains_passes: (a: number) => number;
3083
3152
  readonly molhandle_pka_acid_value: (a: number) => number;
3084
3153
  readonly molhandle_pka_base_value: (a: number) => number;
3154
+ readonly molhandle_potential_stereocenter_indices: (a: number) => [number, number];
3085
3155
  readonly molhandle_qed: (a: number) => number;
3086
3156
  readonly molhandle_randic_index: (a: number) => number;
3087
3157
  readonly molhandle_reos_passes: (a: number) => number;
@@ -3133,9 +3203,16 @@ export interface InitOutput {
3133
3203
  readonly rdkit_ecfp_config_chiral_bitvec: (a: number, b: number, c: number) => [number, number, number, number];
3134
3204
  readonly rdkit_ecfp_config_chiral_detail_json: (a: number, b: number, c: number) => [number, number, number, number];
3135
3205
  readonly rdkit_ecfp_config_detail_json: (a: number, b: number, c: number) => [number, number, number, number];
3206
+ readonly rdkit_nearest_neighbors_json: (a: number, b: number, c: number, d: number, e: number) => [number, number];
3136
3207
  readonly rdkit_path_bitvec: (a: number) => [number, number];
3137
3208
  readonly rdkit_rdk_bitvec: (a: number) => [number, number];
3138
3209
  readonly rdkit_torsion_bitvec: (a: number) => [number, number];
3210
+ readonly rdkitsearchindex_is_empty: (a: number) => number;
3211
+ readonly rdkitsearchindex_len: (a: number) => number;
3212
+ readonly rdkitsearchindex_new: (a: number, b: number) => [number, number, number];
3213
+ readonly rdkitsearchindex_search_json: (a: number, b: number, c: number, d: number) => [number, number];
3214
+ readonly rdkitsearchindex_search_json_precise: (a: number, b: number, c: number, d: number) => [number, number];
3215
+ readonly rdkitsearchindex_search_json_threshold_precise: (a: number, b: number, c: number, d: number, e: number) => [number, number];
3139
3216
  readonly reaction_document_json_v1: (a: number, b: number) => [number, number, number, number];
3140
3217
  readonly reaction_document_to_rxn_v1: (a: number, b: number) => [number, number, number, number];
3141
3218
  readonly reaction_smarts_match: (a: number, b: number, c: number, d: number) => [number, number, number];
package/chematic_wasm.js CHANGED
@@ -961,6 +961,16 @@ export class MolHandle {
961
961
  const ret = wasm.molhandle_pka_base_value(this.__wbg_ptr);
962
962
  return ret;
963
963
  }
964
+ /**
965
+ * Atom indices of potential tetrahedral stereocenters.
966
+ * @returns {Uint32Array}
967
+ */
968
+ potential_stereocenter_indices() {
969
+ const ret = wasm.molhandle_potential_stereocenter_indices(this.__wbg_ptr);
970
+ var v1 = getArrayU32FromWasm0(ret[0], ret[1]).slice();
971
+ wasm.__wbindgen_free(ret[0], ret[1] * 4, 4);
972
+ return v1;
973
+ }
964
974
  /**
965
975
  * Quantitative Estimate of Drug-likeness (QED); range [0, 1].
966
976
  * @returns {number}
@@ -1079,6 +1089,124 @@ export class MolHandle {
1079
1089
  }
1080
1090
  if (Symbol.dispose) MolHandle.prototype[Symbol.dispose] = MolHandle.prototype.free;
1081
1091
 
1092
+ /**
1093
+ * Reusable prepared index for the RDKit-compatible Morgan profile.
1094
+ *
1095
+ * Build one index per input chunk (the WASM batch limit is 1,024 molecules),
1096
+ * then call [`RdkitSearchIndex::search_json`] for multiple queries without
1097
+ * reparsing or refingerprinting the database.
1098
+ */
1099
+ export class RdkitSearchIndex {
1100
+ __destroy_into_raw() {
1101
+ const ptr = this.__wbg_ptr;
1102
+ this.__wbg_ptr = 0;
1103
+ RdkitSearchIndexFinalization.unregister(this);
1104
+ return ptr;
1105
+ }
1106
+ free() {
1107
+ const ptr = this.__destroy_into_raw();
1108
+ wasm.__wbg_rdkitsearchindex_free(ptr, 0);
1109
+ }
1110
+ /**
1111
+ * Whether the prepared index contains no molecules.
1112
+ * @returns {boolean}
1113
+ */
1114
+ is_empty() {
1115
+ const ret = wasm.rdkitsearchindex_is_empty(this.__wbg_ptr);
1116
+ return ret !== 0;
1117
+ }
1118
+ /**
1119
+ * Number of molecules in this chunk.
1120
+ * @returns {number}
1121
+ */
1122
+ len() {
1123
+ const ret = wasm.rdkitsearchindex_len(this.__wbg_ptr);
1124
+ return ret >>> 0;
1125
+ }
1126
+ /**
1127
+ * Build an index from a JSON array of SMILES strings.
1128
+ * @param {string} db_smiles_json
1129
+ */
1130
+ constructor(db_smiles_json) {
1131
+ const ptr0 = passStringToWasm0(db_smiles_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1132
+ const len0 = WASM_VECTOR_LEN;
1133
+ const ret = wasm.rdkitsearchindex_new(ptr0, len0);
1134
+ if (ret[2]) {
1135
+ throw takeFromExternrefTable0(ret[1]);
1136
+ }
1137
+ this.__wbg_ptr = ret[0];
1138
+ RdkitSearchIndexFinalization.register(this, this.__wbg_ptr, this);
1139
+ return this;
1140
+ }
1141
+ /**
1142
+ * Search the prepared index with a query SMILES.
1143
+ * @param {string} query_smiles
1144
+ * @param {number} k
1145
+ * @returns {string}
1146
+ */
1147
+ search_json(query_smiles, k) {
1148
+ let deferred2_0;
1149
+ let deferred2_1;
1150
+ try {
1151
+ const ptr0 = passStringToWasm0(query_smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1152
+ const len0 = WASM_VECTOR_LEN;
1153
+ const ret = wasm.rdkitsearchindex_search_json(this.__wbg_ptr, ptr0, len0, k);
1154
+ deferred2_0 = ret[0];
1155
+ deferred2_1 = ret[1];
1156
+ return getStringFromWasm0(ret[0], ret[1]);
1157
+ } finally {
1158
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1159
+ }
1160
+ }
1161
+ /**
1162
+ * Search without the historical six-decimal JSON score truncation.
1163
+ *
1164
+ * This opt-in endpoint is for exact parity measurements. Callers that
1165
+ * need the stable historical wire format should continue using
1166
+ * RdkitSearchIndex::search_json.
1167
+ * @param {string} query_smiles
1168
+ * @param {number} k
1169
+ * @returns {string}
1170
+ */
1171
+ search_json_precise(query_smiles, k) {
1172
+ let deferred2_0;
1173
+ let deferred2_1;
1174
+ try {
1175
+ const ptr0 = passStringToWasm0(query_smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1176
+ const len0 = WASM_VECTOR_LEN;
1177
+ const ret = wasm.rdkitsearchindex_search_json_precise(this.__wbg_ptr, ptr0, len0, k);
1178
+ deferred2_0 = ret[0];
1179
+ deferred2_1 = ret[1];
1180
+ return getStringFromWasm0(ret[0], ret[1]);
1181
+ } finally {
1182
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1183
+ }
1184
+ }
1185
+ /**
1186
+ * Search with an inclusive Tanimoto threshold and precise JSON scores.
1187
+ * A threshold of `0.0` includes zero-score candidates.
1188
+ * @param {string} query_smiles
1189
+ * @param {number} threshold
1190
+ * @param {number} k
1191
+ * @returns {string}
1192
+ */
1193
+ search_json_threshold_precise(query_smiles, threshold, k) {
1194
+ let deferred2_0;
1195
+ let deferred2_1;
1196
+ try {
1197
+ const ptr0 = passStringToWasm0(query_smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1198
+ const len0 = WASM_VECTOR_LEN;
1199
+ const ret = wasm.rdkitsearchindex_search_json_threshold_precise(this.__wbg_ptr, ptr0, len0, threshold, k);
1200
+ deferred2_0 = ret[0];
1201
+ deferred2_1 = ret[1];
1202
+ return getStringFromWasm0(ret[0], ret[1]);
1203
+ } finally {
1204
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1205
+ }
1206
+ }
1207
+ }
1208
+ if (Symbol.dispose) RdkitSearchIndex.prototype[Symbol.dispose] = RdkitSearchIndex.prototype.free;
1209
+
1082
1210
  /**
1083
1211
  * Return a copy of the molecule with all implicit hydrogens converted to explicit H atoms.
1084
1212
  * @param {MolHandle} mol
@@ -2998,6 +3126,31 @@ export function get_dihedral_json(smiles, a, b, c, d) {
2998
3126
  return ret;
2999
3127
  }
3000
3128
 
3129
+ /**
3130
+ * RDKit-compatibility descriptor profile as JSON.
3131
+ *
3132
+ * This is deliberately separate from [`get_descriptors_json`]: the latter is
3133
+ * the historical native profile, while this profile uses the opt-in RDKit
3134
+ * molecular-weight, HBA, and aromatic-ring implementations. Keeping the
3135
+ * boundary explicit prevents a compatibility correction from silently
3136
+ * changing the browser's native descriptor contract.
3137
+ * @param {MolHandle} mol
3138
+ * @returns {string}
3139
+ */
3140
+ export function get_rdkit_descriptors_json(mol) {
3141
+ let deferred1_0;
3142
+ let deferred1_1;
3143
+ try {
3144
+ _assertClass(mol, MolHandle);
3145
+ const ret = wasm.get_rdkit_descriptors_json(mol.__wbg_ptr);
3146
+ deferred1_0 = ret[0];
3147
+ deferred1_1 = ret[1];
3148
+ return getStringFromWasm0(ret[0], ret[1]);
3149
+ } finally {
3150
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
3151
+ }
3152
+ }
3153
+
3001
3154
  /**
3002
3155
  * Compute GETAWAY descriptors (GEometry, Topology and Atom-Weights AssemblY) from 3D coords.
3003
3156
  *
@@ -5594,6 +5747,36 @@ export function rdkit_ecfp_config_detail_json(mol, radius, nbits) {
5594
5747
  }
5595
5748
  }
5596
5749
 
5750
+ /**
5751
+ * Find the k nearest neighbours using the RDKit-compatible Morgan/ECFP4
5752
+ * profile. This is intentionally separate from [`nearest_neighbors_json`],
5753
+ * whose historical contract uses chematic's native ECFP4 profile.
5754
+ *
5755
+ * Returns JSON with the original database indices and six-decimal Tanimoto
5756
+ * scores. Any RDKit-profile preprocessing failure is returned as an error;
5757
+ * this API never falls back to the native profile.
5758
+ * @param {string} query_smiles
5759
+ * @param {string} db_smiles_json
5760
+ * @param {number} k
5761
+ * @returns {string}
5762
+ */
5763
+ export function rdkit_nearest_neighbors_json(query_smiles, db_smiles_json, k) {
5764
+ let deferred3_0;
5765
+ let deferred3_1;
5766
+ try {
5767
+ const ptr0 = passStringToWasm0(query_smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
5768
+ const len0 = WASM_VECTOR_LEN;
5769
+ const ptr1 = passStringToWasm0(db_smiles_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
5770
+ const len1 = WASM_VECTOR_LEN;
5771
+ const ret = wasm.rdkit_nearest_neighbors_json(ptr0, len0, ptr1, len1, k);
5772
+ deferred3_0 = ret[0];
5773
+ deferred3_1 = ret[1];
5774
+ return getStringFromWasm0(ret[0], ret[1]);
5775
+ } finally {
5776
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
5777
+ }
5778
+ }
5779
+
5597
5780
  /**
5598
5781
  * Compute the RDKit-compatible Daylight-like path fingerprint as a bit-packed
5599
5782
  * byte vector (256 bytes = 2048 bits). This is the WASM counterpart of the
@@ -7707,6 +7890,9 @@ const MhfpLshHandleFinalization = (typeof FinalizationRegistry === 'undefined')
7707
7890
  const MolHandleFinalization = (typeof FinalizationRegistry === 'undefined')
7708
7891
  ? { register: () => {}, unregister: () => {} }
7709
7892
  : new FinalizationRegistry(ptr => wasm.__wbg_molhandle_free(ptr, 1));
7893
+ const RdkitSearchIndexFinalization = (typeof FinalizationRegistry === 'undefined')
7894
+ ? { register: () => {}, unregister: () => {} }
7895
+ : new FinalizationRegistry(ptr => wasm.__wbg_rdkitsearchindex_free(ptr, 1));
7710
7896
 
7711
7897
  function addToExternrefTable0(obj) {
7712
7898
  const idx = wasm.__externref_table_alloc();
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.13",
8
+ "version": "1.0.14",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",