woodml-parser 1.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.
- package/README.md +181 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +554 -0
- package/dist/cli.js.map +1 -0
- package/dist/cost.d.ts +94 -0
- package/dist/cost.d.ts.map +1 -0
- package/dist/cost.js +340 -0
- package/dist/cost.js.map +1 -0
- package/dist/cost.test.d.ts +2 -0
- package/dist/cost.test.d.ts.map +1 -0
- package/dist/cost.test.js +241 -0
- package/dist/cost.test.js.map +1 -0
- package/dist/example.d.ts +6 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +136 -0
- package/dist/example.js.map +1 -0
- package/dist/formulas.d.ts +23 -0
- package/dist/formulas.d.ts.map +1 -0
- package/dist/formulas.js +442 -0
- package/dist/formulas.js.map +1 -0
- package/dist/formulas.test.d.ts +5 -0
- package/dist/formulas.test.d.ts.map +1 -0
- package/dist/formulas.test.js +360 -0
- package/dist/formulas.test.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +6 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +271 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/optimizer.d.ts +119 -0
- package/dist/optimizer.d.ts.map +1 -0
- package/dist/optimizer.js +423 -0
- package/dist/optimizer.js.map +1 -0
- package/dist/optimizer.test.d.ts +2 -0
- package/dist/optimizer.test.d.ts.map +1 -0
- package/dist/optimizer.test.js +225 -0
- package/dist/optimizer.test.js.map +1 -0
- package/dist/parser.d.ts +59 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +305 -0
- package/dist/parser.js.map +1 -0
- package/dist/parser.test.d.ts +5 -0
- package/dist/parser.test.d.ts.map +1 -0
- package/dist/parser.test.js +486 -0
- package/dist/parser.test.js.map +1 -0
- package/dist/pdf.d.ts +36 -0
- package/dist/pdf.d.ts.map +1 -0
- package/dist/pdf.js +316 -0
- package/dist/pdf.js.map +1 -0
- package/dist/svg.d.ts +73 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/svg.js +613 -0
- package/dist/svg.js.map +1 -0
- package/dist/svg.test.d.ts +5 -0
- package/dist/svg.test.d.ts.map +1 -0
- package/dist/svg.test.js +333 -0
- package/dist/svg.test.js.map +1 -0
- package/dist/templates.d.ts +126 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +448 -0
- package/dist/templates.js.map +1 -0
- package/dist/templates.test.d.ts +5 -0
- package/dist/templates.test.d.ts.map +1 -0
- package/dist/templates.test.js +630 -0
- package/dist/templates.test.js.map +1 -0
- package/dist/types.d.ts +250 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/units.d.ts +53 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +359 -0
- package/dist/units.js.map +1 -0
- package/dist/units.test.d.ts +5 -0
- package/dist/units.test.d.ts.map +1 -0
- package/dist/units.test.js +364 -0
- package/dist/units.test.js.map +1 -0
- package/package.json +46 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WoodML TypeScript Type Definitions
|
|
3
|
+
* Core types for the WoodML markup language
|
|
4
|
+
*/
|
|
5
|
+
export type UnitSystem = 'imperial' | 'metric';
|
|
6
|
+
export interface Dimension {
|
|
7
|
+
/** Value in base units (inches for imperial, mm for metric) */
|
|
8
|
+
value: number;
|
|
9
|
+
/** Original unit system */
|
|
10
|
+
unit: UnitSystem;
|
|
11
|
+
/** Original string representation */
|
|
12
|
+
original: string;
|
|
13
|
+
}
|
|
14
|
+
export interface FractionalInches {
|
|
15
|
+
whole: number;
|
|
16
|
+
numerator: number;
|
|
17
|
+
denominator: number;
|
|
18
|
+
}
|
|
19
|
+
export interface WoodMLDocument {
|
|
20
|
+
woodml: string;
|
|
21
|
+
project?: Project;
|
|
22
|
+
imports?: string[];
|
|
23
|
+
materials?: Materials;
|
|
24
|
+
formulas?: Formulas;
|
|
25
|
+
parts?: Part[];
|
|
26
|
+
joinery?: Joint[];
|
|
27
|
+
cutlist?: CutList;
|
|
28
|
+
assembly?: AssemblyStep[];
|
|
29
|
+
finishing?: Finishing;
|
|
30
|
+
tools?: Tools;
|
|
31
|
+
notes?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface Project {
|
|
34
|
+
name?: string;
|
|
35
|
+
author?: string;
|
|
36
|
+
version?: string;
|
|
37
|
+
units?: UnitSystem;
|
|
38
|
+
description?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface Materials {
|
|
41
|
+
lumber?: Lumber[];
|
|
42
|
+
hardware?: Hardware[];
|
|
43
|
+
sheet_goods?: SheetGood[];
|
|
44
|
+
}
|
|
45
|
+
export interface Lumber {
|
|
46
|
+
id: string;
|
|
47
|
+
species?: string;
|
|
48
|
+
thickness?: string;
|
|
49
|
+
nominal?: string;
|
|
50
|
+
actual?: string;
|
|
51
|
+
length?: string;
|
|
52
|
+
width?: string;
|
|
53
|
+
board_feet?: number;
|
|
54
|
+
quantity?: number;
|
|
55
|
+
notes?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface Hardware {
|
|
58
|
+
id: string;
|
|
59
|
+
type: 'screw' | 'nail' | 'bolt' | 'hinge' | 'knob' | 'pull' | 'slide' | 'adhesive' | 'dowel' | 'biscuit' | 'other';
|
|
60
|
+
name?: string;
|
|
61
|
+
size?: string;
|
|
62
|
+
quantity?: number;
|
|
63
|
+
notes?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface SheetGood {
|
|
66
|
+
id: string;
|
|
67
|
+
type: 'plywood' | 'mdf' | 'particleboard' | 'hardboard' | 'melamine' | 'other';
|
|
68
|
+
thickness?: string;
|
|
69
|
+
grade?: string;
|
|
70
|
+
size?: string;
|
|
71
|
+
quantity?: number;
|
|
72
|
+
notes?: string;
|
|
73
|
+
}
|
|
74
|
+
export interface Formulas {
|
|
75
|
+
vars?: Record<string, string>;
|
|
76
|
+
computed?: Record<string, string>;
|
|
77
|
+
use_library?: string[];
|
|
78
|
+
custom?: Record<string, CustomFormula>;
|
|
79
|
+
}
|
|
80
|
+
export interface CustomFormula {
|
|
81
|
+
params: string[];
|
|
82
|
+
formula: string;
|
|
83
|
+
}
|
|
84
|
+
export interface Part {
|
|
85
|
+
id: string;
|
|
86
|
+
name?: string;
|
|
87
|
+
use?: string;
|
|
88
|
+
params?: Record<string, string>;
|
|
89
|
+
material?: string;
|
|
90
|
+
dimensions?: Dimensions;
|
|
91
|
+
grain?: 'long' | 'short' | 'any';
|
|
92
|
+
quantity?: number;
|
|
93
|
+
tapers?: Taper[];
|
|
94
|
+
profiles?: Profile[];
|
|
95
|
+
notes?: string;
|
|
96
|
+
}
|
|
97
|
+
export interface Dimensions {
|
|
98
|
+
length?: string;
|
|
99
|
+
width?: string;
|
|
100
|
+
thickness?: string;
|
|
101
|
+
depth?: string;
|
|
102
|
+
}
|
|
103
|
+
export interface Taper {
|
|
104
|
+
face?: 'inside' | 'outside' | 'front' | 'back' | 'all';
|
|
105
|
+
faces?: string[];
|
|
106
|
+
start?: string;
|
|
107
|
+
end_dimension?: string;
|
|
108
|
+
taper_per_foot?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface Profile {
|
|
111
|
+
edge?: 'top' | 'bottom' | 'left' | 'right' | 'front' | 'back' | 'all';
|
|
112
|
+
type: 'roundover' | 'chamfer' | 'ogee' | 'cove' | 'bead' | 'ease' | 'bullnose' | 'custom';
|
|
113
|
+
radius?: string;
|
|
114
|
+
size?: string;
|
|
115
|
+
}
|
|
116
|
+
export type JointType = 'mortise_and_tenon' | 'dovetail' | 'box_joint' | 'dado' | 'rabbet' | 'groove' | 'tongue_and_groove' | 'biscuit' | 'dowel' | 'pocket_hole' | 'miter' | 'spline' | 'half_lap' | 'bridle' | 'finger_joint' | 'scarf' | 'butt';
|
|
117
|
+
export interface Joint {
|
|
118
|
+
type: JointType;
|
|
119
|
+
parts?: string[];
|
|
120
|
+
mortise?: MortiseSpec;
|
|
121
|
+
tenon?: TenonSpec;
|
|
122
|
+
tails?: DovetailSpec;
|
|
123
|
+
pins?: DovetailSpec;
|
|
124
|
+
ratio?: string;
|
|
125
|
+
style?: string;
|
|
126
|
+
housing?: string | HousingSpec;
|
|
127
|
+
insert?: string | InsertSpec;
|
|
128
|
+
connections?: [string, string][];
|
|
129
|
+
width?: string;
|
|
130
|
+
depth?: string;
|
|
131
|
+
position?: string | PositionSpec;
|
|
132
|
+
}
|
|
133
|
+
export interface MortiseSpec {
|
|
134
|
+
part: string;
|
|
135
|
+
position?: string | PositionSpec;
|
|
136
|
+
dimensions?: {
|
|
137
|
+
width?: string;
|
|
138
|
+
height?: string;
|
|
139
|
+
depth?: string;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export interface TenonSpec {
|
|
143
|
+
part: string;
|
|
144
|
+
position?: string | PositionSpec;
|
|
145
|
+
dimensions?: {
|
|
146
|
+
width?: string;
|
|
147
|
+
height?: string;
|
|
148
|
+
length?: string;
|
|
149
|
+
};
|
|
150
|
+
shoulder?: string | ShoulderSpec;
|
|
151
|
+
haunch?: {
|
|
152
|
+
height?: string;
|
|
153
|
+
length?: string;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
export interface DovetailSpec {
|
|
157
|
+
part: string;
|
|
158
|
+
count?: number;
|
|
159
|
+
spacing?: 'even' | 'graduated';
|
|
160
|
+
half_pin?: string;
|
|
161
|
+
}
|
|
162
|
+
export interface HousingSpec {
|
|
163
|
+
part: string;
|
|
164
|
+
position?: string;
|
|
165
|
+
width?: string;
|
|
166
|
+
depth?: string;
|
|
167
|
+
}
|
|
168
|
+
export interface InsertSpec {
|
|
169
|
+
part: string;
|
|
170
|
+
}
|
|
171
|
+
export interface PositionSpec {
|
|
172
|
+
from_top?: string;
|
|
173
|
+
from_bottom?: string;
|
|
174
|
+
from_left?: string;
|
|
175
|
+
from_right?: string;
|
|
176
|
+
from_front?: string;
|
|
177
|
+
from_back?: string;
|
|
178
|
+
from_outside?: string;
|
|
179
|
+
from_inside?: string;
|
|
180
|
+
}
|
|
181
|
+
export interface ShoulderSpec {
|
|
182
|
+
top?: string;
|
|
183
|
+
bottom?: string;
|
|
184
|
+
front?: string;
|
|
185
|
+
back?: string;
|
|
186
|
+
all?: string;
|
|
187
|
+
}
|
|
188
|
+
export interface CutList {
|
|
189
|
+
optimize?: boolean;
|
|
190
|
+
kerf?: string;
|
|
191
|
+
groups?: CutGroup[];
|
|
192
|
+
}
|
|
193
|
+
export interface CutGroup {
|
|
194
|
+
from: string;
|
|
195
|
+
stock_size?: string;
|
|
196
|
+
respect_grain?: boolean;
|
|
197
|
+
edge_allowance?: string;
|
|
198
|
+
rough_length_add?: string;
|
|
199
|
+
rough_width_add?: string;
|
|
200
|
+
cuts: CutSpec[];
|
|
201
|
+
}
|
|
202
|
+
export interface CutSpec {
|
|
203
|
+
part: string;
|
|
204
|
+
quantity?: number;
|
|
205
|
+
grain?: 'length' | 'width' | 'any';
|
|
206
|
+
priority?: number;
|
|
207
|
+
}
|
|
208
|
+
export interface AssemblyStep {
|
|
209
|
+
step: number;
|
|
210
|
+
title: string;
|
|
211
|
+
parts?: string[];
|
|
212
|
+
operations?: string[];
|
|
213
|
+
tools?: string[];
|
|
214
|
+
notes?: string;
|
|
215
|
+
subassemblies?: Subassembly[];
|
|
216
|
+
}
|
|
217
|
+
export interface Subassembly {
|
|
218
|
+
name: string;
|
|
219
|
+
parts: string[];
|
|
220
|
+
clamp_time?: string;
|
|
221
|
+
}
|
|
222
|
+
export interface Finishing {
|
|
223
|
+
steps: FinishStep[];
|
|
224
|
+
}
|
|
225
|
+
export interface FinishStep {
|
|
226
|
+
type: 'sand' | 'stain' | 'dye' | 'topcoat' | 'wax' | 'oil' | 'other';
|
|
227
|
+
grits?: number[];
|
|
228
|
+
product?: string;
|
|
229
|
+
coats?: number;
|
|
230
|
+
dry_time?: string;
|
|
231
|
+
sand_between?: number | string;
|
|
232
|
+
notes?: string;
|
|
233
|
+
}
|
|
234
|
+
export interface Tools {
|
|
235
|
+
required?: (string | Record<string, number>)[];
|
|
236
|
+
optional?: (string | Record<string, number>)[];
|
|
237
|
+
}
|
|
238
|
+
export interface ResolvedPart extends Omit<Part, 'dimensions'> {
|
|
239
|
+
dimensions: {
|
|
240
|
+
length: Dimension;
|
|
241
|
+
width: Dimension;
|
|
242
|
+
thickness: Dimension;
|
|
243
|
+
};
|
|
244
|
+
resolvedQuantity: number;
|
|
245
|
+
}
|
|
246
|
+
export interface ResolvedDocument extends Omit<WoodMLDocument, 'parts'> {
|
|
247
|
+
resolvedParts: ResolvedPart[];
|
|
248
|
+
resolvedVariables: Record<string, Dimension | number>;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
package/dist/units.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WoodML Unit Parsing and Conversion
|
|
3
|
+
* Handles imperial (fractional inches) and metric measurements
|
|
4
|
+
*/
|
|
5
|
+
import { Dimension, FractionalInches, UnitSystem } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Parse a dimension string into a Dimension object
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseDimension(input: string, defaultUnit?: UnitSystem): Dimension;
|
|
10
|
+
/**
|
|
11
|
+
* Convert dimension to inches
|
|
12
|
+
*/
|
|
13
|
+
export declare function toInches(dim: Dimension): number;
|
|
14
|
+
/**
|
|
15
|
+
* Convert dimension to millimeters
|
|
16
|
+
*/
|
|
17
|
+
export declare function toMillimeters(dim: Dimension): number;
|
|
18
|
+
/**
|
|
19
|
+
* Convert dimension to the specified unit system
|
|
20
|
+
*/
|
|
21
|
+
export declare function convertTo(dim: Dimension, targetUnit: UnitSystem): Dimension;
|
|
22
|
+
/**
|
|
23
|
+
* Convert decimal inches to fractional representation
|
|
24
|
+
*/
|
|
25
|
+
export declare function decimalToFraction(decimal: number, maxDenominator?: number): FractionalInches;
|
|
26
|
+
/**
|
|
27
|
+
* Format dimension as imperial string
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatImperial(dim: Dimension, precision?: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* Format dimension as metric string
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatMetric(dim: Dimension, decimals?: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Format dimension in its native unit
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatDimension(dim: Dimension): string;
|
|
38
|
+
/**
|
|
39
|
+
* Parse dimensional lumber notation (e.g., "2x4")
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseDimensionalLumber(notation: string): {
|
|
42
|
+
width: Dimension;
|
|
43
|
+
thickness: Dimension;
|
|
44
|
+
} | null;
|
|
45
|
+
/**
|
|
46
|
+
* Check if a string is a variable reference
|
|
47
|
+
*/
|
|
48
|
+
export declare function isVariableReference(input: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Extract variable name from reference
|
|
51
|
+
*/
|
|
52
|
+
export declare function extractVariableName(input: string): string | null;
|
|
53
|
+
//# sourceMappingURL=units.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../src/units.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAoElE;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,GAAE,UAAuB,GAAG,SAAS,CAgH7F;AAiBD;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAM/C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS,CAkB3E;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,GAAE,MAAW,GAAG,gBAAgB,CAyChG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,GAAE,MAAW,GAAG,MAAM,CAgC7E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CAUzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAKtD;AAUD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAa1G;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE"}
|
package/dist/units.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WoodML Unit Parsing and Conversion
|
|
4
|
+
* Handles imperial (fractional inches) and metric measurements
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parseDimension = parseDimension;
|
|
8
|
+
exports.toInches = toInches;
|
|
9
|
+
exports.toMillimeters = toMillimeters;
|
|
10
|
+
exports.convertTo = convertTo;
|
|
11
|
+
exports.decimalToFraction = decimalToFraction;
|
|
12
|
+
exports.formatImperial = formatImperial;
|
|
13
|
+
exports.formatMetric = formatMetric;
|
|
14
|
+
exports.formatDimension = formatDimension;
|
|
15
|
+
exports.parseDimensionalLumber = parseDimensionalLumber;
|
|
16
|
+
exports.isVariableReference = isVariableReference;
|
|
17
|
+
exports.extractVariableName = extractVariableName;
|
|
18
|
+
// ============================================
|
|
19
|
+
// CONSTANTS
|
|
20
|
+
// ============================================
|
|
21
|
+
const INCHES_PER_FOOT = 12;
|
|
22
|
+
const MM_PER_INCH = 25.4;
|
|
23
|
+
const MM_PER_CM = 10;
|
|
24
|
+
const MM_PER_METER = 1000;
|
|
25
|
+
// Common denominators for fractions (must be powers of 2)
|
|
26
|
+
const VALID_DENOMINATORS = [2, 4, 8, 16, 32, 64];
|
|
27
|
+
// ============================================
|
|
28
|
+
// PARSING REGULAR EXPRESSIONS
|
|
29
|
+
// ============================================
|
|
30
|
+
const PATTERNS = {
|
|
31
|
+
// Imperial patterns
|
|
32
|
+
wholeInches: /^(\d+)"$/, // 24"
|
|
33
|
+
fractionalInches: /^(\d+)\/(\d+)"$/, // 3/4"
|
|
34
|
+
mixedInches: /^(\d+)-(\d+)\/(\d+)"$/, // 3-1/2"
|
|
35
|
+
feetOnly: /^(\d+)'$/, // 6'
|
|
36
|
+
feetAndInches: /^(\d+)'(\d+)"$/, // 6'4"
|
|
37
|
+
feetAndMixed: /^(\d+)'(\d+)-(\d+)\/(\d+)"$/, // 6'4-1/2"
|
|
38
|
+
quarterNotation: /^(\d+)\/4$/, // 4/4, 8/4
|
|
39
|
+
// Metric patterns
|
|
40
|
+
millimeters: /^(\d+(?:\.\d+)?)mm$/i, // 610mm
|
|
41
|
+
centimeters: /^(\d+(?:\.\d+)?)cm$/i, // 61cm
|
|
42
|
+
meters: /^(\d+(?:\.\d+)?)m$/i, // 2.4m
|
|
43
|
+
// Variable reference
|
|
44
|
+
variable: /^\$([a-zA-Z_][a-zA-Z0-9_]*)$/, // $variable
|
|
45
|
+
// Dimensional lumber
|
|
46
|
+
dimensionalLumber: /^(\d+)x(\d+)$/, // 2x4
|
|
47
|
+
};
|
|
48
|
+
// ============================================
|
|
49
|
+
// DIMENSIONAL LUMBER ACTUAL SIZES
|
|
50
|
+
// ============================================
|
|
51
|
+
const DIMENSIONAL_LUMBER = {
|
|
52
|
+
'1x2': { width: 1.5, thickness: 0.75 },
|
|
53
|
+
'1x3': { width: 2.5, thickness: 0.75 },
|
|
54
|
+
'1x4': { width: 3.5, thickness: 0.75 },
|
|
55
|
+
'1x6': { width: 5.5, thickness: 0.75 },
|
|
56
|
+
'1x8': { width: 7.25, thickness: 0.75 },
|
|
57
|
+
'1x10': { width: 9.25, thickness: 0.75 },
|
|
58
|
+
'1x12': { width: 11.25, thickness: 0.75 },
|
|
59
|
+
'2x2': { width: 1.5, thickness: 1.5 },
|
|
60
|
+
'2x3': { width: 2.5, thickness: 1.5 },
|
|
61
|
+
'2x4': { width: 3.5, thickness: 1.5 },
|
|
62
|
+
'2x6': { width: 5.5, thickness: 1.5 },
|
|
63
|
+
'2x8': { width: 7.25, thickness: 1.5 },
|
|
64
|
+
'2x10': { width: 9.25, thickness: 1.5 },
|
|
65
|
+
'2x12': { width: 11.25, thickness: 1.5 },
|
|
66
|
+
'4x4': { width: 3.5, thickness: 3.5 },
|
|
67
|
+
'4x6': { width: 5.5, thickness: 3.5 },
|
|
68
|
+
'6x6': { width: 5.5, thickness: 5.5 },
|
|
69
|
+
};
|
|
70
|
+
// ============================================
|
|
71
|
+
// PARSING FUNCTIONS
|
|
72
|
+
// ============================================
|
|
73
|
+
/**
|
|
74
|
+
* Parse a dimension string into a Dimension object
|
|
75
|
+
*/
|
|
76
|
+
function parseDimension(input, defaultUnit = 'imperial') {
|
|
77
|
+
const trimmed = input.trim();
|
|
78
|
+
// Try each pattern
|
|
79
|
+
let match;
|
|
80
|
+
// Whole inches: 24"
|
|
81
|
+
if ((match = trimmed.match(PATTERNS.wholeInches))) {
|
|
82
|
+
return {
|
|
83
|
+
value: parseInt(match[1], 10),
|
|
84
|
+
unit: 'imperial',
|
|
85
|
+
original: trimmed,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Fractional inches: 3/4"
|
|
89
|
+
if ((match = trimmed.match(PATTERNS.fractionalInches))) {
|
|
90
|
+
const num = parseInt(match[1], 10);
|
|
91
|
+
const denom = parseInt(match[2], 10);
|
|
92
|
+
validateDenominator(denom);
|
|
93
|
+
return {
|
|
94
|
+
value: num / denom,
|
|
95
|
+
unit: 'imperial',
|
|
96
|
+
original: trimmed,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Mixed inches: 3-1/2"
|
|
100
|
+
if ((match = trimmed.match(PATTERNS.mixedInches))) {
|
|
101
|
+
const whole = parseInt(match[1], 10);
|
|
102
|
+
const num = parseInt(match[2], 10);
|
|
103
|
+
const denom = parseInt(match[3], 10);
|
|
104
|
+
validateDenominator(denom);
|
|
105
|
+
return {
|
|
106
|
+
value: whole + num / denom,
|
|
107
|
+
unit: 'imperial',
|
|
108
|
+
original: trimmed,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Feet only: 6'
|
|
112
|
+
if ((match = trimmed.match(PATTERNS.feetOnly))) {
|
|
113
|
+
return {
|
|
114
|
+
value: parseInt(match[1], 10) * INCHES_PER_FOOT,
|
|
115
|
+
unit: 'imperial',
|
|
116
|
+
original: trimmed,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Feet and inches: 6'4"
|
|
120
|
+
if ((match = trimmed.match(PATTERNS.feetAndInches))) {
|
|
121
|
+
const feet = parseInt(match[1], 10);
|
|
122
|
+
const inches = parseInt(match[2], 10);
|
|
123
|
+
return {
|
|
124
|
+
value: feet * INCHES_PER_FOOT + inches,
|
|
125
|
+
unit: 'imperial',
|
|
126
|
+
original: trimmed,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Feet and mixed inches: 6'4-1/2"
|
|
130
|
+
if ((match = trimmed.match(PATTERNS.feetAndMixed))) {
|
|
131
|
+
const feet = parseInt(match[1], 10);
|
|
132
|
+
const inches = parseInt(match[2], 10);
|
|
133
|
+
const num = parseInt(match[3], 10);
|
|
134
|
+
const denom = parseInt(match[4], 10);
|
|
135
|
+
validateDenominator(denom);
|
|
136
|
+
return {
|
|
137
|
+
value: feet * INCHES_PER_FOOT + inches + num / denom,
|
|
138
|
+
unit: 'imperial',
|
|
139
|
+
original: trimmed,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Quarter notation: 4/4
|
|
143
|
+
if ((match = trimmed.match(PATTERNS.quarterNotation))) {
|
|
144
|
+
const quarters = parseInt(match[1], 10);
|
|
145
|
+
return {
|
|
146
|
+
value: quarters / 4,
|
|
147
|
+
unit: 'imperial',
|
|
148
|
+
original: trimmed,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// Millimeters: 610mm
|
|
152
|
+
if ((match = trimmed.match(PATTERNS.millimeters))) {
|
|
153
|
+
return {
|
|
154
|
+
value: parseFloat(match[1]),
|
|
155
|
+
unit: 'metric',
|
|
156
|
+
original: trimmed,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// Centimeters: 61cm
|
|
160
|
+
if ((match = trimmed.match(PATTERNS.centimeters))) {
|
|
161
|
+
return {
|
|
162
|
+
value: parseFloat(match[1]) * MM_PER_CM,
|
|
163
|
+
unit: 'metric',
|
|
164
|
+
original: trimmed,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Meters: 2.4m
|
|
168
|
+
if ((match = trimmed.match(PATTERNS.meters))) {
|
|
169
|
+
return {
|
|
170
|
+
value: parseFloat(match[1]) * MM_PER_METER,
|
|
171
|
+
unit: 'metric',
|
|
172
|
+
original: trimmed,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`Invalid dimension format: "${input}"`);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Validate that denominator is a power of 2
|
|
179
|
+
*/
|
|
180
|
+
function validateDenominator(denom) {
|
|
181
|
+
if (!VALID_DENOMINATORS.includes(denom)) {
|
|
182
|
+
throw new Error(`Invalid fraction denominator: ${denom}. Must be one of: ${VALID_DENOMINATORS.join(', ')}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// ============================================
|
|
186
|
+
// CONVERSION FUNCTIONS
|
|
187
|
+
// ============================================
|
|
188
|
+
/**
|
|
189
|
+
* Convert dimension to inches
|
|
190
|
+
*/
|
|
191
|
+
function toInches(dim) {
|
|
192
|
+
if (dim.unit === 'imperial') {
|
|
193
|
+
return dim.value;
|
|
194
|
+
}
|
|
195
|
+
// Convert from mm to inches
|
|
196
|
+
return dim.value / MM_PER_INCH;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Convert dimension to millimeters
|
|
200
|
+
*/
|
|
201
|
+
function toMillimeters(dim) {
|
|
202
|
+
if (dim.unit === 'metric') {
|
|
203
|
+
return dim.value;
|
|
204
|
+
}
|
|
205
|
+
// Convert from inches to mm
|
|
206
|
+
return dim.value * MM_PER_INCH;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Convert dimension to the specified unit system
|
|
210
|
+
*/
|
|
211
|
+
function convertTo(dim, targetUnit) {
|
|
212
|
+
if (dim.unit === targetUnit) {
|
|
213
|
+
return dim;
|
|
214
|
+
}
|
|
215
|
+
if (targetUnit === 'imperial') {
|
|
216
|
+
return {
|
|
217
|
+
value: toInches(dim),
|
|
218
|
+
unit: 'imperial',
|
|
219
|
+
original: dim.original,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return {
|
|
224
|
+
value: toMillimeters(dim),
|
|
225
|
+
unit: 'metric',
|
|
226
|
+
original: dim.original,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ============================================
|
|
231
|
+
// FORMATTING FUNCTIONS
|
|
232
|
+
// ============================================
|
|
233
|
+
/**
|
|
234
|
+
* Convert decimal inches to fractional representation
|
|
235
|
+
*/
|
|
236
|
+
function decimalToFraction(decimal, maxDenominator = 64) {
|
|
237
|
+
const whole = Math.floor(decimal);
|
|
238
|
+
let remainder = decimal - whole;
|
|
239
|
+
if (remainder < 0.001) {
|
|
240
|
+
return { whole, numerator: 0, denominator: 1 };
|
|
241
|
+
}
|
|
242
|
+
// Find closest fraction
|
|
243
|
+
let bestNumerator = 0;
|
|
244
|
+
let bestDenominator = 1;
|
|
245
|
+
let bestError = remainder;
|
|
246
|
+
for (const denom of VALID_DENOMINATORS) {
|
|
247
|
+
if (denom > maxDenominator)
|
|
248
|
+
break;
|
|
249
|
+
const num = Math.round(remainder * denom);
|
|
250
|
+
const error = Math.abs(remainder - num / denom);
|
|
251
|
+
if (error < bestError) {
|
|
252
|
+
bestError = error;
|
|
253
|
+
bestNumerator = num;
|
|
254
|
+
bestDenominator = denom;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Simplify fraction
|
|
258
|
+
const gcd = greatestCommonDivisor(bestNumerator, bestDenominator);
|
|
259
|
+
bestNumerator /= gcd;
|
|
260
|
+
bestDenominator /= gcd;
|
|
261
|
+
// Handle case where fraction rounds to 1
|
|
262
|
+
if (bestNumerator === bestDenominator) {
|
|
263
|
+
return { whole: whole + 1, numerator: 0, denominator: 1 };
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
whole,
|
|
267
|
+
numerator: bestNumerator,
|
|
268
|
+
denominator: bestDenominator,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Format dimension as imperial string
|
|
273
|
+
*/
|
|
274
|
+
function formatImperial(dim, precision = 64) {
|
|
275
|
+
const inches = toInches(dim);
|
|
276
|
+
// Check if we should use feet
|
|
277
|
+
if (inches >= 12) {
|
|
278
|
+
const feet = Math.floor(inches / 12);
|
|
279
|
+
const remainingInches = inches % 12;
|
|
280
|
+
if (remainingInches < 0.01) {
|
|
281
|
+
return `${feet}'`;
|
|
282
|
+
}
|
|
283
|
+
const frac = decimalToFraction(remainingInches, precision);
|
|
284
|
+
if (frac.numerator === 0) {
|
|
285
|
+
return `${feet}'${frac.whole}"`;
|
|
286
|
+
}
|
|
287
|
+
if (frac.whole === 0) {
|
|
288
|
+
return `${feet}'${frac.numerator}/${frac.denominator}"`;
|
|
289
|
+
}
|
|
290
|
+
return `${feet}'${frac.whole}-${frac.numerator}/${frac.denominator}"`;
|
|
291
|
+
}
|
|
292
|
+
// Format as inches
|
|
293
|
+
const frac = decimalToFraction(inches, precision);
|
|
294
|
+
if (frac.numerator === 0) {
|
|
295
|
+
return `${frac.whole}"`;
|
|
296
|
+
}
|
|
297
|
+
if (frac.whole === 0) {
|
|
298
|
+
return `${frac.numerator}/${frac.denominator}"`;
|
|
299
|
+
}
|
|
300
|
+
return `${frac.whole}-${frac.numerator}/${frac.denominator}"`;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Format dimension as metric string
|
|
304
|
+
*/
|
|
305
|
+
function formatMetric(dim, decimals = 1) {
|
|
306
|
+
const mm = toMillimeters(dim);
|
|
307
|
+
if (mm >= 1000) {
|
|
308
|
+
return `${(mm / 1000).toFixed(decimals)}m`;
|
|
309
|
+
}
|
|
310
|
+
if (mm >= 100 && mm % 10 === 0) {
|
|
311
|
+
return `${mm / 10}cm`;
|
|
312
|
+
}
|
|
313
|
+
return `${mm.toFixed(decimals)}mm`;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Format dimension in its native unit
|
|
317
|
+
*/
|
|
318
|
+
function formatDimension(dim) {
|
|
319
|
+
if (dim.unit === 'imperial') {
|
|
320
|
+
return formatImperial(dim);
|
|
321
|
+
}
|
|
322
|
+
return formatMetric(dim);
|
|
323
|
+
}
|
|
324
|
+
// ============================================
|
|
325
|
+
// UTILITY FUNCTIONS
|
|
326
|
+
// ============================================
|
|
327
|
+
function greatestCommonDivisor(a, b) {
|
|
328
|
+
return b === 0 ? a : greatestCommonDivisor(b, a % b);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Parse dimensional lumber notation (e.g., "2x4")
|
|
332
|
+
*/
|
|
333
|
+
function parseDimensionalLumber(notation) {
|
|
334
|
+
const match = notation.match(PATTERNS.dimensionalLumber);
|
|
335
|
+
if (!match)
|
|
336
|
+
return null;
|
|
337
|
+
const key = `${match[1]}x${match[2]}`;
|
|
338
|
+
const actual = DIMENSIONAL_LUMBER[key];
|
|
339
|
+
if (!actual)
|
|
340
|
+
return null;
|
|
341
|
+
return {
|
|
342
|
+
width: { value: actual.width, unit: 'imperial', original: `${actual.width}"` },
|
|
343
|
+
thickness: { value: actual.thickness, unit: 'imperial', original: `${actual.thickness}"` },
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Check if a string is a variable reference
|
|
348
|
+
*/
|
|
349
|
+
function isVariableReference(input) {
|
|
350
|
+
return PATTERNS.variable.test(input.trim());
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Extract variable name from reference
|
|
354
|
+
*/
|
|
355
|
+
function extractVariableName(input) {
|
|
356
|
+
const match = input.trim().match(PATTERNS.variable);
|
|
357
|
+
return match ? match[1] : null;
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=units.js.map
|