@toolpath/tool-scraper 0.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.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/conventions.d.ts +124 -0
- package/dist/conventions.js +143 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.js +53 -0
- package/dist/families/destinytool.d.ts +49 -0
- package/dist/families/destinytool.js +55 -0
- package/dist/families/index.d.ts +59 -0
- package/dist/families/index.js +91 -0
- package/dist/families/kennametal.d.ts +757 -0
- package/dist/families/kennametal.js +660 -0
- package/dist/families/regofix.d.ts +185 -0
- package/dist/families/regofix.js +250 -0
- package/dist/family.d.ts +130 -0
- package/dist/family.js +38 -0
- package/dist/fetch.d.ts +98 -0
- package/dist/fetch.js +116 -0
- package/dist/identity.d.ts +133 -0
- package/dist/identity.js +118 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +31 -0
- package/dist/node/cad-mirror.d.ts +55 -0
- package/dist/node/cad-mirror.js +89 -0
- package/dist/node/cli.d.ts +35 -0
- package/dist/node/cli.js +340 -0
- package/dist/node/csv.d.ts +47 -0
- package/dist/node/csv.js +123 -0
- package/dist/node/index.d.ts +16 -0
- package/dist/node/index.js +16 -0
- package/dist/node/main.d.ts +13 -0
- package/dist/node/main.js +14 -0
- package/dist/node/paths.d.ts +60 -0
- package/dist/node/paths.js +80 -0
- package/dist/node/receipts.d.ts +100 -0
- package/dist/node/receipts.js +107 -0
- package/dist/order.d.ts +10 -0
- package/dist/order.js +12 -0
- package/dist/provenance.d.ts +125 -0
- package/dist/provenance.js +133 -0
- package/dist/records.d.ts +305 -0
- package/dist/records.js +297 -0
- package/dist/registry.d.ts +63 -0
- package/dist/registry.js +145 -0
- package/dist/scrape.d.ts +70 -0
- package/dist/scrape.js +37 -0
- package/dist/thread.d.ts +48 -0
- package/dist/thread.js +98 -0
- package/dist/uuid5.d.ts +31 -0
- package/dist/uuid5.js +64 -0
- package/dist/vendors/destinytool/index.d.ts +11 -0
- package/dist/vendors/destinytool/index.js +11 -0
- package/dist/vendors/destinytool/records.d.ts +118 -0
- package/dist/vendors/destinytool/records.js +266 -0
- package/dist/vendors/destinytool/scrape.d.ts +108 -0
- package/dist/vendors/destinytool/scrape.js +192 -0
- package/dist/vendors/kennametal/cad.d.ts +87 -0
- package/dist/vendors/kennametal/cad.js +119 -0
- package/dist/vendors/kennametal/index.d.ts +21 -0
- package/dist/vendors/kennametal/index.js +21 -0
- package/dist/vendors/kennametal/materials.d.ts +143 -0
- package/dist/vendors/kennametal/materials.js +200 -0
- package/dist/vendors/kennametal/records.d.ts +88 -0
- package/dist/vendors/kennametal/records.js +241 -0
- package/dist/vendors/kennametal/scrape.d.ts +111 -0
- package/dist/vendors/kennametal/scrape.js +226 -0
- package/dist/vendors/kennametal/thread-column.d.ts +28 -0
- package/dist/vendors/kennametal/thread-column.js +41 -0
- package/dist/vendors/regofix/index.d.ts +8 -0
- package/dist/vendors/regofix/index.js +8 -0
- package/dist/vendors/regofix/scrape.d.ts +237 -0
- package/dist/vendors/regofix/scrape.js +521 -0
- package/package.json +76 -0
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kennametal's and WIDIA's families.
|
|
3
|
+
*
|
|
4
|
+
* One module because they are one platform: the same AEM/Hybris component on the
|
|
5
|
+
* same URL shape, differing only in host, component node and vendor string —
|
|
6
|
+
* `identity.BRANDS` is where that is recorded, and `vendors/kennametal/` is the
|
|
7
|
+
* one adapter that serves both. Their *receipts* stay separate, because an
|
|
8
|
+
* adapter is a fact about code and a scraped CSV is a fact about who published
|
|
9
|
+
* it.
|
|
10
|
+
*
|
|
11
|
+
* `familyCode` is the vendor's numeric family code, lifted out of the family
|
|
12
|
+
* page URL to scrape the table in the first place. It is config rather than
|
|
13
|
+
* runbook prose because `materials` needs it *after* the scrape, to re-query the
|
|
14
|
+
* same family through the workpiece-material facet — recording it here is what
|
|
15
|
+
* makes the material sweep re-runnable without going back to the browser.
|
|
16
|
+
*
|
|
17
|
+
* **Holder families carry no `familyCode`**, and that is a gap rather than a
|
|
18
|
+
* rule: they were scraped by hand from a code read off the page at the time. A
|
|
19
|
+
* re-scrape needs the code passed on the command line until somebody records it.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Facts several families state identically, named once.
|
|
23
|
+
*
|
|
24
|
+
* A `cite` is what a person re-reads to check a vendor claim, so the same
|
|
25
|
+
* claim has to read the same everywhere it is made — and eight copies of one
|
|
26
|
+
* sentence are eight edits when the vendor's page changes, which is how four
|
|
27
|
+
* of them acquired word-joining typos before this was extracted. A fact stays
|
|
28
|
+
* inline where one family states it.
|
|
29
|
+
*/
|
|
30
|
+
const NO_COOLANT_COLUMN = {
|
|
31
|
+
value: false,
|
|
32
|
+
source: 'assumed',
|
|
33
|
+
note: 'the table publishes no coolant column and the family page shows none',
|
|
34
|
+
checked: '2026-08-05',
|
|
35
|
+
by: 'JG',
|
|
36
|
+
};
|
|
37
|
+
const CARBIDE_GRADE_COLUMN = {
|
|
38
|
+
value: 'carbide',
|
|
39
|
+
source: 'vendor-stated',
|
|
40
|
+
cite: 'the Grade column names a Kennametal carbide grade (KC7325, KCU20)',
|
|
41
|
+
};
|
|
42
|
+
const TWO_FLUTE_STRAIGHT = {
|
|
43
|
+
value: 2,
|
|
44
|
+
source: 'assumed',
|
|
45
|
+
note: 'no flute-count column; the vendor\'s "Straight Fluted" names the helix, not the count',
|
|
46
|
+
checked: '2026-08-06',
|
|
47
|
+
by: 'JG',
|
|
48
|
+
};
|
|
49
|
+
const POINT_ANGLE_142 = {
|
|
50
|
+
value: 142,
|
|
51
|
+
source: 'derived',
|
|
52
|
+
note: "no point angle is published on either family, either variant table or a product page. L5 (point length) is, and for a conical point L5 = D1 / (2·tan(SIG/2)). Least squares over all 49 rows gives 142.46° inch and 142.55° metric; at 142° the worst L5 residual is 0.05 mm — the vendor's own rounding — against 0.24 mm at 140°, which is ruled out",
|
|
53
|
+
};
|
|
54
|
+
const INTERNAL_COOLANT_TITLE = {
|
|
55
|
+
value: true,
|
|
56
|
+
source: 'vendor-stated',
|
|
57
|
+
cite: '"Internal Coolant" is in the vendor\'s own family title',
|
|
58
|
+
};
|
|
59
|
+
const PCD_NON_FERROUS = {
|
|
60
|
+
value: true,
|
|
61
|
+
source: 'vendor-stated',
|
|
62
|
+
cite: 'grade KD1415 is "PCD-tip brazed to carbide for … aluminum …, non-ferrous heavy metals, and plastics"; breadcrumb "PCD Tooling / PCD Drills • Aluminum Machining"; the facet returns N1-N4 and nothing else',
|
|
63
|
+
};
|
|
64
|
+
const PCD_SUBSTRATE = {
|
|
65
|
+
value: 'diamond',
|
|
66
|
+
source: 'vendor-stated',
|
|
67
|
+
cite: 'grade KD1415 is PCD — the cutting material, not the carbide body it is brazed to',
|
|
68
|
+
};
|
|
69
|
+
const HSS_ASSUMED = {
|
|
70
|
+
value: 'hss',
|
|
71
|
+
source: 'assumed',
|
|
72
|
+
note: 'no substrate column; carried over from the pre-2026-08-08 config, which recorded no source for it. The KHSST line name implies high-speed steel and the Coating column carries the surface treatment instead of a carbide grade, but neither is a vendor statement of substrate',
|
|
73
|
+
checked: '2026-08-08',
|
|
74
|
+
by: 'JG',
|
|
75
|
+
};
|
|
76
|
+
const INCH_PLAIN_SHANK = {
|
|
77
|
+
value: 'inches',
|
|
78
|
+
source: 'vendor-stated',
|
|
79
|
+
cite: 'the vendor titles the family "…plain shank inch"; both unit columns are published, so this decides which is displayed',
|
|
80
|
+
};
|
|
81
|
+
const BT30_SHANK = {
|
|
82
|
+
value: 'BT30',
|
|
83
|
+
source: 'vendor-stated',
|
|
84
|
+
cite: 'the family page states the shank as JIS B 6339 / MAS 403 size 30',
|
|
85
|
+
};
|
|
86
|
+
const TAPER_CONTACT = {
|
|
87
|
+
value: 'taper',
|
|
88
|
+
source: 'vendor-stated',
|
|
89
|
+
cite: 'the family page says "Shank - SK BT JIS B 6339" with no face-contact claim',
|
|
90
|
+
};
|
|
91
|
+
const CST_COLLET_CLAMPING = {
|
|
92
|
+
value: 'collet',
|
|
93
|
+
source: 'vendor-stated',
|
|
94
|
+
cite: 'the holder publishes a CST collet series, so it grips through a collet',
|
|
95
|
+
};
|
|
96
|
+
const ER_COLLET_CHUCK = {
|
|
97
|
+
value: 'er-collet-chuck',
|
|
98
|
+
source: 'vendor-stated',
|
|
99
|
+
cite: 'breadcrumb ".../ER Collet Chucks/ER(tm) Collet Adapter -BT30"',
|
|
100
|
+
};
|
|
101
|
+
const METRIC_CATALOG = {
|
|
102
|
+
value: 'millimeters',
|
|
103
|
+
source: 'vendor-stated',
|
|
104
|
+
cite: 'the family is titled and catalogued in this system; both unit columns are usually published, so this decides which is displayed',
|
|
105
|
+
};
|
|
106
|
+
const BORE_CLAMPING = {
|
|
107
|
+
value: 'bore',
|
|
108
|
+
source: 'vendor-stated',
|
|
109
|
+
cite: 'the holder publishes a D1 bore and no collet series, so it grips the shank directly',
|
|
110
|
+
};
|
|
111
|
+
const HYDRAULIC_CHUCK = {
|
|
112
|
+
value: 'hydraulic-chuck',
|
|
113
|
+
source: 'vendor-stated',
|
|
114
|
+
cite: 'breadcrumb ".../Hydraulic Chucks - STANDARD /HP Line"',
|
|
115
|
+
};
|
|
116
|
+
const INCH_CATALOG = {
|
|
117
|
+
value: 'inches',
|
|
118
|
+
source: 'vendor-stated',
|
|
119
|
+
cite: 'the family is titled and catalogued in this system; both unit columns are usually published, so this decides which is displayed',
|
|
120
|
+
};
|
|
121
|
+
const SHRINK_FIT_FC = {
|
|
122
|
+
value: 'shrink-fit-fc',
|
|
123
|
+
source: 'vendor-stated',
|
|
124
|
+
cite: 'breadcrumb ".../Shrink Fit Toolholders"; tagline "Standard Heat Shrink Holders … Face Coolant … BT30 Backend"',
|
|
125
|
+
};
|
|
126
|
+
const SHRINK_FIT_GP = {
|
|
127
|
+
value: 'shrink-fit-gp',
|
|
128
|
+
source: 'vendor-stated',
|
|
129
|
+
cite: 'same category; tagline "Shrink Fit Toolholders General Purpose (GP)"',
|
|
130
|
+
};
|
|
131
|
+
// ── Cutting tools ──────────────────────────────────────────────────────────
|
|
132
|
+
export const FAMILIES = {
|
|
133
|
+
// `unit` is required on a drill family as of 2026-08-06 and was hardcoded
|
|
134
|
+
// to millimetres before it. Every drill table publishes both unit columns,
|
|
135
|
+
// so it is config and never inferred: it decides which column is read.
|
|
136
|
+
//
|
|
137
|
+
// `nonFerrous` is required too, and deliberately has no default: it drops
|
|
138
|
+
// the steel and stainless presets, and a family that silently defaulted to
|
|
139
|
+
// False would ship them.
|
|
140
|
+
'godrill_3xd_metric.csv': {
|
|
141
|
+
id: 'godrill-3xd-metric',
|
|
142
|
+
rows: 259,
|
|
143
|
+
familyCode: '100003658',
|
|
144
|
+
kind: 'drill',
|
|
145
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'L3' },
|
|
146
|
+
facts: {
|
|
147
|
+
unit: {
|
|
148
|
+
value: 'millimeters',
|
|
149
|
+
source: 'vendor-stated',
|
|
150
|
+
cite: 'the vendor titles the family "…3xD straight shank metric"; both unit columns are published, so this decides which is displayed',
|
|
151
|
+
},
|
|
152
|
+
flutes: {
|
|
153
|
+
value: 2,
|
|
154
|
+
source: 'assumed',
|
|
155
|
+
note: 'no flute-count column; every GOdrill in this family is a two-flute twist drill',
|
|
156
|
+
checked: '2026-07-24',
|
|
157
|
+
by: 'JG',
|
|
158
|
+
},
|
|
159
|
+
pointAngle: {
|
|
160
|
+
value: 140,
|
|
161
|
+
source: 'assumed',
|
|
162
|
+
note: 'no point angle is published anywhere on this family; 140° is the common GOdrill grind. Contrast the KenDrill TXD families, where L5 lets it be derived',
|
|
163
|
+
checked: '2026-07-24',
|
|
164
|
+
by: 'JG',
|
|
165
|
+
},
|
|
166
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
167
|
+
nonFerrous: {
|
|
168
|
+
value: false,
|
|
169
|
+
source: 'vendor-stated',
|
|
170
|
+
cite: 'the workpiece-material facet returns P M K N S H — ferrous groups included',
|
|
171
|
+
},
|
|
172
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
'kenna_universal_3xd_metric.csv': {
|
|
176
|
+
id: 'kenna-universal-3xd-metric',
|
|
177
|
+
rows: 177,
|
|
178
|
+
familyCode: '100004307',
|
|
179
|
+
kind: 'drill',
|
|
180
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'L3' },
|
|
181
|
+
facts: {
|
|
182
|
+
unit: {
|
|
183
|
+
value: 'millimeters',
|
|
184
|
+
source: 'vendor-stated',
|
|
185
|
+
cite: 'the vendor titles the family "…3xD IC straight shank metric"; both unit columns are published',
|
|
186
|
+
},
|
|
187
|
+
flutes: {
|
|
188
|
+
value: 2,
|
|
189
|
+
source: 'assumed',
|
|
190
|
+
note: 'no flute-count column; a two-flute twist drill',
|
|
191
|
+
checked: '2026-07-24',
|
|
192
|
+
by: 'JG',
|
|
193
|
+
},
|
|
194
|
+
pointAngle: {
|
|
195
|
+
value: 140,
|
|
196
|
+
source: 'assumed',
|
|
197
|
+
note: 'no point angle published on this family; the same grind assumed as GOdrill',
|
|
198
|
+
checked: '2026-07-24',
|
|
199
|
+
by: 'JG',
|
|
200
|
+
},
|
|
201
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
202
|
+
nonFerrous: {
|
|
203
|
+
value: false,
|
|
204
|
+
source: 'vendor-stated',
|
|
205
|
+
cite: 'the workpiece-material facet returns P M K N S (no H) — ferrous groups included',
|
|
206
|
+
},
|
|
207
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
// ── KenDrill TXD 5xD, PCD-tipped, internal coolant, straight shank ──
|
|
211
|
+
// Scraped JG 2026-08-06. Two vendor codes for one product line, the same
|
|
212
|
+
// split as the BT hydraulic chucks: `100165153` inch (20 rows) and
|
|
213
|
+
// `100164033` metric (29). Both are wholly active — the obsolete query
|
|
214
|
+
// returns the same counts — and their headers are byte-identical to
|
|
215
|
+
// `godrill_3xd_metric.csv`.
|
|
216
|
+
//
|
|
217
|
+
// The unit split is the vendor's own, and its catalog numbers corroborate
|
|
218
|
+
// `unit` rather than leaving it on the family title: the inch parts are
|
|
219
|
+
// `K467A…` and encode the size in ten-thousandths of an inch
|
|
220
|
+
// (`K467A02344SP` is 15/64), the metric ones `B467A…` in hundredths of a
|
|
221
|
+
// millimetre (`B467A06000SP` is 6.00 mm). On each side the native column
|
|
222
|
+
// carries the exact value and the other is rounded to four places.
|
|
223
|
+
//
|
|
224
|
+
// **`pointAngle` is 142, not the 140 the two families above assume**, and
|
|
225
|
+
// it is derived rather than published: no point angle appears on either
|
|
226
|
+
// family page, in either variant table, or on a product page (checked
|
|
227
|
+
// 2026-08-06). What *is* published is `L5`, the drill point length, and for
|
|
228
|
+
// a conical point `L5 = D1 / (2·tan(SIG/2))`. Least squares over all 49
|
|
229
|
+
// rows gives an apex of 142.46° inch / 142.55° metric; at 142° the worst
|
|
230
|
+
// residual in `L5` is 0.05 mm, which is the vendor's own rounding of a
|
|
231
|
+
// four-decimal cell, and at 140° it is 0.24 mm — five times larger and
|
|
232
|
+
// ruled out. 142.5° fits equally well and 142 was chosen (JG 2026-08-06).
|
|
233
|
+
// This is arithmetic over vendor inputs rather than a vendor statement,
|
|
234
|
+
// which is what makes it `derived` and not `assumed` — and what makes it
|
|
235
|
+
// re-checkable: `L5` is in the CSV, so a re-scrape that moved it can be
|
|
236
|
+
// caught by re-deriving the angle.
|
|
237
|
+
//
|
|
238
|
+
// **`coolantThrough` is True — the first True in this table.** Unlike the
|
|
239
|
+
// 140° above it is not an assumption: "Internal Coolant" is in the vendor's
|
|
240
|
+
// own family title on both codes.
|
|
241
|
+
//
|
|
242
|
+
// **`bmc` is 'diamond' and `nonFerrous` is True, and they are the same
|
|
243
|
+
// fact.** Grade KD1415 is, in Kennametal's words, "PCD-tip brazed to
|
|
244
|
+
// carbide for general machining of aluminum with a low silicon content,
|
|
245
|
+
// non-ferrous heavy metals, and plastics"; the breadcrumb is `PCD Tooling /
|
|
246
|
+
// PCD Drills • Aluminum Machining`, the product page states workpiece
|
|
247
|
+
// material "Non-Ferrous", and the Application Data table publishes ISO
|
|
248
|
+
// group N alone. 'diamond' names the cutting material rather than the body
|
|
249
|
+
// it is brazed to (JG 2026-08-06) — nothing in BetterToolLib's schema
|
|
250
|
+
// validates `BMC` and the web app does not display it, so the audience is
|
|
251
|
+
// Fusion's material field.
|
|
252
|
+
//
|
|
253
|
+
// `flutes` is 2, which the table does not state either. It is the same
|
|
254
|
+
// assumption as the two families above rather than a new one, and the
|
|
255
|
+
// vendor's "Straight Fluted" describes the helix, not the count.
|
|
256
|
+
'kendrill_txd_5xd_inch.csv': {
|
|
257
|
+
id: 'kendrill-txd-5xd-inch',
|
|
258
|
+
rows: 20,
|
|
259
|
+
familyCode: '100165153',
|
|
260
|
+
kind: 'drill',
|
|
261
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'L3' },
|
|
262
|
+
facts: {
|
|
263
|
+
unit: {
|
|
264
|
+
value: 'inches',
|
|
265
|
+
source: 'vendor-stated',
|
|
266
|
+
cite: 'catalog numbers are K467A… encoding the size in ten-thousandths of an inch (K467A02344SP is 15/64), and the inch column carries the exact value while the metric one is rounded',
|
|
267
|
+
},
|
|
268
|
+
flutes: TWO_FLUTE_STRAIGHT,
|
|
269
|
+
pointAngle: POINT_ANGLE_142,
|
|
270
|
+
coolantThrough: INTERNAL_COOLANT_TITLE,
|
|
271
|
+
nonFerrous: PCD_NON_FERROUS,
|
|
272
|
+
bmc: PCD_SUBSTRATE,
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
'kendrill_txd_5xd_metric.csv': {
|
|
276
|
+
id: 'kendrill-txd-5xd-metric',
|
|
277
|
+
rows: 29,
|
|
278
|
+
familyCode: '100164033',
|
|
279
|
+
kind: 'drill',
|
|
280
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'L3' },
|
|
281
|
+
facts: {
|
|
282
|
+
unit: {
|
|
283
|
+
value: 'millimeters',
|
|
284
|
+
source: 'vendor-stated',
|
|
285
|
+
cite: 'catalog numbers are B467A… encoding the size in hundredths of a millimetre (B467A06000SP is 6.00 mm), and the metric column carries the exact value while the inch one is rounded',
|
|
286
|
+
},
|
|
287
|
+
flutes: TWO_FLUTE_STRAIGHT,
|
|
288
|
+
pointAngle: POINT_ANGLE_142,
|
|
289
|
+
coolantThrough: INTERNAL_COOLANT_TITLE,
|
|
290
|
+
nonFerrous: PCD_NON_FERROUS,
|
|
291
|
+
bmc: PCD_SUBSTRATE,
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
'khsst_spiral_point_plug_inch.csv': {
|
|
295
|
+
id: 'khsst-spiral-point-plug-inch',
|
|
296
|
+
rows: 95,
|
|
297
|
+
familyCode: '100004132',
|
|
298
|
+
kind: 'tap',
|
|
299
|
+
columns: { SFDM: 'D', OAL: 'L', LCF: 'L3', TP: 'Thread Pitch' },
|
|
300
|
+
facts: {
|
|
301
|
+
bmc: HSS_ASSUMED,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
'khsst_hand_metric_plug.csv': {
|
|
305
|
+
id: 'khsst-hand-metric-plug',
|
|
306
|
+
rows: 14,
|
|
307
|
+
familyCode: '100004161',
|
|
308
|
+
kind: 'tap',
|
|
309
|
+
columns: { SFDM: 'D', OAL: 'L', LCF: 'L3', TP: 'Thread Pitch' },
|
|
310
|
+
facts: {
|
|
311
|
+
bmc: HSS_ASSUMED,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
'spiral_point_metric_plug.csv': {
|
|
315
|
+
id: 'spiral-point-metric-plug',
|
|
316
|
+
rows: 20,
|
|
317
|
+
familyCode: '100004191',
|
|
318
|
+
kind: 'tap',
|
|
319
|
+
columns: { SFDM: 'D', OAL: 'L', LCF: 'L3', TP: 'Thread Pitch' },
|
|
320
|
+
facts: {
|
|
321
|
+
bmc: HSS_ASSUMED,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
'gomill_pro_radiused_4fl_necked_metric.csv': {
|
|
325
|
+
id: 'gomill-pro-radiused-4fl-necked-metric',
|
|
326
|
+
rows: 60,
|
|
327
|
+
familyCode: '109353075',
|
|
328
|
+
kind: 'endmill',
|
|
329
|
+
columns: {
|
|
330
|
+
DC: 'D1',
|
|
331
|
+
SFDM: 'D',
|
|
332
|
+
OAL: 'L',
|
|
333
|
+
LCF: 'AP1MAX',
|
|
334
|
+
RE: 'Re',
|
|
335
|
+
'shoulder-length': 'L3',
|
|
336
|
+
'shoulder-diameter': 'D3',
|
|
337
|
+
},
|
|
338
|
+
facts: {
|
|
339
|
+
unit: {
|
|
340
|
+
value: 'millimeters',
|
|
341
|
+
source: 'vendor-stated',
|
|
342
|
+
cite: 'the vendor titles the family "…necked plain shank metric"; both unit columns are published, so this decides which is displayed',
|
|
343
|
+
},
|
|
344
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
345
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
'gomill_pro_square_4fl_plain_inch.csv': {
|
|
349
|
+
id: 'gomill-pro-square-4fl-plain-inch',
|
|
350
|
+
rows: 93,
|
|
351
|
+
familyCode: '109426909',
|
|
352
|
+
kind: 'endmill',
|
|
353
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'AP1MAX', 'shoulder-length': 'L3' },
|
|
354
|
+
facts: {
|
|
355
|
+
unit: INCH_PLAIN_SHANK,
|
|
356
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
357
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
'varimill_chip_splitter_radiused_5fl_3xd_plain_metric.csv': {
|
|
361
|
+
id: 'varimill-chip-splitter-radiused-5fl-3xd-plain-metric',
|
|
362
|
+
rows: 3,
|
|
363
|
+
familyCode: '103354322',
|
|
364
|
+
kind: 'endmill',
|
|
365
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'AP1MAX', RE: 'Re' },
|
|
366
|
+
brand: 'widia',
|
|
367
|
+
facts: {
|
|
368
|
+
unit: {
|
|
369
|
+
value: 'millimeters',
|
|
370
|
+
source: 'vendor-stated',
|
|
371
|
+
cite: 'the vendor titles the family "…3xD plain shank metric"; both unit columns are published, so this decides which is displayed',
|
|
372
|
+
},
|
|
373
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
374
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
'varimill_chip_splitter_570t_radiused_5fl_cyl_inch.csv': {
|
|
378
|
+
id: 'varimill-chip-splitter-570t-radiused-5fl-cyl-inch',
|
|
379
|
+
rows: 3,
|
|
380
|
+
familyCode: '100680824',
|
|
381
|
+
kind: 'endmill',
|
|
382
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'AP1MAX', RE: 'Re' },
|
|
383
|
+
brand: 'widia',
|
|
384
|
+
facts: {
|
|
385
|
+
unit: {
|
|
386
|
+
value: 'inches',
|
|
387
|
+
source: 'vendor-stated',
|
|
388
|
+
cite: 'the vendor titles the family "…cylindrical shank inch"; both unit columns are published, so this decides which is displayed',
|
|
389
|
+
},
|
|
390
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
391
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
// The first sub-4-flute endmill line here, and the first one treated
|
|
395
|
+
// downstream as a non-ferrous cutter. "Plain Shank" in the vendor's title is the
|
|
396
|
+
// shank form, not the profile: D3 < D1 on every row, so these are necked
|
|
397
|
+
// and L3 is published. `coolantThrough` False like every other family —
|
|
398
|
+
// the table states no coolant column and the page shows none (JG,
|
|
399
|
+
// 2026-08-05, unverified against a datasheet).
|
|
400
|
+
'maximet_square_3fl_wiper_necked_plain_inch.csv': {
|
|
401
|
+
id: 'maximet-square-3fl-wiper-necked-plain-inch',
|
|
402
|
+
rows: 14,
|
|
403
|
+
familyCode: '101273936',
|
|
404
|
+
kind: 'endmill',
|
|
405
|
+
columns: {
|
|
406
|
+
DC: 'D1',
|
|
407
|
+
SFDM: 'D',
|
|
408
|
+
OAL: 'L',
|
|
409
|
+
LCF: 'AP1MAX',
|
|
410
|
+
'shoulder-length': 'L3',
|
|
411
|
+
'shoulder-diameter': 'D3',
|
|
412
|
+
},
|
|
413
|
+
facts: {
|
|
414
|
+
unit: {
|
|
415
|
+
value: 'inches',
|
|
416
|
+
source: 'vendor-stated',
|
|
417
|
+
cite: 'the vendor titles the family "…necked plain shank inch"; both unit columns are published, so this decides which is displayed',
|
|
418
|
+
},
|
|
419
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
420
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
'kencut_ff_hpft_square_6fl_plain_inch.csv': {
|
|
424
|
+
id: 'kencut-ff-hpft-square-6fl-plain-inch',
|
|
425
|
+
rows: 12,
|
|
426
|
+
familyCode: '100003783',
|
|
427
|
+
kind: 'endmill',
|
|
428
|
+
columns: { DC: 'D1', SFDM: 'D', OAL: 'L', LCF: 'AP1MAX' },
|
|
429
|
+
facts: {
|
|
430
|
+
unit: INCH_PLAIN_SHANK,
|
|
431
|
+
coolantThrough: NO_COOLANT_COLUMN,
|
|
432
|
+
bmc: CARBIDE_GRADE_COLUMN,
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
// ── Toolholding ────────────────────────────────────────────────────────────
|
|
437
|
+
// Holder tables state neither the spindle taper nor how the holder grips —
|
|
438
|
+
// both are in the family's title and its catalog numbers, never in a column —
|
|
439
|
+
// so both are config here, per the rule about facts the table never states
|
|
440
|
+
// (JG 2026-08-04, from the family page titles and the BT30* catalog number
|
|
441
|
+
// prefixes).
|
|
442
|
+
//
|
|
443
|
+
// `clamping` is the discriminant a picker branches on and is deliberately not
|
|
444
|
+
// the same field as `style`: 'bore' means the holder takes one shank size
|
|
445
|
+
// directly, 'collet' means it needs a collet in between. A shrink-fit or
|
|
446
|
+
// side-lock family added later is a new `style` but an existing `clamping`, so
|
|
447
|
+
// the fit rules do not grow a case.
|
|
448
|
+
//
|
|
449
|
+
// `contact` is the second such discriminant and arrived with BTKV30
|
|
450
|
+
// (JG 2026-08-05). 'taper' is a plain 7/24 cone; 'face' is a dual-contact
|
|
451
|
+
// shank that seats on the spindle face as well — the vendor's own words, from
|
|
452
|
+
// the product page's "Shank - SK BT Taper Face Contact". It is a *separate*
|
|
453
|
+
// axis from `taper` on purpose: BTKV30 is the same JIS B 6339 cone as BT30, so
|
|
454
|
+
// collapsing the distinction into the taper string would hide these holders
|
|
455
|
+
// from a BT30 filter, and folding it into `style` would conflate how a holder
|
|
456
|
+
// meets the spindle with how it grips the tool. **It has no default.** A family
|
|
457
|
+
// added without it fails loudly rather than being recorded as plain-taper on no
|
|
458
|
+
// evidence.
|
|
459
|
+
//
|
|
460
|
+
// The collet *series* is NOT here — holders publish it as `CST` and collets as
|
|
461
|
+
// `Collet Series`, so the join between them is a scraped vendor fact.
|
|
462
|
+
//
|
|
463
|
+
// **Where the `style` values come from.** They are config, like `taper` and
|
|
464
|
+
// `clamping` — the variant table states none of them. But they are not coined
|
|
465
|
+
// here: every one is Kennametal's own category for the family, read off the
|
|
466
|
+
// family page's breadcrumb and tagline and verified JG 2026-08-05. A consumer
|
|
467
|
+
// turns them into the words on a holder row, so a wrong one is a wrong label in
|
|
468
|
+
// front of a machinist rather than a wrong number, and the citation is what
|
|
469
|
+
// keeps it checkable. The breadcrumb is server-rendered, so re-checking one is
|
|
470
|
+
// a single `curl` of `fam.x.<CODE>.html` — no scraper change and no browser.
|
|
471
|
+
export const HOLDER_FAMILIES = {
|
|
472
|
+
'bt30_er_collet_adapters_metric.csv': {
|
|
473
|
+
catalogName: 'Kennametal BT30 ER Collet Adapters Metric',
|
|
474
|
+
rows: 12,
|
|
475
|
+
facts: {
|
|
476
|
+
taper: BT30_SHANK,
|
|
477
|
+
contact: TAPER_CONTACT,
|
|
478
|
+
clamping: CST_COLLET_CLAMPING,
|
|
479
|
+
style: ER_COLLET_CHUCK,
|
|
480
|
+
unit: METRIC_CATALOG,
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
'bt30_hydraulic_chucks_form_ad_metric.csv': {
|
|
484
|
+
catalogName: 'Kennametal BT30 Hydraulic Chucks Form AD Metric',
|
|
485
|
+
rows: 8,
|
|
486
|
+
facts: {
|
|
487
|
+
taper: BT30_SHANK,
|
|
488
|
+
contact: TAPER_CONTACT,
|
|
489
|
+
clamping: BORE_CLAMPING,
|
|
490
|
+
style: HYDRAULIC_CHUCK,
|
|
491
|
+
unit: METRIC_CATALOG,
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
// The inch half of the same Form AD line (family 100127657, "HC IN-BT",
|
|
495
|
+
// scraped JG 2026-08-05) — same BT30 cone, same actuation screw, three
|
|
496
|
+
// fractional bores (1/4, 3/8, 1/2 in) instead of eight metric ones. It is
|
|
497
|
+
// a *sibling* family and not more rows on the one above: Kennametal
|
|
498
|
+
// numbers and codes the two separately, and the bores do not overlap.
|
|
499
|
+
//
|
|
500
|
+
// `unit` is 'inches' because the family is inch-native, which is the only
|
|
501
|
+
// thing that decides which column a holder's record mapper displays. Both unit
|
|
502
|
+
// columns are published here for every dimension — the HSK63A missing-pair
|
|
503
|
+
// case does not apply — so this family would have converted either way and
|
|
504
|
+
// silently shown 6.35 mm where a machinist ordered 1/4 in.
|
|
505
|
+
'bt30_hydraulic_chucks_form_ad_inch.csv': {
|
|
506
|
+
catalogName: 'Kennametal BT30 Hydraulic Chucks Form AD Inch',
|
|
507
|
+
rows: 3,
|
|
508
|
+
facts: {
|
|
509
|
+
taper: BT30_SHANK,
|
|
510
|
+
contact: TAPER_CONTACT,
|
|
511
|
+
clamping: BORE_CLAMPING,
|
|
512
|
+
style: HYDRAULIC_CHUCK,
|
|
513
|
+
unit: INCH_CATALOG,
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
// Dual-contact BT30. Same cone, same M16 drawbar, same ER collets as the
|
|
517
|
+
// family above — what differs is that the flange face seats on the spindle
|
|
518
|
+
// face too, and the vendor prices and numbers it as its own line (BTKV*).
|
|
519
|
+
//
|
|
520
|
+
// This family publishes **two** gage lengths: `L1` (100 mm on all five) and
|
|
521
|
+
// `L1FC`, "Gage Length Face Contact" (99.002 mm on all five). Which one is
|
|
522
|
+
// real is a property of the spindle, not of the holder. `gaugeLength` is
|
|
523
|
+
// `L1` because this shop's BT30 spindle is not face-contact (JG
|
|
524
|
+
// 2026-08-05), so `L1FC` is scraped into the CSV — the record of what the
|
|
525
|
+
// vendor said — and deliberately not carried onto the record, per
|
|
526
|
+
// a holder's record mapper's rule about published columns nothing displays. Promote
|
|
527
|
+
// it the day a dual-contact spindle exists to read it, and change
|
|
528
|
+
// `gaugeLength` with it rather than showing both.
|
|
529
|
+
'btkv30_er_collet_chucks_metric.csv': {
|
|
530
|
+
catalogName: 'Kennametal BTKV30 ER Collet Chucks Metric',
|
|
531
|
+
rows: 5,
|
|
532
|
+
facts: {
|
|
533
|
+
taper: BT30_SHANK,
|
|
534
|
+
contact: {
|
|
535
|
+
value: 'face',
|
|
536
|
+
source: 'vendor-stated',
|
|
537
|
+
cite: 'the product page names the shank "SK BT Taper Face Contact"',
|
|
538
|
+
},
|
|
539
|
+
clamping: CST_COLLET_CLAMPING,
|
|
540
|
+
style: ER_COLLET_CHUCK,
|
|
541
|
+
unit: METRIC_CATALOG,
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
// Shrink-fit chucks, scraped JG 2026-08-05 from the BT category page. Four
|
|
545
|
+
// entries, two vendor families — see the split note below.
|
|
546
|
+
//
|
|
547
|
+
// `clamping: 'bore'` and not a new mode: a shrink fit grips the shank
|
|
548
|
+
// directly, exactly as a hydraulic chuck does, and the picker's fit rule is
|
|
549
|
+
// the same question ("is this bore the shank's size?"). What differs is
|
|
550
|
+
// thermal rather than geometric, and nothing in this catalog reads it.
|
|
551
|
+
//
|
|
552
|
+
// The `style` split is the vendor's own product line, not a coinage.
|
|
553
|
+
// Kennametal sells two shrink-fit lines on the same BT30 cone: the **FC
|
|
554
|
+
// Line** ("Standard Heat Shrink Holders | Carbide and HSS Compatible | Face
|
|
555
|
+
// Coolant | Through Coolant", Balanced-by-Design, 3 µm or less) and the
|
|
556
|
+
// older **General Purpose (GP)** TT HPV line, which is *balanceable* with
|
|
557
|
+
// optional M6 set screws rather than balanced as shipped. They overlap in
|
|
558
|
+
// size but are not interchangeable at speed, so they are told apart the way
|
|
559
|
+
// `er-standard` and `er-sealed` are. `FC` is the vendor's token and is left
|
|
560
|
+
// unexpanded — nothing on the page says what it abbreviates.
|
|
561
|
+
//
|
|
562
|
+
// **`HLD_D1_MIN` is metric-only on both FC families, including the inch
|
|
563
|
+
// one.** That is the HSK63A case from the runbook, and this is the first
|
|
564
|
+
// family where it bites a family the catalog actually ships: without
|
|
565
|
+
// `_dim`'s cross-unit fallback every one of these six inch chucks would
|
|
566
|
+
// carry no bore, match no tool, and raise nothing.
|
|
567
|
+
'bt30_shrink_fit_fc_form_ad_metric.csv': {
|
|
568
|
+
catalogName: 'Kennametal BT30 Shrink Fit FC Line Form AD Metric',
|
|
569
|
+
rows: 6,
|
|
570
|
+
facts: {
|
|
571
|
+
taper: BT30_SHANK,
|
|
572
|
+
contact: TAPER_CONTACT,
|
|
573
|
+
clamping: BORE_CLAMPING,
|
|
574
|
+
style: SHRINK_FIT_FC,
|
|
575
|
+
unit: METRIC_CATALOG,
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
'bt30_shrink_fit_fc_form_ad_inch.csv': {
|
|
579
|
+
catalogName: 'Kennametal BT30 Shrink Fit FC Line Form AD Inch',
|
|
580
|
+
rows: 6,
|
|
581
|
+
facts: {
|
|
582
|
+
taper: BT30_SHANK,
|
|
583
|
+
contact: TAPER_CONTACT,
|
|
584
|
+
clamping: BORE_CLAMPING,
|
|
585
|
+
style: SHRINK_FIT_FC,
|
|
586
|
+
unit: INCH_CATALOG,
|
|
587
|
+
},
|
|
588
|
+
},
|
|
589
|
+
// **These two are one vendor family (100017036, "TT HPV-BT Form AD") split
|
|
590
|
+
// in half, and it is the only place in this package that happens.** Every
|
|
591
|
+
// other family is wholly metric or wholly inch; this one publishes seven
|
|
592
|
+
// metric bores (6-20 mm) and six fractional ones (1/4-3/4 in) as thirteen
|
|
593
|
+
// rows under one code, so a single `unit` would have displayed 0.4724 in
|
|
594
|
+
// for a 12 mm bore or 11.113 mm for a 7/16 in one.
|
|
595
|
+
//
|
|
596
|
+
// The partition is the vendor's own catalog-number suffix — `...M` is a
|
|
597
|
+
// metric bore — and it is corroborated by which column carries the exact
|
|
598
|
+
// value: the `M` rows give D1 as integers in millimetres and rounded
|
|
599
|
+
// decimals in inches (12 / 0.4724), the others exactly the other way round
|
|
600
|
+
// (0.4375 / 11.113). the toolholding tests pin both halves of that, so a
|
|
601
|
+
// re-scrape that lost or moved a row fails rather than converting quietly.
|
|
602
|
+
//
|
|
603
|
+
// If a third mixed family ever turns up, stop splitting CSVs and make
|
|
604
|
+
// `unit` a per-record fact instead — that is the honest model, and it is
|
|
605
|
+
// not worth the churn for one family.
|
|
606
|
+
'bt30_shrink_fit_hpv_form_ad_metric.csv': {
|
|
607
|
+
catalogName: 'Kennametal BT30 Shrink Fit HPV GP Form AD Metric',
|
|
608
|
+
rows: 7,
|
|
609
|
+
facts: {
|
|
610
|
+
taper: BT30_SHANK,
|
|
611
|
+
contact: TAPER_CONTACT,
|
|
612
|
+
clamping: BORE_CLAMPING,
|
|
613
|
+
style: SHRINK_FIT_GP,
|
|
614
|
+
unit: METRIC_CATALOG,
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
'bt30_shrink_fit_hpv_form_ad_inch.csv': {
|
|
618
|
+
catalogName: 'Kennametal BT30 Shrink Fit HPV GP Form AD Inch',
|
|
619
|
+
rows: 6,
|
|
620
|
+
facts: {
|
|
621
|
+
taper: BT30_SHANK,
|
|
622
|
+
contact: TAPER_CONTACT,
|
|
623
|
+
clamping: BORE_CLAMPING,
|
|
624
|
+
style: SHRINK_FIT_GP,
|
|
625
|
+
unit: INCH_CATALOG,
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
};
|
|
629
|
+
export const COLLET_FAMILIES = {
|
|
630
|
+
'er_standard_collets_metric.csv': {
|
|
631
|
+
catalogName: 'Kennametal ER Standard Collets Metric',
|
|
632
|
+
rows: 110,
|
|
633
|
+
facts: {
|
|
634
|
+
style: {
|
|
635
|
+
value: 'er-standard',
|
|
636
|
+
source: 'vendor-stated',
|
|
637
|
+
cite: "the family is Kennametal's plain ER collet line",
|
|
638
|
+
},
|
|
639
|
+
unit: METRIC_CATALOG,
|
|
640
|
+
},
|
|
641
|
+
},
|
|
642
|
+
// Sealed coolant-through collets. `style` separates them from the standard
|
|
643
|
+
// ones because they behave differently in a way the numbers alone show but
|
|
644
|
+
// a label should not hide: CCCX == CCCN on every row, so each clamps one
|
|
645
|
+
// exact size (Kennametal specs H6 shank tolerance) rather than a 1 mm band.
|
|
646
|
+
// No special case is needed anywhere — a zero-width range is still a range
|
|
647
|
+
// — but a user choosing one deserves to be told which kind it is.
|
|
648
|
+
'er16_collets_coolant_through_inch.csv': {
|
|
649
|
+
catalogName: 'Kennametal ER16 Collets Coolant-Through Inch',
|
|
650
|
+
rows: 10,
|
|
651
|
+
facts: {
|
|
652
|
+
style: {
|
|
653
|
+
value: 'er-sealed',
|
|
654
|
+
source: 'vendor-stated',
|
|
655
|
+
cite: 'CCCX == CCCN == D1 on every row; Kennametal specs an H6 shank, so it clamps one exact size',
|
|
656
|
+
},
|
|
657
|
+
unit: INCH_CATALOG,
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
};
|