@miclivs/cadcli 0.1.2 → 0.3.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 +70 -14
- package/dist/commands/edit.d.ts +42 -2
- package/dist/commands/edit.js +281 -7
- package/dist/commands/json.js +0 -1
- package/dist/commands/query.d.ts +7 -0
- package/dist/commands/query.js +45 -0
- package/dist/commands/shared.d.ts +0 -1
- package/dist/commands/shared.js +0 -1
- package/dist/commands/svg.js +0 -1
- package/dist/commands/thumbnail.js +0 -1
- package/dist/commands/view.d.ts +0 -1
- package/dist/commands/view.js +5 -7
- package/dist/core/acad-edit.d.ts +142 -0
- package/dist/core/acad-edit.js +234 -0
- package/dist/core/acad-view.d.ts +6 -0
- package/dist/core/acad-view.js +22 -0
- package/dist/core/acad.d.ts +11 -0
- package/dist/core/acad.js +82 -0
- package/dist/core/adapter.d.ts +0 -6
- package/dist/core/adapter.js +16 -14
- package/dist/core/drawing.d.ts +0 -1
- package/dist/core/drawing.js +2 -1
- package/dist/core/normalize.js +4 -1
- package/dist/core/query.d.ts +17 -0
- package/dist/core/query.js +232 -0
- package/dist/core/text-normalize.d.ts +3 -0
- package/dist/core/text-normalize.js +104 -0
- package/dist/index.d.ts +2 -1
- package/dist/main.js +98 -7
- package/dist/sdk.d.ts +5 -7
- package/dist/sdk.js +6 -6
- package/dist/types.d.ts +9 -0
- package/package.json +2 -2
- package/skills/cadcli/SKILL.md +50 -9
- package/dist/core/libredwg.d.ts +0 -37
- package/dist/core/libredwg.js +0 -86
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Agent-friendly CAD inspection, search, viewing, and editing for DWG/DXF files.
|
|
|
6
6
|
npm install -g @miclivs/cadcli
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Inspection, search, viewing, and editing use the pure TypeScript `acad-ts` backend. No native CAD tools are required.
|
|
10
10
|
|
|
11
11
|
## Why cadcli
|
|
12
12
|
|
|
@@ -17,7 +17,7 @@ cadcli info floorplan.dwg --json
|
|
|
17
17
|
cadcli overview floorplan.dwg
|
|
18
18
|
cadcli search floorplan.dwg "conference" --layer A-TEXT --json
|
|
19
19
|
cadcli view floorplan.dwg -o preview.svg
|
|
20
|
-
cadcli edit floorplan.dwg --
|
|
20
|
+
cadcli edit floorplan.dwg --set-text "Conference" --text-id 2A -o edited.dwg
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Workflow
|
|
@@ -41,9 +41,20 @@ cadcli entities <file> # entities, optionally filtered
|
|
|
41
41
|
|
|
42
42
|
cadcli search <file> [query] # search IDs, types, layers, text, raw fields
|
|
43
43
|
--query "door" --type TEXT --layer A-TEXT --limit 10 --score --no-snippets
|
|
44
|
-
|
|
45
|
-
cadcli
|
|
46
|
-
|
|
44
|
+
cadcli query <file> --schema # show SQL query tables
|
|
45
|
+
cadcli query <file> --sql "select text from texts"
|
|
46
|
+
|
|
47
|
+
cadcli view <file> [-o preview.svg] # SVG preview
|
|
48
|
+
cadcli edit <file> --set-text <text> --text-id <id> -o out.dwg
|
|
49
|
+
cadcli edit <file> --set-layer <layer> --layer-id <id> -o out.dwg
|
|
50
|
+
cadcli edit <file> --set-color '#ff0000' --color-id <id> -o out.dwg
|
|
51
|
+
cadcli edit <file> --move <id> --dx 10 --dy 0 -o out.dwg
|
|
52
|
+
cadcli edit <file> --rotate <id> --angle 90 --origin 0,0 -o out.dwg
|
|
53
|
+
cadcli edit <file> --scale <id> --factor 2 -o out.dwg
|
|
54
|
+
cadcli edit <file> --copy <id> --dx 10 --dy 0 -o out.dwg
|
|
55
|
+
cadcli edit <file> --delete <id> -o out.dwg
|
|
56
|
+
cadcli edit <file> --add-line 0,0:10,0 --new-layer A-WALL -o out.dwg
|
|
57
|
+
cadcli edit <file> --add-text "Label" --at 5,5 --height 2.5 -o out.dwg
|
|
47
58
|
cadcli json <file> [-o drawing.json] # normalized JSON
|
|
48
59
|
cadcli svg <file> [-o sketch.svg] # best-effort SVG from normalized JSON
|
|
49
60
|
cadcli thumbnail <file> [-o thumb.png] # embedded thumbnail when available
|
|
@@ -72,24 +83,71 @@ SEARCH HINTS
|
|
|
72
83
|
```
|
|
73
84
|
|
|
74
85
|
|
|
86
|
+
## Text normalization
|
|
87
|
+
|
|
88
|
+
Some CAD files store visible text through legacy code pages and SHX fonts. For example, a Hebrew DWG may store `jsr muu, 8` while AutoCAD displays it as `חדר צוות 8`. `cadcli` automatically normalizes these cases while loading the drawing, before `overview`, `search`, `entities`, `json`, and future query features consume the document.
|
|
89
|
+
|
|
90
|
+
The normalizer is route-based: document metadata such as `codePage` is combined with per-entity text style/font metadata such as `gil.shx`, `narkism$.shx`, or `heb.shx`. When the route is confident, `cadcli` rewrites the in-memory `text` field to the intended text. It does not store both raw and normalized copies in caches or output.
|
|
91
|
+
|
|
92
|
+
```txt
|
|
93
|
+
raw DWG text: jsr muu, 8
|
|
94
|
+
cadcli text: חדר צוות 8
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The normalized document metadata records what happened:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"metadata": {
|
|
102
|
+
"codePage": "ansi_1255",
|
|
103
|
+
"textNormalization": {
|
|
104
|
+
"applied": ["hebrew-keyboard"],
|
|
105
|
+
"entitiesChanged": 58
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
This makes discovery work naturally:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cadcli overview office.dwg
|
|
115
|
+
cadcli search office.dwg "חדר" --json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Query
|
|
119
|
+
|
|
120
|
+
`cadcli query` runs read-only SQL over a narrow in-memory projection of the normalized drawing. It does not create a user-visible database file.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
cadcli query office.dwg --schema
|
|
124
|
+
cadcli query office.dwg --schema --json
|
|
125
|
+
cadcli query office.dwg --sql "select id, text, layer, x, y from texts where text like 'חדר%'" --json
|
|
126
|
+
cadcli query office.dwg --file rooms.sql --json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The base tables are `summary`, `metadata`, `layers`, `blocks`, and `entities`. Convenience tables expose common drawing concepts such as `texts` and `inserts`.
|
|
130
|
+
|
|
75
131
|
## Viewing vs SVG export
|
|
76
132
|
|
|
77
|
-
`cadcli view`
|
|
133
|
+
`cadcli view` renders SVG through acad-ts directly from the CAD document.
|
|
78
134
|
|
|
79
|
-
`cadcli svg` renders a lightweight SVG from cadcli’s normalized JSON model. It is useful for quick agent previews and debugging,
|
|
135
|
+
`cadcli svg` renders a lightweight SVG from cadcli’s normalized JSON model. It is useful for quick agent previews and debugging, while `view` preserves more of acad-ts’ CAD model semantics.
|
|
80
136
|
|
|
81
137
|
## Editing
|
|
82
138
|
|
|
83
|
-
Editing is intentionally copy-first
|
|
139
|
+
Editing is intentionally copy-first and typed. You can update text, layers, color, linetype, lineweight, transparency, visibility, block attributes, transforms, copies, and deletion; you can also add point, line, circle, arc, text, mtext, and lightweight polyline entities.
|
|
84
140
|
|
|
85
141
|
```bash
|
|
86
|
-
cadcli edit drawing.dwg --
|
|
142
|
+
cadcli edit drawing.dwg --set-text "New label" --text-id 2A -o edited.dwg
|
|
143
|
+
cadcli edit drawing.dwg --set-attr ROOM=204 --insert-id 3F -o edited.dwg
|
|
144
|
+
cadcli edit drawing.dwg --points '0,0;10,0;10,5' --closed --new-layer A-WALL -o edited.dwg
|
|
87
145
|
```
|
|
88
146
|
|
|
89
147
|
In-place edits are refused unless you explicitly pass `--overwrite`:
|
|
90
148
|
|
|
91
149
|
```bash
|
|
92
|
-
cadcli edit drawing.dwg --
|
|
150
|
+
cadcli edit drawing.dwg --set-text "New label" --text-id 2A --overwrite
|
|
93
151
|
```
|
|
94
152
|
|
|
95
153
|
## SDK
|
|
@@ -107,7 +165,7 @@ const preview = drawing.view();
|
|
|
107
165
|
console.log(preview.svg);
|
|
108
166
|
```
|
|
109
167
|
|
|
110
|
-
The public SDK is intentionally small: `Dwg` plus stable CAD/result types.
|
|
168
|
+
The public SDK is intentionally small: `Dwg` plus stable CAD/result types.
|
|
111
169
|
|
|
112
170
|
## Cache
|
|
113
171
|
|
|
@@ -123,9 +181,7 @@ Set `CADCLI_CACHE_DIR` to override this location.
|
|
|
123
181
|
|
|
124
182
|
## Requirements
|
|
125
183
|
|
|
126
|
-
Inspection, overview, layers, blocks, entities, search, JSON,
|
|
127
|
-
|
|
128
|
-
Install native LibreDWG tools for advanced workflows: `dwgread` for high-fidelity `view`, and `dwgfilter` for edits.
|
|
184
|
+
Inspection, overview, layers, blocks, entities, search, JSON, SVG export, viewing, and editing work through the default pure TypeScript acad-ts backend.
|
|
129
185
|
|
|
130
186
|
## License
|
|
131
187
|
|
package/dist/commands/edit.d.ts
CHANGED
|
@@ -1,8 +1,48 @@
|
|
|
1
1
|
import type { OutputOptions } from "../utils/output.js";
|
|
2
2
|
export interface EditOptions extends OutputOptions {
|
|
3
|
-
jq?: string;
|
|
4
3
|
output?: string;
|
|
5
4
|
overwrite?: boolean;
|
|
6
|
-
|
|
5
|
+
setText?: string;
|
|
6
|
+
textId?: string;
|
|
7
|
+
delete?: string;
|
|
8
|
+
move?: string;
|
|
9
|
+
dx?: string;
|
|
10
|
+
dy?: string;
|
|
11
|
+
dz?: string;
|
|
12
|
+
setLayer?: string;
|
|
13
|
+
layerId?: string;
|
|
14
|
+
setColor?: string;
|
|
15
|
+
colorId?: string;
|
|
16
|
+
setLinetype?: string;
|
|
17
|
+
linetypeId?: string;
|
|
18
|
+
setLineweight?: string;
|
|
19
|
+
lineweightId?: string;
|
|
20
|
+
setTransparency?: string;
|
|
21
|
+
transparencyId?: string;
|
|
22
|
+
hide?: string;
|
|
23
|
+
show?: string;
|
|
24
|
+
rotate?: string;
|
|
25
|
+
angle?: string;
|
|
26
|
+
origin?: string;
|
|
27
|
+
scale?: string;
|
|
28
|
+
factor?: string;
|
|
29
|
+
copy?: string;
|
|
30
|
+
matchProperties?: string;
|
|
31
|
+
sourceId?: string;
|
|
32
|
+
setAttr?: string;
|
|
33
|
+
insertId?: string;
|
|
34
|
+
addPoint?: string;
|
|
35
|
+
addLine?: string;
|
|
36
|
+
addCircle?: string;
|
|
37
|
+
addArc?: string;
|
|
38
|
+
addText?: string;
|
|
39
|
+
addMtext?: string;
|
|
40
|
+
at?: string;
|
|
41
|
+
height?: string;
|
|
42
|
+
width?: string;
|
|
43
|
+
closed?: boolean;
|
|
44
|
+
points?: string;
|
|
45
|
+
newLayer?: string;
|
|
46
|
+
newColor?: string;
|
|
7
47
|
}
|
|
8
48
|
export declare function edit(file: string, options: EditOptions): Promise<void>;
|
package/dist/commands/edit.js
CHANGED
|
@@ -1,21 +1,295 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { editWithAcadTs, } from "../core/acad-edit.js";
|
|
2
2
|
import { output, success } from "../utils/output.js";
|
|
3
3
|
import { handleCommandError, userError } from "./shared.js";
|
|
4
|
+
function numberOption(value, name) {
|
|
5
|
+
const parsed = Number(value);
|
|
6
|
+
if (!Number.isFinite(parsed)) {
|
|
7
|
+
throw userError(`Invalid ${name}: ${value}`, "INVALID_NUMBER");
|
|
8
|
+
}
|
|
9
|
+
return parsed;
|
|
10
|
+
}
|
|
11
|
+
function pointOption(value, name) {
|
|
12
|
+
if (!value)
|
|
13
|
+
throw userError(`${name} requires x,y[,z].`, "INVALID_POINT");
|
|
14
|
+
const parts = value.split(",").map((part) => numberOption(part, name));
|
|
15
|
+
if (parts.length < 2 || parts.length > 3) {
|
|
16
|
+
throw userError(`${name} requires x,y[,z].`, "INVALID_POINT");
|
|
17
|
+
}
|
|
18
|
+
return { x: parts[0], y: parts[1], z: parts[2] };
|
|
19
|
+
}
|
|
20
|
+
function pointsOption(value, name) {
|
|
21
|
+
if (!value)
|
|
22
|
+
throw userError(`${name} requires x,y pairs.`, "INVALID_POINT");
|
|
23
|
+
const points = value.split(/[;|]/).map((part) => pointOption(part, name));
|
|
24
|
+
if (points.length < 2) {
|
|
25
|
+
throw userError(`${name} requires at least two points.`, "INVALID_POINT");
|
|
26
|
+
}
|
|
27
|
+
return points;
|
|
28
|
+
}
|
|
29
|
+
function colorOption(value, name) {
|
|
30
|
+
if (!value)
|
|
31
|
+
throw userError(`${name} requires a color.`, "INVALID_COLOR");
|
|
32
|
+
const normalized = value.toLowerCase();
|
|
33
|
+
if (normalized === "bylayer")
|
|
34
|
+
return { mode: "byLayer" };
|
|
35
|
+
if (normalized === "byblock")
|
|
36
|
+
return { mode: "byBlock" };
|
|
37
|
+
if (/^#?[0-9a-f]{6}$/i.test(value)) {
|
|
38
|
+
const hex = value.replace("#", "");
|
|
39
|
+
return {
|
|
40
|
+
mode: "rgb",
|
|
41
|
+
r: Number.parseInt(hex.slice(0, 2), 16),
|
|
42
|
+
g: Number.parseInt(hex.slice(2, 4), 16),
|
|
43
|
+
b: Number.parseInt(hex.slice(4, 6), 16),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (value.includes(",")) {
|
|
47
|
+
const [r, g, b] = value.split(",").map((part) => numberOption(part, name));
|
|
48
|
+
return { mode: "rgb", r, g, b };
|
|
49
|
+
}
|
|
50
|
+
return { mode: "index", index: numberOption(value, name) };
|
|
51
|
+
}
|
|
52
|
+
function createOptions(options) {
|
|
53
|
+
return {
|
|
54
|
+
layer: options.newLayer,
|
|
55
|
+
color: options.newColor
|
|
56
|
+
? colorOption(options.newColor, "--new-color")
|
|
57
|
+
: undefined,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function acadOperations(options) {
|
|
61
|
+
const operations = [];
|
|
62
|
+
if (options.setText !== undefined) {
|
|
63
|
+
if (!options.textId) {
|
|
64
|
+
throw userError("--set-text requires --text-id <id>.", "MISSING_TEXT_ID");
|
|
65
|
+
}
|
|
66
|
+
operations.push({
|
|
67
|
+
kind: "setText",
|
|
68
|
+
entityId: options.textId,
|
|
69
|
+
text: options.setText,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (options.setLayer !== undefined) {
|
|
73
|
+
if (!options.layerId) {
|
|
74
|
+
throw userError("--set-layer requires --layer-id <id>.", "MISSING_LAYER_ID");
|
|
75
|
+
}
|
|
76
|
+
operations.push({
|
|
77
|
+
kind: "setLayer",
|
|
78
|
+
entityId: options.layerId,
|
|
79
|
+
layer: options.setLayer,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (options.setColor !== undefined) {
|
|
83
|
+
if (!options.colorId) {
|
|
84
|
+
throw userError("--set-color requires --color-id <id>.", "MISSING_COLOR_ID");
|
|
85
|
+
}
|
|
86
|
+
operations.push({
|
|
87
|
+
kind: "setColor",
|
|
88
|
+
entityId: options.colorId,
|
|
89
|
+
color: colorOption(options.setColor, "--set-color"),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (options.setLinetype !== undefined) {
|
|
93
|
+
if (!options.linetypeId) {
|
|
94
|
+
throw userError("--set-linetype requires --linetype-id <id>.", "MISSING_LINETYPE_ID");
|
|
95
|
+
}
|
|
96
|
+
operations.push({
|
|
97
|
+
kind: "setLineType",
|
|
98
|
+
entityId: options.linetypeId,
|
|
99
|
+
lineType: options.setLinetype,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (options.setLineweight !== undefined) {
|
|
103
|
+
if (!options.lineweightId) {
|
|
104
|
+
throw userError("--set-lineweight requires --lineweight-id <id>.", "MISSING_LINEWEIGHT_ID");
|
|
105
|
+
}
|
|
106
|
+
operations.push({
|
|
107
|
+
kind: "setLineWeight",
|
|
108
|
+
entityId: options.lineweightId,
|
|
109
|
+
weight: numberOption(options.setLineweight, "--set-lineweight"),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (options.setTransparency !== undefined) {
|
|
113
|
+
if (!options.transparencyId) {
|
|
114
|
+
throw userError("--set-transparency requires --transparency-id <id>.", "MISSING_TRANSPARENCY_ID");
|
|
115
|
+
}
|
|
116
|
+
operations.push({
|
|
117
|
+
kind: "setTransparency",
|
|
118
|
+
entityId: options.transparencyId,
|
|
119
|
+
alpha: numberOption(options.setTransparency, "--set-transparency"),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (options.hide !== undefined) {
|
|
123
|
+
operations.push({
|
|
124
|
+
kind: "setVisibility",
|
|
125
|
+
entityId: options.hide,
|
|
126
|
+
visible: false,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (options.show !== undefined) {
|
|
130
|
+
operations.push({
|
|
131
|
+
kind: "setVisibility",
|
|
132
|
+
entityId: options.show,
|
|
133
|
+
visible: true,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (options.move !== undefined) {
|
|
137
|
+
operations.push({
|
|
138
|
+
kind: "move",
|
|
139
|
+
entityId: options.move,
|
|
140
|
+
dx: numberOption(options.dx ?? "0", "--dx"),
|
|
141
|
+
dy: numberOption(options.dy ?? "0", "--dy"),
|
|
142
|
+
dz: options.dz === undefined ? undefined : numberOption(options.dz, "--dz"),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (options.rotate !== undefined) {
|
|
146
|
+
operations.push({
|
|
147
|
+
kind: "rotate",
|
|
148
|
+
entityId: options.rotate,
|
|
149
|
+
angleDegrees: numberOption(options.angle, "--angle"),
|
|
150
|
+
origin: options.origin
|
|
151
|
+
? pointOption(options.origin, "--origin")
|
|
152
|
+
: undefined,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (options.scale !== undefined) {
|
|
156
|
+
operations.push({
|
|
157
|
+
kind: "scale",
|
|
158
|
+
entityId: options.scale,
|
|
159
|
+
factor: numberOption(options.factor, "--factor"),
|
|
160
|
+
origin: options.origin
|
|
161
|
+
? pointOption(options.origin, "--origin")
|
|
162
|
+
: undefined,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (options.copy !== undefined) {
|
|
166
|
+
operations.push({
|
|
167
|
+
kind: "copy",
|
|
168
|
+
entityId: options.copy,
|
|
169
|
+
dx: options.dx === undefined ? undefined : numberOption(options.dx, "--dx"),
|
|
170
|
+
dy: options.dy === undefined ? undefined : numberOption(options.dy, "--dy"),
|
|
171
|
+
dz: options.dz === undefined ? undefined : numberOption(options.dz, "--dz"),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (options.matchProperties !== undefined) {
|
|
175
|
+
if (!options.sourceId) {
|
|
176
|
+
throw userError("--match-properties requires --source-id <id>.", "MISSING_SOURCE_ID");
|
|
177
|
+
}
|
|
178
|
+
operations.push({
|
|
179
|
+
kind: "matchProperties",
|
|
180
|
+
entityId: options.matchProperties,
|
|
181
|
+
sourceId: options.sourceId,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (options.setAttr !== undefined) {
|
|
185
|
+
if (!options.insertId) {
|
|
186
|
+
throw userError("--set-attr requires --insert-id <id>.", "MISSING_INSERT_ID");
|
|
187
|
+
}
|
|
188
|
+
const [tag, ...valueParts] = options.setAttr.split("=");
|
|
189
|
+
if (!tag || valueParts.length === 0) {
|
|
190
|
+
throw userError("--set-attr requires TAG=VALUE.", "INVALID_ATTRIBUTE_EDIT");
|
|
191
|
+
}
|
|
192
|
+
operations.push({
|
|
193
|
+
kind: "setAttribute",
|
|
194
|
+
entityId: options.insertId,
|
|
195
|
+
tag,
|
|
196
|
+
value: valueParts.join("="),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (options.delete !== undefined) {
|
|
200
|
+
operations.push({ kind: "delete", entityId: options.delete });
|
|
201
|
+
}
|
|
202
|
+
const common = createOptions(options);
|
|
203
|
+
if (options.addPoint !== undefined) {
|
|
204
|
+
operations.push({
|
|
205
|
+
kind: "addPoint",
|
|
206
|
+
at: pointOption(options.addPoint, "--add-point"),
|
|
207
|
+
...common,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (options.addLine !== undefined) {
|
|
211
|
+
const [from, to] = options.addLine.split(":");
|
|
212
|
+
operations.push({
|
|
213
|
+
kind: "addLine",
|
|
214
|
+
from: pointOption(from, "--add-line"),
|
|
215
|
+
to: pointOption(to, "--add-line"),
|
|
216
|
+
...common,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (options.addCircle !== undefined) {
|
|
220
|
+
const [center, radius] = options.addCircle.split(":");
|
|
221
|
+
operations.push({
|
|
222
|
+
kind: "addCircle",
|
|
223
|
+
center: pointOption(center, "--add-circle"),
|
|
224
|
+
radius: numberOption(radius, "--add-circle radius"),
|
|
225
|
+
...common,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (options.addArc !== undefined) {
|
|
229
|
+
const [center, radius, start, end] = options.addArc.split(":");
|
|
230
|
+
operations.push({
|
|
231
|
+
kind: "addArc",
|
|
232
|
+
center: pointOption(center, "--add-arc"),
|
|
233
|
+
radius: numberOption(radius, "--add-arc radius"),
|
|
234
|
+
startAngleDegrees: numberOption(start, "--add-arc start angle"),
|
|
235
|
+
endAngleDegrees: numberOption(end, "--add-arc end angle"),
|
|
236
|
+
...common,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
if (options.addText !== undefined) {
|
|
240
|
+
operations.push({
|
|
241
|
+
kind: "addText",
|
|
242
|
+
text: options.addText,
|
|
243
|
+
at: pointOption(options.at, "--at"),
|
|
244
|
+
height: options.height
|
|
245
|
+
? numberOption(options.height, "--height")
|
|
246
|
+
: undefined,
|
|
247
|
+
rotationDegrees: options.angle
|
|
248
|
+
? numberOption(options.angle, "--angle")
|
|
249
|
+
: undefined,
|
|
250
|
+
...common,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
if (options.addMtext !== undefined) {
|
|
254
|
+
operations.push({
|
|
255
|
+
kind: "addMText",
|
|
256
|
+
text: options.addMtext,
|
|
257
|
+
at: pointOption(options.at, "--at"),
|
|
258
|
+
height: options.height
|
|
259
|
+
? numberOption(options.height, "--height")
|
|
260
|
+
: undefined,
|
|
261
|
+
width: options.width ? numberOption(options.width, "--width") : undefined,
|
|
262
|
+
rotationDegrees: options.angle
|
|
263
|
+
? numberOption(options.angle, "--angle")
|
|
264
|
+
: undefined,
|
|
265
|
+
...common,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (options.points !== undefined) {
|
|
269
|
+
operations.push({
|
|
270
|
+
kind: "addPolyline",
|
|
271
|
+
points: pointsOption(options.points, "--points"),
|
|
272
|
+
closed: options.closed,
|
|
273
|
+
...common,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return operations;
|
|
277
|
+
}
|
|
4
278
|
export async function edit(file, options) {
|
|
5
279
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
280
|
+
const operations = acadOperations(options);
|
|
281
|
+
if (operations.length === 0) {
|
|
282
|
+
throw userError("No edit operation specified. Use --set-text, --set-layer, --move, --delete, or an add-* operation.", "MISSING_EDIT_OPERATION");
|
|
8
283
|
}
|
|
9
|
-
const result =
|
|
284
|
+
const result = editWithAcadTs({
|
|
10
285
|
input: file,
|
|
11
286
|
output: options.output ?? file,
|
|
12
|
-
|
|
287
|
+
operations,
|
|
13
288
|
overwrite: options.overwrite,
|
|
14
|
-
toolDir: options.toolDir,
|
|
15
289
|
});
|
|
16
290
|
output(options, {
|
|
17
291
|
json: () => ({ success: true, ...result }),
|
|
18
|
-
human: () => success(`Edited ${result.output} with
|
|
292
|
+
human: () => success(`Edited ${result.output} with acad-ts`),
|
|
19
293
|
});
|
|
20
294
|
}
|
|
21
295
|
catch (err) {
|
package/dist/commands/json.js
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { queryDrawing, querySchema, querySchemaTables } from "../core/query.js";
|
|
3
|
+
import { output } from "../utils/output.js";
|
|
4
|
+
import { drawingFor, handleCommandError, userError } from "./shared.js";
|
|
5
|
+
function querySql(options) {
|
|
6
|
+
if (options.schema)
|
|
7
|
+
return "";
|
|
8
|
+
if (options.sql && options.file) {
|
|
9
|
+
throw userError("Use either --sql or --file, not both.", "QUERY_SOURCE_CONFLICT");
|
|
10
|
+
}
|
|
11
|
+
if (options.sql)
|
|
12
|
+
return options.sql;
|
|
13
|
+
if (options.file)
|
|
14
|
+
return readFileSync(options.file, "utf8");
|
|
15
|
+
throw userError("Provide --sql <query>, --file <path>, or --schema.", "MISSING_QUERY");
|
|
16
|
+
}
|
|
17
|
+
function printRows(rows) {
|
|
18
|
+
for (const row of rows) {
|
|
19
|
+
console.log(Object.values(row)
|
|
20
|
+
.map((value) => value ?? "")
|
|
21
|
+
.join("\t"));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function query(file, options) {
|
|
25
|
+
try {
|
|
26
|
+
if (options.schema) {
|
|
27
|
+
output(options, {
|
|
28
|
+
json: () => ({ tables: querySchemaTables() }),
|
|
29
|
+
human: () => console.log(querySchema()),
|
|
30
|
+
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const sql = querySql(options);
|
|
34
|
+
const doc = await drawingFor(file, options).document();
|
|
35
|
+
const result = await queryDrawing(doc, sql);
|
|
36
|
+
output(options, {
|
|
37
|
+
json: () => result,
|
|
38
|
+
human: () => printRows(result.rows),
|
|
39
|
+
quiet: () => console.log(String(result.rows.length)),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
handleCommandError(err);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -4,7 +4,6 @@ import type { DrawingReader } from "../types.js";
|
|
|
4
4
|
import type { OutputOptions } from "../utils/output.js";
|
|
5
5
|
export interface DrawingCommandOptions extends OutputOptions {
|
|
6
6
|
reader?: DrawingReader;
|
|
7
|
-
toolDir?: string;
|
|
8
7
|
}
|
|
9
8
|
export interface OutputFileOptions extends OutputOptions {
|
|
10
9
|
output?: string;
|
package/dist/commands/shared.js
CHANGED
package/dist/commands/svg.js
CHANGED
package/dist/commands/view.d.ts
CHANGED
package/dist/commands/view.js
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { renderSvgWithAcadTs } from "../core/acad-view.js";
|
|
2
2
|
import { handleCommandError, writeCommandOutput } from "./shared.js";
|
|
3
3
|
export async function view(file, options) {
|
|
4
4
|
try {
|
|
5
|
-
const result =
|
|
5
|
+
const result = renderSvgWithAcadTs(file);
|
|
6
6
|
const svg = result.svg;
|
|
7
|
-
const tool = result.tool;
|
|
8
7
|
if (options.output) {
|
|
9
8
|
writeCommandOutput(options, svg, () => ({
|
|
10
9
|
success: true,
|
|
11
10
|
file: options.output,
|
|
12
|
-
backend: "
|
|
13
|
-
|
|
14
|
-
}), `Wrote ${options.output} with ${tool}`);
|
|
11
|
+
backend: "acad-ts",
|
|
12
|
+
}), `Wrote ${options.output} with acad-ts`);
|
|
15
13
|
return;
|
|
16
14
|
}
|
|
17
15
|
if (options.json) {
|
|
18
|
-
console.log(JSON.stringify({ backend: "
|
|
16
|
+
console.log(JSON.stringify({ backend: "acad-ts", svg }, null, 2));
|
|
19
17
|
}
|
|
20
18
|
else {
|
|
21
19
|
console.log(svg.trimEnd());
|