@toolpath/tool-scraper 0.1.0 → 2.0.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 (68) hide show
  1. package/README.md +41 -11
  2. package/dist/columns.d.ts +62 -0
  3. package/dist/columns.js +62 -0
  4. package/dist/conventions.d.ts +89 -15
  5. package/dist/conventions.js +108 -15
  6. package/dist/families/emuge.d.ts +183 -0
  7. package/dist/families/emuge.js +159 -0
  8. package/dist/families/harvey.d.ts +1782 -0
  9. package/dist/families/harvey.js +1328 -0
  10. package/dist/families/index.js +5 -2
  11. package/dist/families/kennametal.d.ts +21 -0
  12. package/dist/families/kennametal.js +10 -0
  13. package/dist/families/maritool.d.ts +120 -0
  14. package/dist/families/maritool.js +175 -0
  15. package/dist/family.d.ts +35 -1
  16. package/dist/family.js +28 -0
  17. package/dist/identity.d.ts +18 -0
  18. package/dist/identity.js +46 -0
  19. package/dist/index.d.ts +16 -0
  20. package/dist/index.js +16 -0
  21. package/dist/measure.d.ts +112 -0
  22. package/dist/measure.js +130 -0
  23. package/dist/node/cli.d.ts +3 -0
  24. package/dist/node/cli.js +152 -2
  25. package/dist/node/main.js +0 -0
  26. package/dist/records.d.ts +169 -12
  27. package/dist/records.js +116 -5
  28. package/dist/registry.d.ts +31 -1
  29. package/dist/registry.js +40 -1
  30. package/dist/scrape.d.ts +15 -0
  31. package/dist/scrape.js +24 -0
  32. package/dist/vendors/destinytool/records.d.ts +13 -3
  33. package/dist/vendors/destinytool/records.js +41 -37
  34. package/dist/vendors/emuge/index.d.ts +17 -0
  35. package/dist/vendors/emuge/index.js +17 -0
  36. package/dist/vendors/emuge/records.d.ts +150 -0
  37. package/dist/vendors/emuge/records.js +375 -0
  38. package/dist/vendors/emuge/scrape.d.ts +227 -0
  39. package/dist/vendors/emuge/scrape.js +358 -0
  40. package/dist/vendors/emuge/value.d.ts +75 -0
  41. package/dist/vendors/emuge/value.js +116 -0
  42. package/dist/vendors/harvey/catalog.d.ts +53 -0
  43. package/dist/vendors/harvey/catalog.js +120 -0
  44. package/dist/vendors/harvey/header.d.ts +89 -0
  45. package/dist/vendors/harvey/header.js +185 -0
  46. package/dist/vendors/harvey/index.d.ts +21 -0
  47. package/dist/vendors/harvey/index.js +21 -0
  48. package/dist/vendors/harvey/lexicon.d.ts +73 -0
  49. package/dist/vendors/harvey/lexicon.js +126 -0
  50. package/dist/vendors/harvey/literal.d.ts +68 -0
  51. package/dist/vendors/harvey/literal.js +214 -0
  52. package/dist/vendors/harvey/records.d.ts +79 -0
  53. package/dist/vendors/harvey/records.js +163 -0
  54. package/dist/vendors/harvey/scrape.d.ts +187 -0
  55. package/dist/vendors/harvey/scrape.js +483 -0
  56. package/dist/vendors/harvey/value.d.ts +74 -0
  57. package/dist/vendors/harvey/value.js +119 -0
  58. package/dist/vendors/kennametal/records.d.ts +13 -4
  59. package/dist/vendors/kennametal/records.js +61 -26
  60. package/dist/vendors/maritool/catalog.d.ts +81 -0
  61. package/dist/vendors/maritool/catalog.js +132 -0
  62. package/dist/vendors/maritool/index.d.ts +10 -0
  63. package/dist/vendors/maritool/index.js +10 -0
  64. package/dist/vendors/maritool/scrape.d.ts +297 -0
  65. package/dist/vendors/maritool/scrape.js +593 -0
  66. package/dist/vendors/regofix/scrape.d.ts +8 -11
  67. package/dist/vendors/regofix/scrape.js +21 -36
  68. package/package.json +31 -7
