tsdraft 0.1.0 → 0.2.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.
@@ -0,0 +1,333 @@
1
+ import { extents } from "./extents.js";
2
+ import { dxfText, fmt } from "./format.js";
3
+ /** `$INSUNITS` codes from the DXF Reference. */
4
+ const INSUNITS = { in: 1, ft: 2, mm: 4, cm: 5, m: 6 };
5
+ /**
6
+ * Writes an ASCII DXF for AutoCAD 2018 and later (AC1032), the newest DXF
7
+ * version Autodesk has published. AutoCAD 2027 still reads and writes AC1032.
8
+ *
9
+ * Unlike R12, this version has handles, owner links, an OBJECTS section and the
10
+ * `$INSUNITS` header, so the drawing's units reach CAD and xref and block
11
+ * insertion scale correctly. Text is UTF-8.
12
+ */
13
+ export function toDXFR2018(drawing) {
14
+ let seed = 1;
15
+ const handle = () => (seed++).toString(16).toUpperCase();
16
+ const body = [];
17
+ const g = groupWriter(body);
18
+ const rootDictionary = handle();
19
+ const groupDictionary = handle();
20
+ const plotStyleDictionary = handle();
21
+ const normalPlotStyle = handle();
22
+ const modelSpace = handle();
23
+ const paperSpace = handle();
24
+ const [minX, minY, maxX, maxY] = extents(drawing.entities);
25
+ g(0, "SECTION");
26
+ g(2, "CLASSES");
27
+ g(0, "ENDSEC");
28
+ g(0, "SECTION");
29
+ g(2, "TABLES");
30
+ writeTable(g, handle, "VPORT", [
31
+ {
32
+ type: "VPORT",
33
+ subclass: "AcDbViewportTableRecord",
34
+ name: "*Active",
35
+ handle: handle(),
36
+ fields: (g) => writeActiveViewport(g, minX, minY, maxX, maxY),
37
+ },
38
+ ]);
39
+ writeTable(g, handle, "LTYPE", [
40
+ ["ByBlock", ""],
41
+ ["ByLayer", ""],
42
+ ["Continuous", "Solid line"],
43
+ ].map(([name = "", description = ""]) => ({
44
+ type: "LTYPE",
45
+ subclass: "AcDbLinetypeTableRecord",
46
+ name,
47
+ handle: handle(),
48
+ fields: (g) => {
49
+ g(3, description);
50
+ g(72, 65);
51
+ g(73, 0);
52
+ g(40, 0);
53
+ },
54
+ })));
55
+ writeTable(g, handle, "LAYER", drawing.layers.map((layer) => ({
56
+ type: "LAYER",
57
+ subclass: "AcDbLayerTableRecord",
58
+ name: layer.name,
59
+ handle: handle(),
60
+ fields: (g) => {
61
+ g(62, layer.color);
62
+ g(6, "Continuous");
63
+ g(370, -3); // lineweight: default
64
+ g(390, normalPlotStyle); // AutoCAD rejects a layer without a plot style
65
+ },
66
+ })));
67
+ writeTable(g, handle, "STYLE", [
68
+ {
69
+ type: "STYLE",
70
+ subclass: "AcDbTextStyleTableRecord",
71
+ name: "Standard",
72
+ handle: handle(),
73
+ fields: (g) => {
74
+ g(40, 0); // fixed height: none
75
+ g(41, 1); // width factor
76
+ g(50, 0); // oblique angle
77
+ g(71, 0); // generation flags
78
+ g(42, 0.2); // last height used
79
+ g(3, "txt");
80
+ g(4, "");
81
+ },
82
+ },
83
+ ]);
84
+ writeTable(g, handle, "VIEW", []);
85
+ writeTable(g, handle, "UCS", []);
86
+ writeTable(g, handle, "APPID", [
87
+ { type: "APPID", subclass: "AcDbRegAppTableRecord", name: "ACAD", handle: handle() },
88
+ ]);
89
+ writeTable(g, handle, "DIMSTYLE", [
90
+ { type: "DIMSTYLE", subclass: "AcDbDimStyleTableRecord", name: "Standard", handle: handle() },
91
+ ]);
92
+ const blockRecordFields = (g) => {
93
+ g(280, 1); // explodable
94
+ g(281, 0); // scale uniformly: no
95
+ };
96
+ writeTable(g, handle, "BLOCK_RECORD", [
97
+ {
98
+ type: "BLOCK_RECORD",
99
+ subclass: "AcDbBlockTableRecord",
100
+ name: "*Model_Space",
101
+ handle: modelSpace,
102
+ fields: blockRecordFields,
103
+ },
104
+ {
105
+ type: "BLOCK_RECORD",
106
+ subclass: "AcDbBlockTableRecord",
107
+ name: "*Paper_Space",
108
+ handle: paperSpace,
109
+ fields: blockRecordFields,
110
+ },
111
+ ]);
112
+ g(0, "ENDSEC");
113
+ g(0, "SECTION");
114
+ g(2, "BLOCKS");
115
+ writeBlock(g, handle, "*Model_Space", modelSpace, false);
116
+ writeBlock(g, handle, "*Paper_Space", paperSpace, true);
117
+ g(0, "ENDSEC");
118
+ g(0, "SECTION");
119
+ g(2, "ENTITIES");
120
+ for (const entity of drawing.entities)
121
+ writeEntity(g, entity, handle(), modelSpace);
122
+ g(0, "ENDSEC");
123
+ g(0, "SECTION");
124
+ g(2, "OBJECTS");
125
+ g(0, "DICTIONARY");
126
+ g(5, rootDictionary);
127
+ g(330, "0");
128
+ g(100, "AcDbDictionary");
129
+ g(281, 1); // duplicate records: keep existing
130
+ g(3, "ACAD_GROUP");
131
+ g(350, groupDictionary);
132
+ g(3, "ACAD_PLOTSTYLENAME");
133
+ g(350, plotStyleDictionary);
134
+ g(0, "DICTIONARY");
135
+ ownedBy(g, groupDictionary, rootDictionary);
136
+ g(100, "AcDbDictionary");
137
+ g(281, 1);
138
+ // Plot style names: a dictionary with a default, holding the "Normal" placeholder.
139
+ g(0, "ACDBDICTIONARYWDFLT");
140
+ ownedBy(g, plotStyleDictionary, rootDictionary);
141
+ g(100, "AcDbDictionary");
142
+ g(281, 1);
143
+ g(3, "Normal");
144
+ g(350, normalPlotStyle);
145
+ g(100, "AcDbDictionaryWithDefault");
146
+ g(340, normalPlotStyle);
147
+ g(0, "ACDBPLACEHOLDER");
148
+ ownedBy(g, normalPlotStyle, plotStyleDictionary);
149
+ g(0, "ENDSEC");
150
+ g(0, "EOF");
151
+ // The header goes first in the file but is written last, once every handle is assigned.
152
+ const header = [];
153
+ const h = groupWriter(header);
154
+ h(0, "SECTION");
155
+ h(2, "HEADER");
156
+ h(9, "$ACADVER");
157
+ h(1, "AC1032");
158
+ h(9, "$DWGCODEPAGE");
159
+ h(3, "ANSI_1252");
160
+ h(9, "$INSBASE");
161
+ point(h, 10, 0, 0);
162
+ h(9, "$EXTMIN");
163
+ point(h, 10, minX, minY);
164
+ h(9, "$EXTMAX");
165
+ point(h, 10, maxX, maxY);
166
+ h(9, "$INSUNITS");
167
+ h(70, INSUNITS[drawing.units]);
168
+ h(9, "$MEASUREMENT");
169
+ h(70, drawing.units === "in" || drawing.units === "ft" ? 0 : 1);
170
+ h(9, "$CLAYER");
171
+ h(8, "0");
172
+ h(9, "$HANDSEED");
173
+ h(5, handle());
174
+ h(0, "ENDSEC");
175
+ return [...header, ...body].join("\r\n") + "\r\n";
176
+ }
177
+ function groupWriter(out) {
178
+ return (code, value) => {
179
+ out.push(String(code), typeof value === "number" ? fmt(value) : value);
180
+ };
181
+ }
182
+ /** Handle, reactor and owner fields for an object owned by a dictionary. */
183
+ function ownedBy(g, handle, owner) {
184
+ g(5, handle);
185
+ g(102, "{ACAD_REACTORS");
186
+ g(330, owner);
187
+ g(102, "}");
188
+ g(330, owner);
189
+ }
190
+ function point(g, code, x, y) {
191
+ g(code, x);
192
+ g(code + 10, y);
193
+ g(code + 20, 0);
194
+ }
195
+ function writeTable(g, handle, name, records) {
196
+ const table = handle();
197
+ g(0, "TABLE");
198
+ g(2, name);
199
+ g(5, table);
200
+ g(330, "0");
201
+ g(100, "AcDbSymbolTable");
202
+ g(70, records.length);
203
+ if (name === "DIMSTYLE") {
204
+ g(100, "AcDbDimStyleTable");
205
+ g(71, records.length);
206
+ for (const r of records)
207
+ g(340, r.handle);
208
+ }
209
+ for (const r of records) {
210
+ g(0, r.type);
211
+ // DIMSTYLE records use 105 for their handle, because 5 is DIMBLK's code there.
212
+ g(r.type === "DIMSTYLE" ? 105 : 5, r.handle);
213
+ g(330, table);
214
+ g(100, "AcDbSymbolTableRecord");
215
+ g(100, r.subclass);
216
+ g(2, r.name);
217
+ g(70, 0);
218
+ r.fields?.(g);
219
+ }
220
+ g(0, "ENDTAB");
221
+ }
222
+ /** The *Active viewport, zoomed to the drawing's extents so the file opens on the drawing. */
223
+ function writeActiveViewport(g, minX, minY, maxX, maxY) {
224
+ const aspect = 1.6;
225
+ const height = Math.max(maxY - minY, (maxX - minX) / aspect, 1) * 1.1;
226
+ g(10, 0); // lower-left corner of the viewport on screen
227
+ g(20, 0);
228
+ g(11, 1); // upper-right corner
229
+ g(21, 1);
230
+ g(12, (minX + maxX) / 2); // view center
231
+ g(22, (minY + maxY) / 2);
232
+ g(13, 0); // snap base
233
+ g(23, 0);
234
+ g(14, 0.5); // snap spacing
235
+ g(24, 0.5);
236
+ g(15, 0.5); // grid spacing
237
+ g(25, 0.5);
238
+ g(16, 0); // view direction
239
+ g(26, 0);
240
+ g(36, 1);
241
+ g(17, 0); // view target
242
+ g(27, 0);
243
+ g(37, 0);
244
+ g(40, height);
245
+ g(41, aspect);
246
+ g(42, 50); // lens length
247
+ g(43, 0); // front clip
248
+ g(44, 0); // back clip
249
+ g(50, 0); // snap rotation
250
+ g(51, 0); // view twist
251
+ g(71, 0); // view mode
252
+ g(72, 1000); // circle zoom percent
253
+ g(73, 1); // fast zoom
254
+ g(74, 3); // UCS icon
255
+ g(75, 0); // snap off
256
+ g(76, 0); // grid off
257
+ g(77, 0); // snap style
258
+ g(78, 0); // snap isopair
259
+ }
260
+ function writeBlock(g, handle, name, owner, paper) {
261
+ g(0, "BLOCK");
262
+ g(5, handle());
263
+ g(330, owner);
264
+ g(100, "AcDbEntity");
265
+ if (paper)
266
+ g(67, 1);
267
+ g(8, "0");
268
+ g(100, "AcDbBlockBegin");
269
+ g(2, name);
270
+ g(70, 0);
271
+ point(g, 10, 0, 0);
272
+ g(3, name);
273
+ g(1, "");
274
+ g(0, "ENDBLK");
275
+ g(5, handle());
276
+ g(330, owner);
277
+ g(100, "AcDbEntity");
278
+ if (paper)
279
+ g(67, 1);
280
+ g(8, "0");
281
+ g(100, "AcDbBlockEnd");
282
+ }
283
+ function writeEntity(g, e, handle, owner) {
284
+ const begin = (type, subclass) => {
285
+ g(0, type);
286
+ g(5, handle);
287
+ g(330, owner);
288
+ g(100, "AcDbEntity");
289
+ g(8, e.layer);
290
+ g(100, subclass);
291
+ };
292
+ switch (e.kind) {
293
+ case "line":
294
+ begin("LINE", "AcDbLine");
295
+ point(g, 10, ...e.from);
296
+ point(g, 11, ...e.to);
297
+ return;
298
+ case "polyline":
299
+ begin("LWPOLYLINE", "AcDbPolyline");
300
+ g(90, e.points.length);
301
+ g(70, e.closed ? 1 : 0);
302
+ g(43, 0); // constant width
303
+ for (const [x, y] of e.points) {
304
+ g(10, x);
305
+ g(20, y);
306
+ }
307
+ return;
308
+ case "circle":
309
+ begin("CIRCLE", "AcDbCircle");
310
+ point(g, 10, ...e.center);
311
+ g(40, e.radius);
312
+ return;
313
+ case "arc":
314
+ begin("ARC", "AcDbCircle");
315
+ point(g, 10, ...e.center);
316
+ g(40, e.radius);
317
+ g(100, "AcDbArc");
318
+ g(50, e.startAngle);
319
+ g(51, e.endAngle);
320
+ return;
321
+ case "text":
322
+ begin("TEXT", "AcDbText");
323
+ point(g, 10, ...e.at);
324
+ g(40, e.height);
325
+ g(1, dxfText(e.value));
326
+ if (e.rotation !== 0)
327
+ g(50, e.rotation);
328
+ g(7, "Standard");
329
+ // TEXT repeats its subclass marker before the vertical alignment fields.
330
+ g(100, "AcDbText");
331
+ return;
332
+ }
333
+ }
package/dist/dxf.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import type { Drawing } from "./drawing.ts";
1
+ import type { Drawing, DxfVersion } from "./drawing.ts";
2
+ export interface DxfOptions {
3
+ /** Defaults to the version the drawing was created for, which is `"R12"` unless set. */
4
+ readonly version?: DxfVersion;
5
+ }
2
6
  /**
3
- * Writes an ASCII DXF (AC1009, R12). R12 is the most widely readable DXF:
4
- * AutoCAD, BricsCAD, LibreCAD, QCAD and most converters open it.
5
- *
6
- * R12 has no header variable for drawing units, so coordinates are written as
7
- * plain numbers in the drawing's units and `drawing.units` is not written.
7
+ * Writes the drawing as ASCII DXF. Throws a `DrawingError` listing every lint
8
+ * error when the drawing breaks a rule of the version being written, because
9
+ * AutoCAD would reject or garble the file.
8
10
  */
