@toolpath/tool-scraper 0.1.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +41 -11
  2. package/dist/columns.d.ts +64 -0
  3. package/dist/columns.js +68 -0
  4. package/dist/conventions.d.ts +107 -15
  5. package/dist/conventions.js +126 -15
  6. package/dist/errors.d.ts +30 -0
  7. package/dist/errors.js +30 -0
  8. package/dist/families/emuge.d.ts +185 -0
  9. package/dist/families/emuge.js +163 -0
  10. package/dist/families/harvey.d.ts +1782 -0
  11. package/dist/families/harvey.js +1328 -0
  12. package/dist/families/index.js +5 -2
  13. package/dist/families/kennametal.d.ts +21 -0
  14. package/dist/families/kennametal.js +10 -0
  15. package/dist/families/maritool.d.ts +120 -0
  16. package/dist/families/maritool.js +175 -0
  17. package/dist/family.d.ts +35 -1
  18. package/dist/family.js +28 -0
  19. package/dist/identity.d.ts +18 -0
  20. package/dist/identity.js +46 -0
  21. package/dist/index.d.ts +16 -0
  22. package/dist/index.js +16 -0
  23. package/dist/measure.d.ts +112 -0
  24. package/dist/measure.js +130 -0
  25. package/dist/node/cli.d.ts +3 -0
  26. package/dist/node/cli.js +158 -3
  27. package/dist/node/main.js +0 -0
  28. package/dist/records.d.ts +214 -12
  29. package/dist/records.js +140 -5
  30. package/dist/registry.d.ts +56 -1
  31. package/dist/registry.js +79 -2
  32. package/dist/scrape.d.ts +15 -0
  33. package/dist/scrape.js +24 -0
  34. package/dist/vendors/destinytool/records.d.ts +13 -3
  35. package/dist/vendors/destinytool/records.js +49 -37
  36. package/dist/vendors/emuge/index.d.ts +17 -0
  37. package/dist/vendors/emuge/index.js +17 -0
  38. package/dist/vendors/emuge/records.d.ts +230 -0
  39. package/dist/vendors/emuge/records.js +543 -0
  40. package/dist/vendors/emuge/scrape.d.ts +227 -0
  41. package/dist/vendors/emuge/scrape.js +358 -0
  42. package/dist/vendors/emuge/value.d.ts +75 -0
  43. package/dist/vendors/emuge/value.js +116 -0
  44. package/dist/vendors/harvey/catalog.d.ts +53 -0
  45. package/dist/vendors/harvey/catalog.js +120 -0
  46. package/dist/vendors/harvey/header.d.ts +89 -0
  47. package/dist/vendors/harvey/header.js +185 -0
  48. package/dist/vendors/harvey/index.d.ts +21 -0
  49. package/dist/vendors/harvey/index.js +21 -0
  50. package/dist/vendors/harvey/lexicon.d.ts +73 -0
  51. package/dist/vendors/harvey/lexicon.js +126 -0
  52. package/dist/vendors/harvey/literal.d.ts +68 -0
  53. package/dist/vendors/harvey/literal.js +214 -0
  54. package/dist/vendors/harvey/records.d.ts +79 -0
  55. package/dist/vendors/harvey/records.js +163 -0
  56. package/dist/vendors/harvey/scrape.d.ts +187 -0
  57. package/dist/vendors/harvey/scrape.js +483 -0
  58. package/dist/vendors/harvey/value.d.ts +74 -0
  59. package/dist/vendors/harvey/value.js +119 -0
  60. package/dist/vendors/kennametal/family.d.ts +119 -0
  61. package/dist/vendors/kennametal/family.js +155 -0
  62. package/dist/vendors/kennametal/index.d.ts +1 -0
  63. package/dist/vendors/kennametal/index.js +1 -0
  64. package/dist/vendors/kennametal/records.d.ts +29 -4
  65. package/dist/vendors/kennametal/records.js +93 -26
  66. package/dist/vendors/kennametal/scrape.d.ts +25 -2
  67. package/dist/vendors/kennametal/scrape.js +28 -3
  68. package/dist/vendors/maritool/catalog.d.ts +81 -0
  69. package/dist/vendors/maritool/catalog.js +132 -0
  70. package/dist/vendors/maritool/index.d.ts +10 -0
  71. package/dist/vendors/maritool/index.js +10 -0
  72. package/dist/vendors/maritool/scrape.d.ts +297 -0
  73. package/dist/vendors/maritool/scrape.js +593 -0
  74. package/dist/vendors/regofix/scrape.d.ts +8 -11
  75. package/dist/vendors/regofix/scrape.js +21 -36
  76. package/package.json +31 -7