@@ -0,0 +1,1328 @@
1
+ /**
2
+ * Harvey Tool's families — one per product page, 52 of them.
3
+ *
4
+ * A family here is a product page, because that is the unit Harvey publishes:
5
+ * one page carries one product line's whole variant table, and its
6
+ * `productCode` — `HT-Harvey-EndMill-008` — is the vendor's own name for it.
7
+ * That code is the `familyCode`; the CSV name and the family id are derived
8
+ * from it, so nothing here invents a label.
9
+ *
10
+ * ## Where the scrape target lives, and why it is not in the definition
11
+ *
12
+ * A Harvey scrape needs a product-page **path**, and `FamilyDefinition` has no
13
+ * key for one — `familyCode` is the vendor's code and a path is not that.
14
+ * Harvey's slugs are also not derivable from the code: three of the 52 say
15
+ * `end-mills-` where the rest say `miniature-end-mills-`, and the separators
16
+ * change from `---` to `-` partway through the catalog.
17
+ *
18
+ * So {@link PRODUCT_PAGES} is a second table beside the first, keyed by the same
19
+ * CSV name, and `tests/harvey-families.test.ts` holds the two to the same keys.
20
+ * The alternative — widening the shared `FamilyDefinition` with a key one vendor
21
+ * uses — would put a Harvey fact in the type every family in the catalog is
22
+ * written against.
23
+ *
24
+ * ## `rows` is Harvey's count, not this adapter's
25
+ *
26
+ * Every count below was read on 2026-08-29 by summing the `T` entries of each
27
+ * table row's own add-to-cart payload (`atc.j`) across all 80 tables — Harvey's
28
+ * independent statement of what is orderable, not a number this adapter
29
+ * produced. That is what makes `receipts.checkRows` worth running, and it is the
30
+ * same list `vendors/harvey/scrape.ts` checks the matrix explosion against on
31
+ * every row.
32
+ *
33
+ * It is still a script's count rather than a person's. The payload lists 12,799
34
+ * entries across 5,033 HTML rows; **26 of them are not parts.** Two families
35
+ * carry the marketing string `25x Diameter!` / `30x Diameter!` in a tool-number
36
+ * column, with no product link and no CAD model, and Harvey's own payload lists
37
+ * those as if they were orderable. The adapter drops them and warns, so the two
38
+ * counts below are the payload's minus that vendor fault: 12,773 real parts.
39
+ *
40
+ * ## `NOF` maps a column the adapter synthesises
41
+ *
42
+ * Half these tables state the flute count in a column of their own and half
43
+ * state it in a coating group's sub-header, so `vendors/harvey/scrape.ts`
44
+ * writes one `FLUTES` column either way and every family maps `NOF` to it. The
45
+ * two exceptions are the deburring families, which publish right- and left-hand
46
+ * tooth counts and no flute count at all — `NOF` is absent there because the
47
+ * vendor states none, not because the mapping was forgotten.
48
+ *
49
+ * ## Every family is `endmill`
50
+ *
51
+ * Including the twelve keyseat-cutter families. `records.ToolKind` has three
52
+ * values — `drill`, `tap`, `endmill` — and a keyseat cutter is a side-cutting
53
+ * milling tool with a cutting diameter, a width of cut, a shank and an overall
54
+ * length, so it maps onto the endmill contract exactly. Adding a fourth kind for
55
+ * it would be a cross-package contract change, and nothing downstream is asking
56
+ * for one yet.
57
+ */
58
+ /**
59
+ * The unit fact the 47 imperial families share.
60
+ *
61
+ * One object rather than 47 copies of the same sentence. The citation is still
62
+ * re-checkable with one request against any of them: open the page, read the
63
+ * `D1` sub-header.
64
+ */
65
+ const INCHES = {
66
+ value: 'inches',
67
+ source: 'vendor-stated',
68
+ cite: 'every imperial Harvey product page publishes its dimensions as US-customary ' +
69
+ 'decimals and fractions, with the D1/L1/L2 sub-headers carrying inch ' +
70
+ 'tolerances (all 47 read 2026-08-29)',
71
+ };
72
+ /** The unit fact the 5 metric families share. */
73
+ const MILLIMETERS = {
74
+ value: 'millimeters',
75
+ source: 'vendor-stated',
76
+ cite: "each of these pages titles itself '- Metric' and publishes its D1 tolerance " +
77
+ 'in mm (e.g. D1 +.000 mm / -.020 mm), and its dimension cells carry a ' +
78
+ 'trailing mm (all 5 read 2026-08-29)',
79
+ };
80
+ /** Solid carbide, stated on every one of the 52 pages. */
81
+ const SOLID_CARBIDE = {
82
+ value: 'carbide',
83
+ source: 'vendor-stated',
84
+ cite: "the product page's own description block, which states the tool is CNC " +
85
+ 'ground from solid carbide (all 52 checked 2026-08-29)',
86
+ };
87
+ /**
88
+ * No coolant through, on the 51 families that are not the coolant-through line.
89
+ *
90
+ * Derived rather than assumed: Harvey publishes no coolant column anywhere in
91
+ * these tables, and names its one coolant-through product line in that page's
92
+ * own title. A family whose title does not name it is not one.
93
+ */
94
+ const NO_COOLANT_THROUGH = {
95
+ value: false,
96
+ source: 'derived',
97
+ note: 'Harvey publishes no coolant column in any product table and names its one ' +
98
+ "coolant-through line in that page's own productTitle; this family's title " +
99
+ 'does not name it',
100
+ };
101
+ /**
102
+ * The end profile, as the page's own title states it.
103
+ *
104
+ * `vendors/harvey/records.ts` reads it for exactly one thing: a family with no
105
+ * corner-radius column is a ball nose with `RE = DC / 2` rather than a flat end
106
+ * with `RE = 0`, and nothing in the variant table says which.
107
+ */
108
+ function statedProfile(value, title) {
109
+ return {
110
+ value,
111
+ source: 'vendor-stated',
112
+ cite: `the page's own productTitle, ${JSON.stringify(title)}`,
113
+ };
114
+ }
115
+ export const FAMILIES = {
116
+ // End Mills - Ball - Reduced Shank
117
+ 'harvey_endmill_001.csv': {
118
+ id: 'endmill-001',
119
+ brand: 'harvey',
120
+ kind: 'endmill',
121
+ familyCode: 'HT-Harvey-EndMill-001',
122
+ rows: 28,
123
+ columns: {
124
+ DC: 'CUTTER DIAMETER',
125
+ SFDM: 'SHANK DIAMETER',
126
+ OAL: 'OVERALL LENGTH',
127
+ LCF: 'LENGTH OF CUT',
128
+ NOF: 'FLUTES',
129
+ },
130
+ facts: {
131
+ unit: INCHES,
132
+ bmc: SOLID_CARBIDE,
133
+ profile: statedProfile('Ball', 'End Mills - Ball - Reduced Shank'),
134
+ coolantThrough: NO_COOLANT_THROUGH,
135
+ },
136
+ },
137
+ // End Mills - Corner Radius - Reduced Shank
138
+ 'harvey_endmill_002.csv': {
139
+ id: 'endmill-002',
140
+ brand: 'harvey',
141
+ kind: 'endmill',
142
+ familyCode: 'HT-Harvey-EndMill-002',
143
+ rows: 44,
144
+ columns: {
145
+ DC: 'CUTTER DIAMETER',
146
+ SFDM: 'SHANK DIAMETER',
147
+ OAL: 'OVERALL LENGTH',
148
+ LCF: 'LENGTH OF CUT',
149
+ RE: 'CORNER RADIUS',
150
+ NOF: 'FLUTES',
151
+ },
152
+ facts: {
153
+ unit: INCHES,
154
+ bmc: SOLID_CARBIDE,
155
+ profile: statedProfile('Corner Radius', 'End Mills - Corner Radius - Reduced Shank'),
156
+ coolantThrough: NO_COOLANT_THROUGH,
157
+ },
158
+ },
159
+ // End Mills - Square - Reduced Shank
160
+ 'harvey_endmill_003.csv': {
161
+ id: 'endmill-003',
162
+ brand: 'harvey',
163
+ kind: 'endmill',
164
+ familyCode: 'HT-Harvey-EndMill-003',
165
+ rows: 49,
166
+ columns: {
167
+ DC: 'CUTTER DIAMETER',
168
+ SFDM: 'SHANK DIAMETER',
169
+ OAL: 'OVERALL LENGTH',
170
+ LCF: 'LENGTH OF CUT',
171
+ NOF: 'FLUTES',
172
+ },
173
+ facts: {
174
+ unit: INCHES,
175
+ bmc: SOLID_CARBIDE,
176
+ profile: statedProfile('Square', 'End Mills - Square - Reduced Shank'),
177
+ coolantThrough: NO_COOLANT_THROUGH,
178
+ },
179
+ },
180
+ // Miniature End Mills - Ball - Long Flute
181
+ 'harvey_endmill_004.csv': {
182
+ id: 'endmill-004',
183
+ brand: 'harvey',
184
+ kind: 'endmill',
185
+ familyCode: 'HT-Harvey-EndMill-004',
186
+ rows: 389,
187
+ columns: {
188
+ DC: 'CUTTER DIA.',
189
+ SFDM: 'SHANK DIA.',
190
+ OAL: 'OAL',
191
+ LCF: 'LENGTH OF CUT',
192
+ NOF: 'FLUTES',
193
+ },
194
+ facts: {
195
+ unit: INCHES,
196
+ bmc: SOLID_CARBIDE,
197
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Long Flute'),
198
+ coolantThrough: NO_COOLANT_THROUGH,
199
+ },
200
+ },
201
+ // Miniature End Mills - Ball - Long Reach, Long Flute
202
+ 'harvey_endmill_005.csv': {
203
+ id: 'endmill-005',
204
+ brand: 'harvey',
205
+ kind: 'endmill',
206
+ familyCode: 'HT-Harvey-EndMill-005',
207
+ rows: 95,
208
+ columns: {
209
+ DC: 'CUTTER DIA.',
210
+ SFDM: 'SHANK DIA.',
211
+ OAL: 'OAL',
212
+ LCF: 'LENGTH OF CUT',
213
+ 'shoulder-length': 'OVERALL REACH',
214
+ NOF: 'FLUTES',
215
+ },
216
+ facts: {
217
+ unit: INCHES,
218
+ bmc: SOLID_CARBIDE,
219
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Long Reach, Long Flute'),
220
+ coolantThrough: NO_COOLANT_THROUGH,
221
+ },
222
+ },
223
+ // Miniature End Mills - Ball - Long Reach, Standard Flute
224
+ 'harvey_endmill_006.csv': {
225
+ id: 'endmill-006',
226
+ brand: 'harvey',
227
+ kind: 'endmill',
228
+ familyCode: 'HT-Harvey-EndMill-006',
229
+ rows: 284,
230
+ columns: {
231
+ DC: 'CUTTER DIAMETER',
232
+ SFDM: 'SHANK DIAMETER',
233
+ OAL: 'OVERALL LENGTH',
234
+ LCF: 'LENGTH OF CUT',
235
+ 'shoulder-length': 'OVERALL REACH',
236
+ NOF: 'FLUTES',
237
+ },
238
+ facts: {
239
+ unit: INCHES,
240
+ bmc: SOLID_CARBIDE,
241
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Long Reach, Standard Flute'),
242
+ coolantThrough: NO_COOLANT_THROUGH,
243
+ },
244
+ },
245
+ // Miniature End Mills - Ball - Long Reach, Stub Flute
246
+ 'harvey_endmill_007.csv': {
247
+ id: 'endmill-007',
248
+ brand: 'harvey',
249
+ kind: 'endmill',
250
+ familyCode: 'HT-Harvey-EndMill-007',
251
+ // 728 tool-number cells, 10 of which are the `30x Diameter!` marketing
252
+ // string sitting in a tool-number column with no product link. See the
253
+ // module note above and `vendors/harvey/scrape.ts`.
254
+ rows: 718,
255
+ columns: {
256
+ DC: 'CUTTER DIA.',
257
+ SFDM: 'SHANK DIA.',
258
+ OAL: 'OAL',
259
+ LCF: 'LOC',
260
+ 'shoulder-length': 'OVERALL REACH',
261
+ NOF: 'FLUTES',
262
+ },
263
+ facts: {
264
+ unit: INCHES,
265
+ bmc: SOLID_CARBIDE,
266
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Long Reach, Stub Flute'),
267
+ coolantThrough: NO_COOLANT_THROUGH,
268
+ },
269
+ },
270
+ // Miniature End Mills - Ball - Stub & Standard
271
+ 'harvey_endmill_008.csv': {
272
+ id: 'endmill-008',
273
+ brand: 'harvey',
274
+ kind: 'endmill',
275
+ familyCode: 'HT-Harvey-EndMill-008',
276
+ rows: 840,
277
+ columns: {
278
+ DC: 'CUTTER DIA.',
279
+ SFDM: 'SHANK DIA.',
280
+ OAL: 'OAL',
281
+ LCF: 'LOC',
282
+ NOF: 'FLUTES',
283
+ },
284
+ facts: {
285
+ unit: INCHES,
286
+ bmc: SOLID_CARBIDE,
287
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Stub & Standard'),
288
+ coolantThrough: NO_COOLANT_THROUGH,
289
+ },
290
+ },
291
+ // Miniature End Mills - Ball - Tapered Reach (Clearance Cutters)
292
+ 'harvey_endmill_009.csv': {
293
+ id: 'endmill-009',
294
+ brand: 'harvey',
295
+ kind: 'endmill',
296
+ familyCode: 'HT-Harvey-EndMill-009',
297
+ rows: 171,
298
+ columns: {
299
+ DC: 'CUTTER DIA.',
300
+ SFDM: 'SHANK DIA.',
301
+ OAL: 'OAL',
302
+ LCF: 'LOC',
303
+ 'shoulder-length': 'OVERALL REACH',
304
+ NOF: 'FLUTES',
305
+ },
306
+ facts: {
307
+ unit: INCHES,
308
+ bmc: SOLID_CARBIDE,
309
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Tapered Reach (Clearance Cutters)'),
310
+ coolantThrough: NO_COOLANT_THROUGH,
311
+ },
312
+ },
313
+ // Miniature End Mills - Tapered - Ball
314
+ 'harvey_endmill_010.csv': {
315
+ id: 'endmill-010',
316
+ brand: 'harvey',
317
+ kind: 'endmill',
318
+ familyCode: 'HT-Harvey-EndMill-010',
319
+ rows: 178,
320
+ columns: {
321
+ DC: 'CUTTER DIAMETER',
322
+ SFDM: 'SHANK DIAMETER',
323
+ OAL: 'OVERALL LENGTH',
324
+ LCF: 'LENGTH OF CUT',
325
+ NOF: 'FLUTES',
326
+ },
327
+ facts: {
328
+ unit: INCHES,
329
+ bmc: SOLID_CARBIDE,
330
+ profile: statedProfile('Ball', 'Miniature End Mills - Tapered - Ball'),
331
+ coolantThrough: NO_COOLANT_THROUGH,
332
+ },
333
+ },
334
+ // Miniature End Mills - Corner Radius - Long Flute
335
+ 'harvey_endmill_011.csv': {
336
+ id: 'endmill-011',
337
+ brand: 'harvey',
338
+ kind: 'endmill',
339
+ familyCode: 'HT-Harvey-EndMill-011',
340
+ rows: 293,
341
+ columns: {
342
+ DC: 'CUTTER DIA.',
343
+ SFDM: 'SHANK DIA.',
344
+ OAL: 'OAL',
345
+ LCF: 'LENGTH OF CUT',
346
+ RE: 'CORNER RADIUS',
347
+ NOF: 'FLUTES',
348
+ },
349
+ facts: {
350
+ unit: INCHES,
351
+ bmc: SOLID_CARBIDE,
352
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Long Flute'),
353
+ coolantThrough: NO_COOLANT_THROUGH,
354
+ },
355
+ },
356
+ // Miniature End Mills - Corner Radius - Long Reach, Standard Flute
357
+ 'harvey_endmill_012.csv': {
358
+ id: 'endmill-012',
359
+ brand: 'harvey',
360
+ kind: 'endmill',
361
+ familyCode: 'HT-Harvey-EndMill-012',
362
+ rows: 154,
363
+ columns: {
364
+ DC: 'CUTTER DIA.',
365
+ SFDM: 'SHANK DIA.',
366
+ OAL: 'OAL',
367
+ LCF: 'LOC',
368
+ RE: 'CORNER RADIUS',
369
+ 'shoulder-length': 'OVERALL REACH',
370
+ NOF: 'FLUTES',
371
+ },
372
+ facts: {
373
+ unit: INCHES,
374
+ bmc: SOLID_CARBIDE,
375
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Long Reach, Standard Flute'),
376
+ coolantThrough: NO_COOLANT_THROUGH,
377
+ },
378
+ },
379
+ // Miniature End Mills - Corner Radius - Long Reach, Stub Flute
380
+ 'harvey_endmill_013.csv': {
381
+ id: 'endmill-013',
382
+ brand: 'harvey',
383
+ kind: 'endmill',
384
+ familyCode: 'HT-Harvey-EndMill-013',
385
+ rows: 598,
386
+ columns: {
387
+ DC: 'CUTTER DIA.',
388
+ SFDM: 'SHANK DIA.',
389
+ OAL: 'OAL',
390
+ LCF: 'LOC',
391
+ RE: 'CORNER RADIUS',
392
+ 'shoulder-length': 'OVERALL REACH',
393
+ NOF: 'FLUTES',
394
+ },
395
+ facts: {
396
+ unit: INCHES,
397
+ bmc: SOLID_CARBIDE,
398
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Long Reach, Stub Flute'),
399
+ coolantThrough: NO_COOLANT_THROUGH,
400
+ },
401
+ },
402
+ // Miniature End Mills - Corner Radius - Stub & Standard
403
+ 'harvey_endmill_014.csv': {
404
+ id: 'endmill-014',
405
+ brand: 'harvey',
406
+ kind: 'endmill',
407
+ familyCode: 'HT-Harvey-EndMill-014',
408
+ rows: 1344,
409
+ columns: {
410
+ DC: 'CUTTER DIA.',
411
+ SFDM: 'SHANK DIA.',
412
+ OAL: 'OAL',
413
+ LCF: 'LENGTH OF CUT',
414
+ RE: 'CORNER RADIUS',
415
+ NOF: 'FLUTES',
416
+ },
417
+ facts: {
418
+ unit: INCHES,
419
+ bmc: SOLID_CARBIDE,
420
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Stub & Standard'),
421
+ coolantThrough: NO_COOLANT_THROUGH,
422
+ },
423
+ },
424
+ // Miniature End Mills - Square - Deburring End Mill
425
+ 'harvey_endmill_015.csv': {
426
+ id: 'endmill-015',
427
+ brand: 'harvey',
428
+ kind: 'endmill',
429
+ familyCode: 'HT-Harvey-EndMill-015',
430
+ rows: 18,
431
+ columns: {
432
+ DC: 'CUTTER DIA.',
433
+ SFDM: 'SHANK DIA.',
434
+ OAL: 'OAL',
435
+ LCF: 'LOC',
436
+ },
437
+ facts: {
438
+ unit: INCHES,
439
+ bmc: SOLID_CARBIDE,
440
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Deburring End Mill'),
441
+ coolantThrough: NO_COOLANT_THROUGH,
442
+ },
443
+ },
444
+ // Miniature End Mills - Square - Long Flute
445
+ 'harvey_endmill_016.csv': {
446
+ id: 'endmill-016',
447
+ brand: 'harvey',
448
+ kind: 'endmill',
449
+ familyCode: 'HT-Harvey-EndMill-016',
450
+ rows: 734,
451
+ columns: {
452
+ DC: 'CUTTER DIA.',
453
+ SFDM: 'SHANK DIA.',
454
+ OAL: 'OAL',
455
+ LCF: 'LENGTH OF CUT',
456
+ NOF: 'FLUTES',
457
+ },
458
+ facts: {
459
+ unit: INCHES,
460
+ bmc: SOLID_CARBIDE,
461
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Flute'),
462
+ coolantThrough: NO_COOLANT_THROUGH,
463
+ },
464
+ },
465
+ // Miniature End Mills - Square - Long Reach, Long Flute
466
+ 'harvey_endmill_017.csv': {
467
+ id: 'endmill-017',
468
+ brand: 'harvey',
469
+ kind: 'endmill',
470
+ familyCode: 'HT-Harvey-EndMill-017',
471
+ rows: 194,
472
+ columns: {
473
+ DC: 'CUTTER DIA.',
474
+ SFDM: 'SHANK DIA.',
475
+ OAL: 'OAL',
476
+ LCF: 'LENGTH OF CUT',
477
+ 'shoulder-length': 'OVERALL REACH',
478
+ NOF: 'FLUTES',
479
+ },
480
+ facts: {
481
+ unit: INCHES,
482
+ bmc: SOLID_CARBIDE,
483
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Reach, Long Flute'),
484
+ coolantThrough: NO_COOLANT_THROUGH,
485
+ },
486
+ },
487
+ // Miniature End Mills - Square - Long Reach, Standard Flute
488
+ 'harvey_endmill_018.csv': {
489
+ id: 'endmill-018',
490
+ brand: 'harvey',
491
+ kind: 'endmill',
492
+ familyCode: 'HT-Harvey-EndMill-018',
493
+ rows: 519,
494
+ columns: {
495
+ DC: 'CUTTER DIAMETER',
496
+ SFDM: 'SHANK DIAMETER',
497
+ OAL: 'OVERALL LENGTH',
498
+ LCF: 'LENGTH OF CUT',
499
+ 'shoulder-length': 'OVERALL REACH',
500
+ NOF: 'FLUTES',
501
+ },
502
+ facts: {
503
+ unit: INCHES,
504
+ bmc: SOLID_CARBIDE,
505
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Reach, Standard Flute'),
506
+ coolantThrough: NO_COOLANT_THROUGH,
507
+ },
508
+ },
509
+ // Miniature End Mills - Square - Long Reach, Stub Flute
510
+ 'harvey_endmill_019.csv': {
511
+ id: 'endmill-019',
512
+ brand: 'harvey',
513
+ kind: 'endmill',
514
+ familyCode: 'HT-Harvey-EndMill-019',
515
+ // 1,042 tool-number cells, 16 of which are the `25x Diameter!` marketing
516
+ // string. Same fault as EndMill-007.
517
+ rows: 1026,
518
+ columns: {
519
+ DC: 'CUTTER DIA.',
520
+ SFDM: 'SHANK DIA.',
521
+ OAL: 'OAL',
522
+ LCF: 'LOC',
523
+ 'shoulder-length': 'OVERALL REACH',
524
+ NOF: 'FLUTES',
525
+ },
526
+ facts: {
527
+ unit: INCHES,
528
+ bmc: SOLID_CARBIDE,
529
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Reach, Stub Flute'),
530
+ coolantThrough: NO_COOLANT_THROUGH,
531
+ },
532
+ },
533
+ // Miniature End Mills - Square - Stub & Standard
534
+ 'harvey_endmill_020.csv': {
535
+ id: 'endmill-020',
536
+ brand: 'harvey',
537
+ kind: 'endmill',
538
+ familyCode: 'HT-Harvey-EndMill-020',
539
+ rows: 1239,
540
+ columns: {
541
+ DC: 'CUTTER DIA.',
542
+ SFDM: 'SHANK DIA.',
543
+ OAL: 'OAL',
544
+ LCF: 'LOC',
545
+ NOF: 'FLUTES',
546
+ },
547
+ facts: {
548
+ unit: INCHES,
549
+ bmc: SOLID_CARBIDE,
550
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Stub & Standard'),
551
+ coolantThrough: NO_COOLANT_THROUGH,
552
+ },
553
+ },
554
+ // Miniature End Mills - Square - Tapered Reach (Clearance Cutters)
555
+ 'harvey_endmill_021.csv': {
556
+ id: 'endmill-021',
557
+ brand: 'harvey',
558
+ kind: 'endmill',
559
+ familyCode: 'HT-Harvey-EndMill-021',
560
+ rows: 88,
561
+ columns: {
562
+ DC: 'CUTTER DIA.',
563
+ SFDM: 'SHANK DIA.',
564
+ OAL: 'OAL',
565
+ LCF: 'LOC',
566
+ 'shoulder-length': 'OVERALL REACH',
567
+ NOF: 'FLUTES',
568
+ },
569
+ facts: {
570
+ unit: INCHES,
571
+ bmc: SOLID_CARBIDE,
572
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Tapered Reach (Clearance Cutters)'),
573
+ coolantThrough: NO_COOLANT_THROUGH,
574
+ },
575
+ },
576
+ // Miniature End Mills - Tapered - Square
577
+ 'harvey_endmill_022.csv': {
578
+ id: 'endmill-022',
579
+ brand: 'harvey',
580
+ kind: 'endmill',
581
+ familyCode: 'HT-Harvey-EndMill-022',
582
+ rows: 371,
583
+ columns: {
584
+ DC: 'CUTTER DIAMETER',
585
+ SFDM: 'SHANK DIAMETER',
586
+ OAL: 'OVERALL LENGTH',
587
+ LCF: 'LENGTH OF CUT',
588
+ NOF: 'FLUTES',
589
+ },
590
+ facts: {
591
+ unit: INCHES,
592
+ bmc: SOLID_CARBIDE,
593
+ profile: statedProfile('Square', 'Miniature End Mills - Tapered - Square'),
594
+ coolantThrough: NO_COOLANT_THROUGH,
595
+ },
596
+ },
597
+ // Miniature End Mills - Ball - Deburring End Mill
598
+ 'harvey_endmill_023.csv': {
599
+ id: 'endmill-023',
600
+ brand: 'harvey',
601
+ kind: 'endmill',
602
+ familyCode: 'HT-Harvey-EndMill-023',
603
+ rows: 26,
604
+ columns: {
605
+ DC: 'CUTTER DIA.',
606
+ SFDM: 'SHANK DIA.',
607
+ OAL: 'OAL',
608
+ LCF: 'LOC',
609
+ },
610
+ facts: {
611
+ unit: INCHES,
612
+ bmc: SOLID_CARBIDE,
613
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Deburring End Mill'),
614
+ coolantThrough: NO_COOLANT_THROUGH,
615
+ },
616
+ },
617
+ // Miniature End Mills - Ball - Extra Long Length
618
+ 'harvey_endmill_025.csv': {
619
+ id: 'endmill-025',
620
+ brand: 'harvey',
621
+ kind: 'endmill',
622
+ familyCode: 'HT-Harvey-EndMill-025',
623
+ rows: 10,
624
+ columns: {
625
+ DC: 'CUTTER DIA.',
626
+ SFDM: 'SHANK DIA.',
627
+ OAL: 'OAL',
628
+ LCF: 'LOC',
629
+ 'shoulder-length': 'OVERALL REACH',
630
+ NOF: 'FLUTES',
631
+ },
632
+ facts: {
633
+ unit: INCHES,
634
+ bmc: SOLID_CARBIDE,
635
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Extra Long Length'),
636
+ coolantThrough: NO_COOLANT_THROUGH,
637
+ },
638
+ },
639
+ // Miniature End Mills - Corner Radius - Extra Long Length
640
+ 'harvey_endmill_026.csv': {
641
+ id: 'endmill-026',
642
+ brand: 'harvey',
643
+ kind: 'endmill',
644
+ familyCode: 'HT-Harvey-EndMill-026',
645
+ rows: 12,
646
+ columns: {
647
+ DC: 'CUTTER DIA.',
648
+ SFDM: 'SHANK DIA.',
649
+ OAL: 'OAL',
650
+ LCF: 'LOC',
651
+ RE: 'CORNER RADIUS',
652
+ 'shoulder-length': 'OVERALL REACH',
653
+ NOF: 'FLUTES',
654
+ },
655
+ facts: {
656
+ unit: INCHES,
657
+ bmc: SOLID_CARBIDE,
658
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Extra Long Length'),
659
+ coolantThrough: NO_COOLANT_THROUGH,
660
+ },
661
+ },
662
+ // Miniature End Mills - Square - Extra Long Length
663
+ 'harvey_endmill_027.csv': {
664
+ id: 'endmill-027',
665
+ brand: 'harvey',
666
+ kind: 'endmill',
667
+ familyCode: 'HT-Harvey-EndMill-027',
668
+ rows: 20,
669
+ columns: {
670
+ DC: 'CUTTER DIA.',
671
+ SFDM: 'SHANK DIA.',
672
+ OAL: 'OAL',
673
+ LCF: 'LOC',
674
+ 'shoulder-length': 'OVERALL REACH',
675
+ NOF: 'FLUTES',
676
+ },
677
+ facts: {
678
+ unit: INCHES,
679
+ bmc: SOLID_CARBIDE,
680
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Extra Long Length'),
681
+ coolantThrough: NO_COOLANT_THROUGH,
682
+ },
683
+ },
684
+ // Miniature End Mills - Square - Router Style
685
+ 'harvey_endmill_028.csv': {
686
+ id: 'endmill-028',
687
+ brand: 'harvey',
688
+ kind: 'endmill',
689
+ familyCode: 'HT-Harvey-EndMill-028',
690
+ rows: 36,
691
+ columns: {
692
+ DC: 'CUTTER DIAMETER',
693
+ SFDM: 'SHANK DIAMETER',
694
+ OAL: 'OVERALL LENGTH',
695
+ LCF: 'LENGTH OF CUT',
696
+ NOF: 'FLUTES',
697
+ },
698
+ facts: {
699
+ unit: INCHES,
700
+ bmc: SOLID_CARBIDE,
701
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Router Style'),
702
+ coolantThrough: NO_COOLANT_THROUGH,
703
+ },
704
+ },
705
+ // Miniature End Mills - Square - Stub & Standard - Metric
706
+ 'harvey_endmill_029.csv': {
707
+ id: 'endmill-029',
708
+ brand: 'harvey',
709
+ kind: 'endmill',
710
+ familyCode: 'HT-Harvey-EndMill-029',
711
+ rows: 152,
712
+ columns: {
713
+ DC: 'CUTTER DIAMETER',
714
+ SFDM: 'SHANK DIAMETER',
715
+ OAL: 'OVERALL LENGTH',
716
+ LCF: 'LENGTH OF CUT',
717
+ NOF: 'FLUTES',
718
+ },
719
+ facts: {
720
+ unit: MILLIMETERS,
721
+ bmc: SOLID_CARBIDE,
722
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Stub & Standard - Metric'),
723
+ coolantThrough: NO_COOLANT_THROUGH,
724
+ },
725
+ },
726
+ // Miniature End Mills - Ball - Stub & Standard - Metric
727
+ 'harvey_endmill_030.csv': {
728
+ id: 'endmill-030',
729
+ brand: 'harvey',
730
+ kind: 'endmill',
731
+ familyCode: 'HT-Harvey-EndMill-030',
732
+ rows: 144,
733
+ columns: {
734
+ DC: 'CUTTER DIAMETER',
735
+ SFDM: 'SHANK DIAMETER',
736
+ OAL: 'OVERALL LENGTH',
737
+ LCF: 'LENGTH OF CUT',
738
+ NOF: 'FLUTES',
739
+ },
740
+ facts: {
741
+ unit: MILLIMETERS,
742
+ bmc: SOLID_CARBIDE,
743
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Stub & Standard - Metric'),
744
+ coolantThrough: NO_COOLANT_THROUGH,
745
+ },
746
+ },
747
+ // Miniature End Mills - Square - Stub & Standard - 5 Flute
748
+ 'harvey_endmill_031.csv': {
749
+ id: 'endmill-031',
750
+ brand: 'harvey',
751
+ kind: 'endmill',
752
+ familyCode: 'HT-Harvey-EndMill-031',
753
+ rows: 170,
754
+ columns: {
755
+ DC: 'CUTTER DIA.',
756
+ SFDM: 'SHANK DIA.',
757
+ OAL: 'OAL',
758
+ LCF: 'LOC',
759
+ NOF: 'FLUTES',
760
+ },
761
+ facts: {
762
+ unit: INCHES,
763
+ bmc: SOLID_CARBIDE,
764
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Stub & Standard - 5 Flute'),
765
+ coolantThrough: NO_COOLANT_THROUGH,
766
+ },
767
+ },
768
+ // Miniature End Mills - Square - Coolant Through
769
+ 'harvey_endmill_032.csv': {
770
+ id: 'endmill-032',
771
+ brand: 'harvey',
772
+ kind: 'endmill',
773
+ familyCode: 'HT-Harvey-EndMill-032',
774
+ rows: 24,
775
+ columns: {
776
+ DC: 'CUTTER DIA.',
777
+ SFDM: 'SHANK DIA.',
778
+ OAL: 'OAL',
779
+ LCF: 'LOC',
780
+ NOF: 'FLUTES',
781
+ },
782
+ facts: {
783
+ unit: INCHES,
784
+ bmc: SOLID_CARBIDE,
785
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Coolant Through'),
786
+ coolantThrough: {
787
+ value: true,
788
+ source: 'vendor-stated',
789
+ cite: "the page's own productTitle, 'Miniature End Mills - Square - Coolant Through'",
790
+ },
791
+ },
792
+ },
793
+ // Miniature End Mills - Ball - Stub & Standard - 5 Flute
794
+ 'harvey_endmill_033.csv': {
795
+ id: 'endmill-033',
796
+ brand: 'harvey',
797
+ kind: 'endmill',
798
+ familyCode: 'HT-Harvey-EndMill-033',
799
+ rows: 122,
800
+ columns: {
801
+ DC: 'CUTTER DIA.',
802
+ SFDM: 'SHANK DIA.',
803
+ OAL: 'OAL',
804
+ LCF: 'LOC',
805
+ NOF: 'FLUTES',
806
+ },
807
+ facts: {
808
+ unit: INCHES,
809
+ bmc: SOLID_CARBIDE,
810
+ profile: statedProfile('Ball', 'Miniature End Mills - Ball - Stub & Standard - 5 Flute'),
811
+ coolantThrough: NO_COOLANT_THROUGH,
812
+ },
813
+ },
814
+ // Miniature End Mills - Corner Radius - Stub & Standard - 5 Flute
815
+ 'harvey_endmill_034.csv': {
816
+ id: 'endmill-034',
817
+ brand: 'harvey',
818
+ kind: 'endmill',
819
+ familyCode: 'HT-Harvey-EndMill-034',
820
+ rows: 154,
821
+ columns: {
822
+ DC: 'CUTTER DIA.',
823
+ SFDM: 'SHANK DIA.',
824
+ OAL: 'OAL',
825
+ LCF: 'LENGTH OF CUT',
826
+ RE: 'CORNER RADIUS',
827
+ NOF: 'FLUTES',
828
+ },
829
+ facts: {
830
+ unit: INCHES,
831
+ bmc: SOLID_CARBIDE,
832
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Stub & Standard - 5 Flute'),
833
+ coolantThrough: NO_COOLANT_THROUGH,
834
+ },
835
+ },
836
+ // Miniature End Mills - Tapered - Corner Radius
837
+ 'harvey_endmill_035.csv': {
838
+ id: 'endmill-035',
839
+ brand: 'harvey',
840
+ kind: 'endmill',
841
+ familyCode: 'HT-Harvey-EndMill-035',
842
+ rows: 40,
843
+ columns: {
844
+ DC: 'CUTTER DIAMETER',
845
+ SFDM: 'SHANK DIAMETER',
846
+ OAL: 'OVERALL LENGTH',
847
+ LCF: 'LENGTH OF CUT',
848
+ RE: 'CORNER RADIUS',
849
+ NOF: 'FLUTES',
850
+ },
851
+ facts: {
852
+ unit: INCHES,
853
+ bmc: SOLID_CARBIDE,
854
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Tapered - Corner Radius'),
855
+ coolantThrough: NO_COOLANT_THROUGH,
856
+ },
857
+ },
858
+ // Miniature End Mills - Square - Long Flute - 5 Flute
859
+ 'harvey_endmill_036.csv': {
860
+ id: 'endmill-036',
861
+ brand: 'harvey',
862
+ kind: 'endmill',
863
+ familyCode: 'HT-Harvey-EndMill-036',
864
+ rows: 32,
865
+ columns: {
866
+ DC: 'CUTTER DIA.',
867
+ SFDM: 'SHANK DIA.',
868
+ OAL: 'OAL',
869
+ LCF: 'LENGTH OF CUT',
870
+ NOF: 'FLUTES',
871
+ },
872
+ facts: {
873
+ unit: INCHES,
874
+ bmc: SOLID_CARBIDE,
875
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Flute - 5 Flute'),
876
+ coolantThrough: NO_COOLANT_THROUGH,
877
+ },
878
+ },
879
+ // Miniature End Mills - Square - Long Reach, Standard Flute - 5 Flute
880
+ 'harvey_endmill_037.csv': {
881
+ id: 'endmill-037',
882
+ brand: 'harvey',
883
+ kind: 'endmill',
884
+ familyCode: 'HT-Harvey-EndMill-037',
885
+ rows: 32,
886
+ columns: {
887
+ DC: 'CUTTER DIAMETER',
888
+ SFDM: 'SHANK DIAMETER',
889
+ OAL: 'OVERALL LENGTH',
890
+ LCF: 'LENGTH OF CUT',
891
+ 'shoulder-length': 'OVERALL REACH',
892
+ NOF: 'FLUTES',
893
+ },
894
+ facts: {
895
+ unit: INCHES,
896
+ bmc: SOLID_CARBIDE,
897
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Reach, Standard Flute - 5 Flute'),
898
+ coolantThrough: NO_COOLANT_THROUGH,
899
+ },
900
+ },
901
+ // Miniature End Mills - Corner Radius - Stub & Standard - Metric
902
+ 'harvey_endmill_038.csv': {
903
+ id: 'endmill-038',
904
+ brand: 'harvey',
905
+ kind: 'endmill',
906
+ familyCode: 'HT-Harvey-EndMill-038',
907
+ rows: 64,
908
+ columns: {
909
+ DC: 'CUTTER DIA.',
910
+ SFDM: 'SHANK DIA.',
911
+ OAL: 'OAL',
912
+ LCF: 'LENGTH OF CUT',
913
+ RE: 'CORNER RADIUS',
914
+ NOF: 'FLUTES',
915
+ },
916
+ facts: {
917
+ unit: MILLIMETERS,
918
+ bmc: SOLID_CARBIDE,
919
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Stub & Standard - Metric'),
920
+ coolantThrough: NO_COOLANT_THROUGH,
921
+ },
922
+ },
923
+ // Miniature End Mills - Square - Long Flute - Metric
924
+ 'harvey_endmill_039.csv': {
925
+ id: 'endmill-039',
926
+ brand: 'harvey',
927
+ kind: 'endmill',
928
+ familyCode: 'HT-Harvey-EndMill-039',
929
+ rows: 44,
930
+ columns: {
931
+ DC: 'CUTTER DIA.',
932
+ SFDM: 'SHANK DIA.',
933
+ OAL: 'OAL',
934
+ LCF: 'LENGTH OF CUT',
935
+ NOF: 'FLUTES',
936
+ },
937
+ facts: {
938
+ unit: MILLIMETERS,
939
+ bmc: SOLID_CARBIDE,
940
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Flute - Metric'),
941
+ coolantThrough: NO_COOLANT_THROUGH,
942
+ },
943
+ },
944
+ // Miniature End Mills - Square - Long Reach, Standard Flute - Metric
945
+ 'harvey_endmill_041.csv': {
946
+ id: 'endmill-041',
947
+ brand: 'harvey',
948
+ kind: 'endmill',
949
+ familyCode: 'HT-Harvey-EndMill-041',
950
+ rows: 32,
951
+ columns: {
952
+ DC: 'CUTTER DIA.',
953
+ SFDM: 'SHANK DIA.',
954
+ OAL: 'OAL',
955
+ LCF: 'LENGTH OF CUT',
956
+ 'shoulder-length': 'OVERALL REACH',
957
+ NOF: 'FLUTES',
958
+ },
959
+ facts: {
960
+ unit: MILLIMETERS,
961
+ bmc: SOLID_CARBIDE,
962
+ profile: statedProfile('Square', 'Miniature End Mills - Square - Long Reach, Standard Flute - Metric'),
963
+ coolantThrough: NO_COOLANT_THROUGH,
964
+ },
965
+ },
966
+ // Miniature End Mills - Corner Radius - Chipbreaker
967
+ 'harvey_endmill_042.csv': {
968
+ id: 'endmill-042',
969
+ brand: 'harvey',
970
+ kind: 'endmill',
971
+ familyCode: 'HT-Harvey-EndMill-042',
972
+ rows: 24,
973
+ columns: {
974
+ DC: 'CUTTER DIA.',
975
+ SFDM: 'SHANK DIA.',
976
+ OAL: 'OAL',
977
+ LCF: 'LENGTH OF CUT',
978
+ RE: 'CORNER RADIUS',
979
+ NOF: 'FLUTES',
980
+ },
981
+ facts: {
982
+ unit: INCHES,
983
+ bmc: SOLID_CARBIDE,
984
+ profile: statedProfile('Corner Radius', 'Miniature End Mills - Corner Radius - Chipbreaker'),
985
+ coolantThrough: NO_COOLANT_THROUGH,
986
+ },
987
+ },
988
+ // Keyseat Cutters - Corner Radius
989
+ 'harvey_keyseat_001.csv': {
990
+ id: 'keyseat-001',
991
+ brand: 'harvey',
992
+ kind: 'endmill',
993
+ familyCode: 'HT-Harvey-Keyseat-001',
994
+ rows: 345,
995
+ columns: {
996
+ DC: 'CUTTER DIA.',
997
+ SFDM: 'SHANK DIA.',
998
+ OAL: 'OAL',
999
+ LCF: 'CUTTER WIDTH',
1000
+ RE: 'CORNER RADIUS',
1001
+ 'shoulder-length': 'NECK LENGTH',
1002
+ 'shoulder-diameter': 'NECK DIA.',
1003
+ NOF: 'FLUTES',
1004
+ },
1005
+ facts: {
1006
+ unit: INCHES,
1007
+ bmc: SOLID_CARBIDE,
1008
+ profile: statedProfile('Corner Radius', 'Keyseat Cutters - Corner Radius'),
1009
+ coolantThrough: NO_COOLANT_THROUGH,
1010
+ },
1011
+ },
1012
+ // Keyseat Cutters - Corner Radius - Reduced Shank
1013
+ 'harvey_keyseat_002.csv': {
1014
+ id: 'keyseat-002',
1015
+ brand: 'harvey',
1016
+ kind: 'endmill',
1017
+ familyCode: 'HT-Harvey-Keyseat-002',
1018
+ rows: 114,
1019
+ columns: {
1020
+ DC: 'CUTTER DIA.',
1021
+ SFDM: 'SHANK DIA.',
1022
+ OAL: 'OAL',
1023
+ LCF: 'CUTTER WIDTH',
1024
+ RE: 'CORNER RADIUS',
1025
+ NOF: 'FLUTES',
1026
+ },
1027
+ facts: {
1028
+ unit: INCHES,
1029
+ bmc: SOLID_CARBIDE,
1030
+ profile: statedProfile('Corner Radius', 'Keyseat Cutters - Corner Radius - Reduced Shank'),
1031
+ coolantThrough: NO_COOLANT_THROUGH,
1032
+ },
1033
+ },
1034
+ // Keyseat Cutters - Full Radius
1035
+ 'harvey_keyseat_003.csv': {
1036
+ id: 'keyseat-003',
1037
+ brand: 'harvey',
1038
+ kind: 'endmill',
1039
+ familyCode: 'HT-Harvey-Keyseat-003',
1040
+ rows: 174,
1041
+ columns: {
1042
+ DC: 'CUTTER DIA.',
1043
+ SFDM: 'SHANK DIA.',
1044
+ OAL: 'OAL',
1045
+ LCF: 'CUTTER WIDTH',
1046
+ RE: 'RADIUS',
1047
+ 'shoulder-length': 'NECK LENGTH',
1048
+ 'shoulder-diameter': 'NECK DIA.',
1049
+ NOF: 'FLUTES',
1050
+ },
1051
+ facts: {
1052
+ unit: INCHES,
1053
+ bmc: SOLID_CARBIDE,
1054
+ profile: statedProfile('Full Radius', 'Keyseat Cutters - Full Radius'),
1055
+ coolantThrough: NO_COOLANT_THROUGH,
1056
+ },
1057
+ },
1058
+ // Keyseat Cutters - Full Radius - Reduced Shank
1059
+ 'harvey_keyseat_004.csv': {
1060
+ id: 'keyseat-004',
1061
+ brand: 'harvey',
1062
+ kind: 'endmill',
1063
+ familyCode: 'HT-Harvey-Keyseat-004',
1064
+ rows: 74,
1065
+ columns: {
1066
+ DC: 'CUTTER DIA.',
1067
+ SFDM: 'SHANK DIA.',
1068
+ OAL: 'OAL',
1069
+ LCF: 'CUTTER WIDTH',
1070
+ RE: 'RADIUS',
1071
+ NOF: 'FLUTES',
1072
+ },
1073
+ facts: {
1074
+ unit: INCHES,
1075
+ bmc: SOLID_CARBIDE,
1076
+ profile: statedProfile('Full Radius', 'Keyseat Cutters - Full Radius - Reduced Shank'),
1077
+ coolantThrough: NO_COOLANT_THROUGH,
1078
+ },
1079
+ },
1080
+ // Keyseat Cutters - Retaining Ring Keyseat Cutters
1081
+ 'harvey_keyseat_005.csv': {
1082
+ id: 'keyseat-005',
1083
+ brand: 'harvey',
1084
+ kind: 'endmill',
1085
+ familyCode: 'HT-Harvey-Keyseat-005',
1086
+ rows: 26,
1087
+ columns: {
1088
+ DC: 'CUTTER DIA.',
1089
+ SFDM: 'SHANK DIA.',
1090
+ OAL: 'OAL',
1091
+ LCF: 'CUTTER WIDTH',
1092
+ 'shoulder-length': 'NECK LENGTH',
1093
+ 'shoulder-diameter': 'NECK DIA.',
1094
+ NOF: 'FLUTES',
1095
+ },
1096
+ facts: {
1097
+ unit: INCHES,
1098
+ bmc: SOLID_CARBIDE,
1099
+ profile: {
1100
+ value: 'Square',
1101
+ source: 'assumed',
1102
+ note: 'the title names no profile and the table publishes no radius column; a ' +
1103
+ 'retaining-ring groove is square-bottomed',
1104
+ checked: '2026-08-29',
1105
+ by: 'JG',
1106
+ },
1107
+ coolantThrough: NO_COOLANT_THROUGH,
1108
+ },
1109
+ },
1110
+ // Keyseat Cutters - Square
1111
+ 'harvey_keyseat_006.csv': {
1112
+ id: 'keyseat-006',
1113
+ brand: 'harvey',
1114
+ kind: 'endmill',
1115
+ familyCode: 'HT-Harvey-Keyseat-006',
1116
+ rows: 926,
1117
+ columns: {
1118
+ DC: 'CUTTER DIA.',
1119
+ SFDM: 'SHANK DIA.',
1120
+ OAL: 'OAL',
1121
+ LCF: 'CUTTER WIDTH',
1122
+ 'shoulder-length': 'NECK LENGTH',
1123
+ 'shoulder-diameter': 'NECK DIA.',
1124
+ NOF: 'FLUTES',
1125
+ },
1126
+ facts: {
1127
+ unit: INCHES,
1128
+ bmc: SOLID_CARBIDE,
1129
+ profile: statedProfile('Square', 'Keyseat Cutters - Square'),
1130
+ coolantThrough: NO_COOLANT_THROUGH,
1131
+ },
1132
+ },
1133
+ // Keyseat Cutters - Square - For Hardened Steels
1134
+ 'harvey_keyseat_007.csv': {
1135
+ id: 'keyseat-007',
1136
+ brand: 'harvey',
1137
+ kind: 'endmill',
1138
+ familyCode: 'HT-Harvey-Keyseat-007',
1139
+ rows: 49,
1140
+ columns: {
1141
+ DC: 'CUTTER DIA.',
1142
+ SFDM: 'SHANK DIA.',
1143
+ OAL: 'OAL',
1144
+ LCF: 'CUTTER WIDTH',
1145
+ 'shoulder-length': 'NECK LENGTH',
1146
+ 'shoulder-diameter': 'NECK DIA.',
1147
+ NOF: 'FLUTES',
1148
+ },
1149
+ facts: {
1150
+ unit: INCHES,
1151
+ bmc: SOLID_CARBIDE,
1152
+ profile: statedProfile('Square', 'Keyseat Cutters - Square - For Hardened Steels'),
1153
+ coolantThrough: NO_COOLANT_THROUGH,
1154
+ },
1155
+ },
1156
+ // Keyseat Cutters - Square - For Non - Ferrous Materials
1157
+ 'harvey_keyseat_008.csv': {
1158
+ id: 'keyseat-008',
1159
+ brand: 'harvey',
1160
+ kind: 'endmill',
1161
+ familyCode: 'HT-Harvey-Keyseat-008',
1162
+ rows: 108,
1163
+ columns: {
1164
+ DC: 'CUTTER DIA.',
1165
+ SFDM: 'SHANK DIA.',
1166
+ OAL: 'OAL',
1167
+ LCF: 'CUTTER WIDTH',
1168
+ 'shoulder-length': 'NECK LENGTH',
1169
+ 'shoulder-diameter': 'NECK DIA.',
1170
+ NOF: 'FLUTES',
1171
+ },
1172
+ facts: {
1173
+ unit: INCHES,
1174
+ bmc: SOLID_CARBIDE,
1175
+ profile: statedProfile('Square', 'Keyseat Cutters - Square - For Non - Ferrous Materials'),
1176
+ coolantThrough: NO_COOLANT_THROUGH,
1177
+ },
1178
+ },
1179
+ // Keyseat Cutters - Square - Reduced Shank
1180
+ 'harvey_keyseat_009.csv': {
1181
+ id: 'keyseat-009',
1182
+ brand: 'harvey',
1183
+ kind: 'endmill',
1184
+ familyCode: 'HT-Harvey-Keyseat-009',
1185
+ rows: 220,
1186
+ columns: {
1187
+ DC: 'CUTTER DIA.',
1188
+ SFDM: 'SHANK DIA.',
1189
+ OAL: 'OAL',
1190
+ LCF: 'CUTTER WIDTH',
1191
+ NOF: 'FLUTES',
1192
+ },
1193
+ facts: {
1194
+ unit: INCHES,
1195
+ bmc: SOLID_CARBIDE,
1196
+ profile: statedProfile('Square', 'Keyseat Cutters - Square - Reduced Shank'),
1197
+ coolantThrough: NO_COOLANT_THROUGH,
1198
+ },
1199
+ },
1200
+ // Keyseat Cutters - Staggered Tooth - Corner Radius
1201
+ 'harvey_keyseat_010.csv': {
1202
+ id: 'keyseat-010',
1203
+ brand: 'harvey',
1204
+ kind: 'endmill',
1205
+ familyCode: 'HT-Harvey-Keyseat-010',
1206
+ rows: 101,
1207
+ columns: {
1208
+ DC: 'CUTTER DIA.',
1209
+ SFDM: 'SHANK DIA.',
1210
+ OAL: 'OAL',
1211
+ LCF: 'CUTTER WIDTH',
1212
+ RE: 'CORNER RADIUS',
1213
+ 'shoulder-length': 'NECK LENGTH',
1214
+ 'shoulder-diameter': 'NECK DIA.',
1215
+ NOF: 'FLUTES',
1216
+ },
1217
+ facts: {
1218
+ unit: INCHES,
1219
+ bmc: SOLID_CARBIDE,
1220
+ profile: statedProfile('Corner Radius', 'Keyseat Cutters - Staggered Tooth - Corner Radius'),
1221
+ coolantThrough: NO_COOLANT_THROUGH,
1222
+ },
1223
+ },
1224
+ // Keyseat Cutters - Staggered Tooth - Square
1225
+ 'harvey_keyseat_011.csv': {
1226
+ id: 'keyseat-011',
1227
+ brand: 'harvey',
1228
+ kind: 'endmill',
1229
+ familyCode: 'HT-Harvey-Keyseat-011',
1230
+ rows: 88,
1231
+ columns: {
1232
+ DC: 'CUTTER DIA.',
1233
+ SFDM: 'SHANK DIA.',
1234
+ OAL: 'OAL',
1235
+ LCF: 'CUTTER WIDTH',
1236
+ 'shoulder-length': 'NECK LENGTH',
1237
+ 'shoulder-diameter': 'NECK DIA.',
1238
+ NOF: 'FLUTES',
1239
+ },
1240
+ facts: {
1241
+ unit: INCHES,
1242
+ bmc: SOLID_CARBIDE,
1243
+ profile: statedProfile('Square', 'Keyseat Cutters - Staggered Tooth - Square'),
1244
+ coolantThrough: NO_COOLANT_THROUGH,
1245
+ },
1246
+ },
1247
+ // Keyseat Cutters - Staggered Tooth - Square - Reduced Shank
1248
+ 'harvey_keyseat_012.csv': {
1249
+ id: 'keyseat-012',
1250
+ brand: 'harvey',
1251
+ kind: 'endmill',
1252
+ familyCode: 'HT-Harvey-Keyseat-012',
1253
+ rows: 36,
1254
+ columns: {
1255
+ DC: 'CUTTER DIA.',
1256
+ SFDM: 'SHANK DIA.',
1257
+ OAL: 'OAL',
1258
+ LCF: 'CUTTER WIDTH',
1259
+ NOF: 'FLUTES',
1260
+ },
1261
+ facts: {
1262
+ unit: INCHES,
1263
+ bmc: SOLID_CARBIDE,
1264
+ profile: statedProfile('Square', 'Keyseat Cutters - Staggered Tooth - Square - Reduced Shank'),
1265
+ coolantThrough: NO_COOLANT_THROUGH,
1266
+ },
1267
+ },
1268
+ };
1269
+ /**
1270
+ * The product page each family is scraped from, keyed by its CSV name.
1271
+ *
1272
+ * Paths rather than URLs: `vendors/harvey/scrape.ts` owns the host, so a family
1273
+ * config cannot put a scrape on a different one.
1274
+ */
1275
+ export const PRODUCT_PAGES = {
1276
+ 'harvey_endmill_001.csv': '/products/end-mills---ball---reduced-shank',
1277
+ 'harvey_endmill_002.csv': '/products/end-mills---corner-radius---reduced-shank',
1278
+ 'harvey_endmill_003.csv': '/products/end-mills---square---reduced-shank',
1279
+ 'harvey_endmill_004.csv': '/products/miniature-end-mills---ball---long-flute',
1280
+ 'harvey_endmill_005.csv': '/products/miniature-end-mills---ball---long-reach-long-flute',
1281
+ 'harvey_endmill_006.csv': '/products/miniature-end-mills---ball---long-reach-standard-flute',
1282
+ 'harvey_endmill_007.csv': '/products/miniature-end-mills---ball---long-reach-stub-flute',
1283
+ 'harvey_endmill_008.csv': '/products/miniature-end-mills---ball---stub--standard',
1284
+ 'harvey_endmill_009.csv': '/products/miniature-end-mills---ball---tapered-reach-clearance-cutters',
1285
+ 'harvey_endmill_010.csv': '/products/miniature-end-mills---tapered---ball',
1286
+ 'harvey_endmill_011.csv': '/products/miniature-end-mills---corner-radius---long-flute',
1287
+ 'harvey_endmill_012.csv': '/products/miniature-end-mills---corner-radius---long-reach-standard-flute',
1288
+ 'harvey_endmill_013.csv': '/products/miniature-end-mills---corner-radius---long-reach-stub-flute',
1289
+ 'harvey_endmill_014.csv': '/products/miniature-end-mills---corner-radius---stub--standard',
1290
+ 'harvey_endmill_015.csv': '/products/miniature-end-mills---square---deburring-end-mill',
1291
+ 'harvey_endmill_016.csv': '/products/miniature-end-mills---square---long-flute',
1292
+ 'harvey_endmill_017.csv': '/products/miniature-end-mills---square---long-reach-long-flute',
1293
+ 'harvey_endmill_018.csv': '/products/miniature-end-mills---square---long-reach-standard-flute',
1294
+ 'harvey_endmill_019.csv': '/products/miniature-end-mills---square---long-reach-stub-flute',
1295
+ 'harvey_endmill_020.csv': '/products/miniature-end-mills---square---stub--standard',
1296
+ 'harvey_endmill_021.csv': '/products/miniature-end-mills---square---tapered-reach-clearance-cutters',
1297
+ 'harvey_endmill_022.csv': '/products/miniature-end-mills---tapered---square',
1298
+ 'harvey_endmill_023.csv': '/products/miniature-end-mills---ball---deburring-end-mill',
1299
+ 'harvey_endmill_025.csv': '/products/miniature-end-mills---ball---extra-long-length',
1300
+ 'harvey_endmill_026.csv': '/products/miniature-end-mills---corner-radius---extra-long-length',
1301
+ 'harvey_endmill_027.csv': '/products/miniature-end-mills---square---extra-long-length',
1302
+ 'harvey_endmill_028.csv': '/products/miniature-end-mills---square---router-style',
1303
+ 'harvey_endmill_029.csv': '/products/miniature-end-mills-square-stub--standard-metric',
1304
+ 'harvey_endmill_030.csv': '/products/miniature-end-mills-ball-stub--standard-metric',
1305
+ 'harvey_endmill_031.csv': '/products/miniature-end-mills-square-stub--standard-5-flute',
1306
+ 'harvey_endmill_032.csv': '/products/miniature-end-mills-square-coolant-through',
1307
+ 'harvey_endmill_033.csv': '/products/miniature-end-mills-ball-stub--standard-5-flute',
1308
+ 'harvey_endmill_034.csv': '/products/miniature-end-mills-corner-radius-stub--standard-5-flute',
1309
+ 'harvey_endmill_035.csv': '/products/miniature-end-mills-tapered-corner-radius',
1310
+ 'harvey_endmill_036.csv': '/products/miniature-end-mills-square-long-flute-5-flute',
1311
+ 'harvey_endmill_037.csv': '/products/miniature-end-mills-square-long-reach-standard-flute-5-flute',
1312
+ 'harvey_endmill_038.csv': '/products/miniature-end-mills-corner-radius-stub--standard-metric',
1313
+ 'harvey_endmill_039.csv': '/products/miniature-end-mills-square-long-flute-metric',
1314
+ 'harvey_endmill_041.csv': '/products/miniature-end-mills-square-long-reach-standard-flute-metric',
1315
+ 'harvey_endmill_042.csv': '/products/miniature-end-mills-corner-radius-chipbreaker',
1316
+ 'harvey_keyseat_001.csv': '/products/keyseat-cutters---corner-radius',
1317
+ 'harvey_keyseat_002.csv': '/products/keyseat-cutters---corner-radius---reduced-shank',
1318
+ 'harvey_keyseat_003.csv': '/products/keyseat-cutters---full-radius',
1319
+ 'harvey_keyseat_004.csv': '/products/keyseat-cutters---full-radius---reduced-shank',
1320
+ 'harvey_keyseat_005.csv': '/products/keyseat-cutters---retaining-ring-keyseat-cutters',
1321
+ 'harvey_keyseat_006.csv': '/products/keyseat-cutters---square',
1322
+ 'harvey_keyseat_007.csv': '/products/keyseat-cutters---square---for-hardened-steels',
1323
+ 'harvey_keyseat_008.csv': '/products/keyseat-cutters---square---for-non-ferrous-materials',
1324
+ 'harvey_keyseat_009.csv': '/products/keyseat-cutters---square---reduced-shank',
1325
+ 'harvey_keyseat_010.csv': '/products/keyseat-cutters---staggered-tooth---corner-radius',
1326
+ 'harvey_keyseat_011.csv': '/products/keyseat-cutters---staggered-tooth---square',
1327
+ 'harvey_keyseat_012.csv': '/products/keyseat-cutters---staggered-tooth---square---reduced-shank',
1328
+ };