9
- export declare function toDXF(drawing: Drawing): string;
11
+ export declare function toDXF(drawing: Drawing, options?: DxfOptions): string;
package/dist/dxf.js CHANGED
@@ -1,112 +1,18 @@
1
- import { fmt } from "./format.js";
1
+ import { toDXFR12 } from "./dxf-r12.js";
2
+ import { toDXFR2018 } from "./dxf-r2018.js";
3
+ import { DrawingError, lint } from "./lint.js";
2
4
  /**
3
- * Writes an ASCII DXF (AC1009, R12). R12 is the most widely readable DXF:
4
- * AutoCAD, BricsCAD, LibreCAD, QCAD and most converters open it.
5
- *
6
- * R12 has no header variable for drawing units, so coordinates are written as
7
- * plain numbers in the drawing's units and `drawing.units` is not written.
5
+ * Writes the drawing as ASCII DXF. Throws a `DrawingError` listing every lint
6
+ * error when the drawing breaks a rule of the version being written, because
7
+ * AutoCAD would reject or garble the file.
8
8
  */
9
- export function toDXF(drawing) {
10
- const out = [];
11
- const g = (code, value) => {
12
- out.push(String(code), typeof value === "number" ? fmt(value) : value);
13
- };
14
- g(0, "SECTION");
15
- g(2, "HEADER");
16
- g(9, "$ACADVER");
17
- g(1, "AC1009");
18
- g(0, "ENDSEC");
19
- g(0, "SECTION");
20
- g(2, "TABLES");
21
- g(0, "TABLE");
22
- g(2, "LTYPE");
23
- g(70, "1");
24
- g(0, "LTYPE");
25
- g(2, "CONTINUOUS");
26
- g(70, "0");
27
- g(3, "Solid line");
28
- g(72, "65");
29
- g(73, "0");
30
- g(40, "0.0");
31
- g(0, "ENDTAB");
32
- g(0, "TABLE");
33
- g(2, "LAYER");
34
- g(70, String(drawing.layers.length));
35
- for (const layer of drawing.layers) {
36
- g(0, "LAYER");
37
- g(2, layer.name);
38
- g(70, "0");
39
- g(62, String(layer.color));
40
- g(6, "CONTINUOUS");
41
- }
42
- g(0, "ENDTAB");
43
- g(0, "ENDSEC");
44
- g(0, "SECTION");
45
- g(2, "ENTITIES");
46
- for (const entity of drawing.entities)
47
- writeEntity(entity, g);
48
- g(0, "ENDSEC");
49
- g(0, "EOF");
50
- return out.join("\r\n") + "\r\n";
51
- }
52
- function writeEntity(e, g) {
53
- switch (e.kind) {
54
- case "line":
55
- g(0, "LINE");
56
- g(8, e.layer);
57
- g(10, e.from[0]);
58
- g(20, e.from[1]);
59
- g(30, 0);
60
- g(11, e.to[0]);
61
- g(21, e.to[1]);
62
- g(31, 0);
63
- return;
64
- case "polyline":
65
- g(0, "POLYLINE");
66
- g(8, e.layer);
67
- g(66, "1");
68
- g(10, 0);
69
- g(20, 0);
70
- g(30, 0);
71
- g(70, e.closed ? "1" : "0");
72
- for (const [x, y] of e.points) {
73
- g(0, "VERTEX");
74
- g(8, e.layer);
75
- g(10, x);
76
- g(20, y);
77
- g(30, 0);
78
- }
79
- g(0, "SEQEND");
80
- g(8, e.layer);
81
- return;
82
- case "circle":
83
- g(0, "CIRCLE");
84
- g(8, e.layer);
85
- g(10, e.center[0]);
86
- g(20, e.center[1]);
87
- g(30, 0);
88
- g(40, e.radius);
89
- return;
90
- case "arc":
91
- g(0, "ARC");
92
- g(8, e.layer);
93
- g(10, e.center[0]);
94
- g(20, e.center[1]);
95
- g(30, 0);
96
- g(40, e.radius);
97
- g(50, e.startAngle);
98
- g(51, e.endAngle);
99
- return;
100
- case "text":
101
- g(0, "TEXT");
102
- g(8, e.layer);
103
- g(10, e.at[0]);
104
- g(20, e.at[1]);
105
- g(30, 0);
106
- g(40, e.height);
107
- g(1, e.value);
108
- if (e.rotation !== 0)
109
- g(50, e.rotation);
110
- return;
9
+ export function toDXF(drawing, options = {}) {
10
+ const version = options.version ?? drawing.dxf;
11
+ if (version !== "R12" && version !== "R2018") {
12
+ throw new Error(`Unsupported DXF version: ${JSON.stringify(version)}`);
111
13
  }
14
+ const errors = lint(drawing, { version }).filter((d) => d.severity === "error");
15
+ if (errors.length > 0)
16
+ throw new DrawingError(errors);
17
+ return version === "R12" ? toDXFR12(drawing) : toDXFR2018(drawing);
112
18
  }
@@ -0,0 +1,3 @@
1
+ import type { Entity } from "./drawing.ts";
2
+ /** Approximate extents. Arcs use their full circle; text assumes 0.6 × height per character. */
3
+ export declare function extents(entities: readonly Entity[]): [number, number, number, number];
@@ -0,0 +1,42 @@
1
+ /** Approximate extents. Arcs use their full circle; text assumes 0.6 × height per character. */
2
+ export function extents(entities) {
3
+ let minX = Infinity;
4
+ let minY = Infinity;
5
+ let maxX = -Infinity;
6
+ let maxY = -Infinity;
7
+ const add = (x, y) => {
8
+ minX = Math.min(minX, x);
9
+ minY = Math.min(minY, y);
10
+ maxX = Math.max(maxX, x);
11
+ maxY = Math.max(maxY, y);
12
+ };
13
+ for (const e of entities) {
14
+ switch (e.kind) {
15
+ case "line":
16
+ add(...e.from);
17
+ add(...e.to);
18
+ break;
19
+ case "polyline":
20
+ for (const p of e.points)
21
+ add(...p);
22
+ break;
23
+ case "circle":
24
+ case "arc":
25
+ add(e.center[0] - e.radius, e.center[1] - e.radius);
26
+ add(e.center[0] + e.radius, e.center[1] + e.radius);
27
+ break;
28
+ case "text": {
29
+ const len = e.value.length * e.height * 0.6;
30
+ const r = rad(e.rotation);
31
+ add(...e.at);
32
+ add(e.at[0] + len * Math.cos(r), e.at[1] + len * Math.sin(r));
33
+ add(e.at[0] - e.height * Math.sin(r), e.at[1] + e.height * Math.cos(r));
34
+ break;
35
+ }
36
+ }
37
+ }
38
+ return minX === Infinity ? [0, 0, 1, 1] : [minX, minY, maxX, maxY];
39
+ }
40
+ function rad(degrees) {
41
+ return (degrees * Math.PI) / 180;
42
+ }
package/dist/format.d.ts CHANGED
@@ -1,2 +1,11 @@
1
1
  /** Formats a coordinate with at most 6 decimals, no float noise, and no "-0". */
2
2
  export declare function fmt(value: number): string;
3
+ /**
4
+ * Escapes a string value for DXF. A caret starts a control-character escape in
5
+ * DXF, and AutoCAD discards the drawing when it meets a bare one, so a literal
6
+ * caret is written as a caret and a space.
7
+ *
8
+ * With `ascii`, characters outside ASCII become `\U+XXXX`, which is how DXF
9
+ * versions before 2007 carry them. Later versions are UTF-8 and need no escape.
10
+ */
11
+ export declare function dxfText(value: string, ascii?: boolean): string;
package/dist/format.js CHANGED
@@ -3,3 +3,22 @@ export function fmt(value) {
3
3
  const rounded = Number(value.toFixed(6));
4
4
  return Object.is(rounded, -0) ? "0" : String(rounded);
5
5
  }
6
+ /**
7
+ * Escapes a string value for DXF. A caret starts a control-character escape in
8
+ * DXF, and AutoCAD discards the drawing when it meets a bare one, so a literal
9
+ * caret is written as a caret and a space.
10
+ *
11
+ * With `ascii`, characters outside ASCII become `\U+XXXX`, which is how DXF
12
+ * versions before 2007 carry them. Later versions are UTF-8 and need no escape.
13
+ */
14
+ export function dxfText(value, ascii = false) {
15
+ const escaped = value.replaceAll("^", "^ ");
16
+ if (!ascii)
17
+ return escaped;
18
+ let out = "";
19
+ for (let i = 0; i < escaped.length; i++) {
20
+ const code = escaped.charCodeAt(i);
21
+ out += code < 0x80 ? escaped[i] : `\\U+${code.toString(16).toUpperCase().padStart(4, "0")}`;
22
+ }
23
+ return out;
24
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
- export { createDrawing, DrawingBuilder, sweep, type Arc, type Circle, type Drawing, type DrawingOptions, type Entity, type Layer, type LayerOptions, type Line, type Point, type Polyline, type Text, type TextOptions, type Units, } from "./drawing.ts";
2
- export { toDXF } from "./dxf.ts";
1
+ export { createDrawing, DrawingBuilder, sweep, type Arc, type Circle, type Drawing, type DrawingOptions, type DxfVersion, type Entity, type Layer, type LayerOptions, type Line, type Point, type Polyline, type Text, type TextOptions, type Units, } from "./drawing.ts";
2
+ export { toDXF, type DxfOptions } from "./dxf.ts";
3
+ export { DrawingError, lint, type Diagnostic, type LintOptions, type LintRule } from "./lint.ts";
4
+ export type { Aci, LayerColor, LayerName, Positive } from "./rules.ts";
3
5
  export { toSVG, type SvgOptions } from "./svg.ts";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { createDrawing, DrawingBuilder, sweep, } from "./drawing.js";
2
2
  export { toDXF } from "./dxf.js";
3
+ export { DrawingError, lint } from "./lint.js";
3
4
  export { toSVG } from "./svg.js";
package/dist/lint.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { Drawing, DxfVersion } from "./drawing.ts";
2
+ export type LintRule = "units" | "layer-name" | "duplicate-layer" | "layer-color" | "undefined-layer" | "geometry" | "text" | "zero-length";
3
+ export interface Diagnostic {
4
+ readonly rule: LintRule;
5
+ /** An error means AutoCAD rejects, repairs or garbles the output. `toDXF` refuses to write it. */
6
+ readonly severity: "error" | "warning";
7
+ readonly message: string;
8
+ /** The layer the problem is in, when it is a layer problem. */
9
+ readonly layer?: string;
10
+ /** Index into `drawing.entities`, when it is an entity problem. */
11
+ readonly entity?: number;
12
+ }
13
+ export interface LintOptions {
14
+ /** The DXF version to check against. Defaults to the drawing's own. */
15
+ readonly version?: DxfVersion;
16
+ }
17
+ /**
18
+ * Checks a drawing against the rules AutoCAD enforces when it opens DXF.
19
+ *
20
+ * A drawing made with `createDrawing()` already passes the error rules for its
21
+ * own DXF version, because the builder throws at the offending call. `lint`
22
+ * matters when a `Drawing` was built by hand or by other code, when it is
23
+ * exported as a different version than it was built for, and for warnings.
24
+ */
25
+ export declare function lint(drawing: Drawing, options?: LintOptions): Diagnostic[];
26
+ /** Thrown by `toDXF` when a drawing has lint errors for the version being written. */
27
+ export declare class DrawingError extends Error {
28
+ readonly diagnostics: readonly Diagnostic[];
29
+ constructor(diagnostics: readonly Diagnostic[]);
30
+ }