@@ -53,11 +53,12 @@
53
53
  * (`1715.08215` and `1725.08215`). This is why the nominal size is parsed
54
54
  * from the vendor's own designation and `o_mm` is only ever a cross-check.
55
55
  */
56
- import { CAD_COLUMN, DIN_PREFIX } from '../../conventions.js';
56
+ import { CAD_COLUMN, COLLET_SERIES_COLUMN, CONTACT_COLUMN, DIN_PREFIX, GAGE_COLUMNS, } from '../../conventions.js';
57
57
  import { VendorResponseError } from '../../errors.js';
58
58
  import { statusOf } from '../../fetch.js';
59
- import { consoleWarn } from '../../scrape.js';
60
- export const MM_PER_INCH = 25.4;
59
+ import { convertLength, fractionValue } from '../../measure.js';
60
+ import { compare } from '../../order.js';
61
+ import { consoleWarn, unionHeader, } from '../../scrape.js';
61
62
  /**
62
63
  * The Searchkit proxy the ProductFinder posts its Elasticsearch queries to.
63
64
  * Discovered by reading the app bundle, which constructs
@@ -249,15 +250,17 @@ export function plain(value) {
249
250
  return '';
250
251
  return String(value);
251
252
  }
252
- /** `1/4` or `3.5` — the vendor prints both, and both are exact here. */
253
+ /**
254
+ * `1/4` or `3.5` — the vendor prints both, and both are exact here.
255
+ *
256
+ * The grammar is `measure.fractionValue`'s; what stays here is the refusal.
257
+ * `3/` divides by zero and an absent regex capture arrives as `''`, and both
258
+ * would otherwise travel into a row as a nominal size — as would `0`, which
259
+ * reads as a number and is not a collet this vendor makes.
260
+ */
253
261
  export function parseSize(size) {
254
- const value = size.includes('/')
255
- ? Number(size.split('/')[0]) / Number(size.split('/')[1])
256
- : Number(size);
257
- // `3/` divides by zero and reaches here as Infinity, and an absent regex
258
- // capture as `''` -> 0; both would travel into a row as a nominal size. Neither is a collet this
259
- // vendor makes, so an unreadable size is refused rather than carried.
260
- if (!Number.isFinite(value) || value <= 0) {
262
+ const value = fractionValue(size);
263
+ if (value === null || value <= 0) {
261
264
  throw new RangeError(`unrecognized size: ${JSON.stringify(size)}`);
262
265
  }
263
266
  return value;
@@ -336,9 +339,9 @@ export function holderRow(source, properties, warn = consoleWarn) {
336
339
  const row = {
337
340
  'Material Number': sku,
338
341
  'ISO Catalog Number': title,
339
- CST: (parsed['series'] ?? '').replaceAll(' ', ''),
340
- contact,
341
- L1_mm: plain(gauge),
342
+ [COLLET_SERIES_COLUMN]: (parsed['series'] ?? '').replaceAll(' ', ''),
343
+ [CONTACT_COLUMN]: contact,
344
+ [GAGE_COLUMNS.millimeters]: plain(gauge),
342
345
  D2_mm: plain(pinned(properties, 'A1', sku)),
343
346
  B3_mm: plain(projection),
344
347
  [CAD_COLUMN]: cadUrl(source),
@@ -404,7 +407,7 @@ export function colletRow(source, warn = consoleWarn) {
404
407
  }
405
408
  const nominal = parseSize(parsed['size'] ?? '');
406
409
  const unit = inches ? 'inches' : 'millimeters';
407
- const nominalMm = inches ? round(nominal * MM_PER_INCH, 6) : nominal;
410
+ const nominalMm = inches ? round(convertLength(nominal, 'inches', 'millimeters'), 6) : nominal;
408
411
  // A powRgrip collet clamps one size to h6 (h9 on the turning and tapping
409
412
  // lines) rather than closing over a range, so its capacity is its nominal
410
413
  // diameter at both ends. That is the vendor's `Clamping range or tolerance`
@@ -435,29 +438,11 @@ export function colletRow(source, warn = consoleWarn) {
435
438
  // Projected for the same reason `D1` is: an inch tapping collet whose
436
439
  // square sits only in `Square_in` is invisible to mm-side fit arithmetic.
437
440
  if (inches)
438
- row['Square_mm'] = plain(round(square * MM_PER_INCH, 6));
441
+ row['Square_mm'] = plain(round(convertLength(square, 'inches', 'millimeters'), 6));
439
442
  }
440
443
  crossCheckOmm(row, nominalMm, warn);
441
444
  return row;
442
445
  }
443
- /**
444
- * Rows to a result whose header is the union of their keys, in first-seen
445
- * order.
446
- *
447
- * A union rather than the first row's keys: a mixed-unit collet family has
448
- * `D1_mm` on its metric rows and `D1_in` on its inch ones, and keying off row
449
- * one would drop whichever came second.
450
- */
451
- export function unionHeader(rows) {
452
- const header = [];
453
- for (const row of rows) {
454
- for (const key of Object.keys(row)) {
455
- if (!header.includes(key))
456
- header.push(key);
457
- }
458
- }
459
- return header;
460
- }
461
446
  /**
462
447
  * Every powRgrip holder of `group` whose taper is in {@link SCRAPED_TAPERS}.
463
448
  *
@@ -476,7 +461,7 @@ export async function scrapeHolders(fetcher, group = 'BT/PG', category = 'BT', o
476
461
  });
477
462
  const wanted = sources
478
463
  .filter((s) => SCRAPED_TAPERS.some((taper) => text(s, 'title').startsWith(taper)))
479
- .sort((a, b) => text(a, 'field_sku_fulltext').localeCompare(text(b, 'field_sku_fulltext'), 'en'));
464
+ .sort((a, b) => compare(text(a, 'field_sku_fulltext'), text(b, 'field_sku_fulltext')));
480
465
  const rows = [];
481
466
  for (const source of wanted) {
482
467
  const sku = text(source, 'field_sku_fulltext');
@@ -506,7 +491,7 @@ export async function scrapeCollets(fetcher, group, sizes, options = {}) {
506
491
  });
507
492
  const wanted = sources
508
493
  .filter((s) => sizes.includes(String(one(s, 'norm_size'))))
509
- .sort((a, b) => text(a, 'field_sku_fulltext').localeCompare(text(b, 'field_sku_fulltext'), 'en'));
494
+ .sort((a, b) => compare(text(a, 'field_sku_fulltext'), text(b, 'field_sku_fulltext')));
510
495
  return finish(
511
496
  // `options.warn` unguarded: `colletRow` owns the fallback, and defaulting
512
497
  // it here too would be two layers deciding the same thing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolpath/tool-scraper",
3
- "version": "0.1.0",
3
+ "version": "2.1.0",
4
4
  "description": "Scrape cutting-tool geometry from vendor catalogs into records and CSVs",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -43,6 +43,18 @@
43
43
  "types": "./dist/vendors/destinytool/index.d.ts",
44
44
  "import": "./dist/vendors/destinytool/index.js"
45
45
  },
46
+ "./vendors/emuge": {
47
+ "types": "./dist/vendors/emuge/index.d.ts",
48
+ "import": "./dist/vendors/emuge/index.js"
49
+ },
50
+ "./vendors/harvey": {
51
+ "types": "./dist/vendors/harvey/index.d.ts",
52
+ "import": "./dist/vendors/harvey/index.js"
53
+ },
54
+ "./vendors/maritool": {
55
+ "types": "./dist/vendors/maritool/index.d.ts",
56
+ "import": "./dist/vendors/maritool/index.js"
57
+ },
46
58
  "./registry": {
47
59
  "types": "./dist/registry.d.ts",
48
60
  "import": "./dist/registry.js"
@@ -50,6 +62,18 @@
50
62
  "./families": {
51
63
  "types": "./dist/families/index.d.ts",
52
64
  "import": "./dist/families/index.js"
65
+ },
66
+ "./families/harvey": {
67
+ "types": "./dist/families/harvey.d.ts",
68
+ "import": "./dist/families/harvey.js"
69
+ },
70
+ "./families/maritool": {
71
+ "types": "./dist/families/maritool.d.ts",
72
+ "import": "./dist/families/maritool.js"
73
+ },
74
+ "./families/emuge": {
75
+ "types": "./dist/families/emuge.d.ts",
76
+ "import": "./dist/families/emuge.js"
53
77
  }
54
78
  },
55
79
  "files": [
@@ -57,11 +81,6 @@
57
81
  "LICENSE",
58
82
  "README.md"
59
83
  ],
60
- "scripts": {
61
- "build": "tsc -p tsconfig.build.json",
62
- "check-types": "tsc --noEmit",
63
- "test": "vitest run"
64
- },
65
84
  "dependencies": {
66
85
  "htmlparser2": "12.0.0"
67
86
  },
@@ -72,5 +91,10 @@
72
91
  },
73
92
  "bin": {
74
93
  "toolpath-scrape": "./dist/node/main.js"
94
+ },
95
+ "scripts": {
96
+ "build": "tsc -p tsconfig.build.json",
97
+ "check-types": "tsc --noEmit",
98
+ "test": "vitest run"
75
99
  }
76
- }
100
+ }