Skip to content

Commit 6439a0f

Browse files
authored
feat(data-model): OLE2FRAME geometry, ByBlock=ACI7, and native DXF default registration (#160)
1 parent 305e5ff commit 6439a0f

17 files changed

Lines changed: 354 additions & 172 deletions

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ lib
77
tmp
88
tsconfig.tsbuildinfo
99

10-
# mlightcad private parser and converter packages
11-
mlightcad-parser
12-
mlightcad-converter
10+
# Private package — clone locally; never commit
11+
packages/dwg-converter
1312

1413
# dependencies
1514
node_modules

README.md

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ To support reading both DXF and DWG files (and potentially other formats in the
2222

2323
- Each file type (e.g., DXF, DWG) is associated with a converter class that knows how to parse and import that file format into the drawing database.
2424
- The `AcDbDatabaseConverterManager` maintains a registry of these converters, allowing you to register or unregister converters for specific file types at runtime.
25-
- **DXF is registered by default.** Importing `@mlightcad/data-model` registers the built-in MIT `AcDbNativeDxfConverter`. You only need to register a DXF converter if you want to replace that default (for example with `@mlightcad/dxf-json-converter`).
25+
- **DXF is registered by default.** `AcDbDatabaseConverterManager` registers the built-in MIT `AcDbNativeDxfConverter` when the singleton is created. You only need to register a DXF converter if you want to replace that default.
2626
- **DWG is not registered by default.** Register a DWG converter (typically `@mlightcad/libredwg-converter`) before calling `AcDbDatabase.read()` on DWG files.
2727

28-
`@mlightcad/dxf-json-converter` and `@mlightcad/libredwg-converter` are designed to run their parsers in a Web Worker. That is a deliberate licensing choice: their upstream parsers are copyleft (GPL/LGPL), so keeping them in a separate worker bundle helps isolate that code from the main application. The built-in `AcDbNativeDxfConverter` does **not** need a worker — it is MIT-licensed and runs on the main thread.
28+
`@mlightcad/libredwg-converter` runs its LibreDWG parser in a Web Worker. That is a deliberate licensing choice: the upstream parser is copyleft (GPL), so keeping it in a separate worker bundle helps isolate that code from the main application. The built-in `AcDbNativeDxfConverter` does **not** need a worker — it is MIT-licensed and runs on the main thread.
29+
30+
Deprecated GPL converters (`@mlightcad/dxf-json-converter`, `@mlightcad/libdxfrw-converter`) have moved to the separate [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) repository and are no longer documented here.
2931

3032
### Registering Converters
3133

32-
DXF works out of the box. Register a DWG converter before reading DWG files. Optionally replace the default DXF converter:
34+
DXF works out of the box. Register a DWG converter before reading DWG files:
3335

3436
```ts
3537
import {
@@ -38,15 +40,6 @@ import {
3840
} from '@mlightcad/data-model'
3941
import { AcDbLibreDwgConverter } from '@mlightcad/libredwg-converter'
4042

41-
// Optional: replace the default MIT AcDbNativeDxfConverter with the GPL worker-based parser
42-
// import { AcDbDxfConverter } from '@mlightcad/dxf-json-converter'
43-
// const dxfConverter = new AcDbDxfConverter({
44-
// convertByEntityType: false,
45-
// useWorker: true,
46-
// parserWorkerUrl: './assets/dxf-parser-worker.js'
47-
// })
48-
// AcDbDatabaseConverterManager.instance.register(AcDbFileType.DXF, dxfConverter)
49-
5043
// DWG converter (copyleft parser is loaded in a separate Web Worker for license isolation)
5144
const dwgConverter = new AcDbLibreDwgConverter({
5245
convertByEntityType: false,
@@ -59,7 +52,7 @@ AcDbDatabaseConverterManager.instance.register(
5952
)
6053
```
6154

62-
Deploy `libredwg-parser-worker.js` (and `dxf-parser-worker.js` only if you use `dxf-json-converter`) from each converter package's `dist/` folder to a public URL (see [example vite config](./packages/example/vite.config.ts)).
55+
Deploy `libredwg-parser-worker.js` from `@mlightcad/libredwg-converter`'s `dist/` folder to a public URL (see [example vite config](./packages/example/vite.config.ts)).
6356

6457
### Unregistering a Converter
6558

@@ -127,30 +120,17 @@ This design ensures the system is open for extension and can easily adapt to new
127120

128121
AutoCAD holds an absolute dominant position in the 2D CAD field. A large number of vertical applications and third-party plugins have been developed based on AutoCAD ObjectARX, and there are many software engineers familiar with AutoCAD ObjectARX. Therefore, this project mimics the architecture of AutoCAD ObjectARX and adopts similar API interfaces to AutoCAD ObjectARX.
129122

130-
### libdxfrw-converter (DWG file support)
131-
132-
DWG support via libdxfrw lives in the separate [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) monorepo (`@mlightcad/libdxfrw-converter`). It is powered by libdxfrw compiled to WebAssembly. Note: this converter does **not** provide worker isolation — GPL libdxfrw code runs on the main thread.
133-
134123
### libredwg-converter (DWG file support)
135124

136125
This module provides a DWG file converter for the RealDWG-Web ecosystem, enabling reading and conversion of DWG files into the drawing database. It is powered by the LibreDWG library compiled to WebAssembly and is designed to be registered with the converter manager for DWG file support.
137126

138127
DWG parsing is provided through a dedicated Web Worker bundle (`libredwg-parser-worker.js`). Worker-only usage is a licensing choice, not a platform constraint: it keeps the copyleft LibreDWG parser separate from the main application bundle so that MIT-licensed apps can integrate DWG support more safely.
139128

140-
### AcDbNativeDxfConverter vs dxf-json-converter (DXF file support)
141-
142-
`@mlightcad/data-model` ships a built-in DXF converter, `AcDbNativeDxfConverter`. It is the **recommended** way to read DXF files. The optional GPL alternative `@mlightcad/dxf-json-converter` lives in [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter).
129+
### AcDbNativeDxfConverter (DXF file support)
143130

144-
| | `AcDbNativeDxfConverter` (built-in) | `@mlightcad/dxf-json-converter` |
145-
| --- | --- | --- |
146-
| Where it lives | `@mlightcad/data-model` | [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) |
147-
| License | MIT | GPL-3.0 (via `@mlightcad/dxf-json`) |
148-
| Default registration | Yes — registered when you import `data-model` | No — must `register()` yourself (replaces the default) |
149-
| Execution | Main thread, streaming DXF pairs into the database | Web Worker + ParsedDxf JSON intermediate |
150-
| Worker / assets | Not required | Requires `dxf-parser-worker.js` |
151-
| Typical use | New apps; prefer speed and MIT-only DXF | Legacy setups or apps that already depend on `dxf-json` |
131+
`@mlightcad/data-model` ships a built-in MIT DXF converter, `AcDbNativeDxfConverter`. It is registered by default when `AcDbDatabaseConverterManager` is created, streams DXF pairs into the database on the main thread, and requires no Web Worker or extra parser assets.
152132

153-
`dxf-json-converter` remains available for compatibility, but new code should use the built-in `AcDbNativeDxfConverter` unless you have a specific reason to keep the GPL worker-based path.
133+
Deprecated GPL alternatives (`@mlightcad/dxf-json-converter`, `@mlightcad/libdxfrw-converter`) live in the separate [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) repository.
154134

155135
## geometry-engine (AcGe classes in AutoCAD ObjectARX)
156136

@@ -207,6 +187,40 @@ The key classes in this module are as follows.
207187
- AcGiRenderer: Interface used to render entities to drawble objects.
208188
- ...
209189

190+
## Private packages (maintainers)
191+
192+
`@mlightcad/dwg-converter` is **not** part of this public repository and is never
193+
built or published by public GitHub CI. Maintainers who need it locally can clone
194+
it into the workspace:
195+
196+
```bash
197+
pnpm setup:private
198+
pnpm install
199+
pnpm --filter @mlightcad/dwg-converter build
200+
```
201+
202+
Override the clone URL with `DWG_CONVERTER_REPO_URL` if needed. The directory
203+
`packages/dwg-converter` is gitignored so it cannot be committed here. Local
204+
`pnpm install` may temporarily add that package to `pnpm-lock.yaml`**do not
205+
commit** those lockfile changes; public CI must keep a lockfile without it.
206+
207+
**Customers** install the same package from GitHub Packages (not public npm). Do
208+
not point the whole `@mlightcad` scope at GitHub Packages—only authenticate, then
209+
install with an explicit registry:
210+
211+
```ini
212+
# .npmrc
213+
registry=https://registry.npmjs.org/
214+
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
215+
```
216+
217+
```bash
218+
pnpm add @mlightcad/data-model
219+
pnpm add @mlightcad/dwg-converter --registry https://npm.pkg.github.com
220+
```
221+
222+
Publishing `@mlightcad/dwg-converter` happens only from its private repository CI.
223+
210224
## Contributing
211225

212226
Contributions are welcome! Please open issues or pull requests for bug fixes, new features, or suggestions. For bug reports, providing a link to the problematic drawing will help in reproducing and fixing the issue.
@@ -215,61 +229,52 @@ Contributions are welcome! Please open issues or pull requests for bug fixes, ne
215229

216230
This project is generally licensed under the [MIT License](LICENSE). However, this license does not apply to `@mlightcad/libredwg-converter` (GPL-3.0) in this repository.
217231

218-
The GPL converters `@mlightcad/dxf-json-converter` and `@mlightcad/libdxfrw-converter` live in the separate [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) repository. Please refer to each package's license for details.
232+
Deprecated GPL converters (`@mlightcad/dxf-json-converter`, `@mlightcad/libdxfrw-converter`) live in the separate [dwg-dxf-converter](https://github.com/mlightcad/dwg-dxf-converter) repository. Please refer to that repository and each package's license for details.
219233

220234
### Prefer the built-in DXF converter
221235

222-
For DXF files, use the built-in **`AcDbNativeDxfConverter`** in `@mlightcad/data-model` whenever possible:
236+
For DXF files, use the built-in **`AcDbNativeDxfConverter`** in `@mlightcad/data-model`:
223237

224-
- **No GPL license issues for DXF** — it is MIT-licensed and part of the core SDK; you do not need `@mlightcad/dxf-json-converter`.
238+
- **No GPL license issues for DXF** — it is MIT-licensed and part of the core SDK.
225239
- **Faster and simpler** — streams DXF into the database on the main thread with no Web Worker and no extra parser assets.
226-
- **Registered by default**importing `@mlightcad/data-model` is enough to call `AcDbDatabase.read(..., AcDbFileType.DXF)`.
240+
- **Registered by default**accessing `AcDbDatabaseConverterManager` is enough to call `AcDbDatabase.read(..., AcDbFileType.DXF)`.
227241

228-
Reserve `@mlightcad/dxf-json-converter` for legacy apps that already depend on it. For DWG, you still need a separate converter package (prefer `@mlightcad/libredwg-converter` with worker mode).
242+
For DWG, register a separate converter package (prefer `@mlightcad/libredwg-converter` with worker mode).
229243

230244
### GPL copyleft and Web Worker isolation
231245

232246
The MIT-licensed core (`@mlightcad/data-model`, `@mlightcad/geometry-engine`, `@mlightcad/graphic-interface`, `@mlightcad/common`) does **not** depend on any GPL parser. Reading DXF through `AcDbNativeDxfConverter` stays entirely under MIT.
233247

234248
GPL copyleft therefore does **not** automatically apply to your application merely because you use the RealDWG-Web SDK—**provided that any GPL parser code you do use runs only inside separate Web Worker bundles**.
235249

236-
If you still use `@mlightcad/dxf-json-converter` and/or `@mlightcad/libredwg-converter`, the recommended integration is:
250+
For DWG via `@mlightcad/libredwg-converter`, the recommended integration is:
237251

238252
```ts
239-
// Optional DXF replacement (not needed if you keep AcDbNativeDxfConverter)
240-
const dxfConverter = new AcDbDxfConverter({
241-
useWorker: true,
242-
parserWorkerUrl: './assets/dxf-parser-worker.js'
243-
})
244-
245253
const dwgConverter = new AcDbLibreDwgConverter({
246254
useWorker: true,
247255
parserWorkerUrl: './assets/libredwg-parser-worker.js'
248256
})
249257
```
250258

251-
Deploy the worker scripts (`dxf-parser-worker.js` if used, `libredwg-parser-worker.js`) from each converter package's `dist/` folder as static assets (see [example vite config](./packages/example/vite.config.ts)).
259+
Deploy `libredwg-parser-worker.js` from `@mlightcad/libredwg-converter`'s `dist/` folder as a static asset (see [example vite config](./packages/example/vite.config.ts)).
252260

253261
**How this limits copyleft propagation**
254262

255263
| Component | License | Worker isolation |
256264
| --- | --- | --- |
257265
| Core SDK (`data-model`, including `AcDbNativeDxfConverter`) | MIT | N/A — no GPL dependency |
258-
| `dxf-json-converter` / `libredwg-converter` (main bundle) | GPL | Orchestrates parsing; GPL parser execution stays in worker |
259-
| `dxf-parser-worker.js` / `libredwg-parser-worker.js` | GPL | Separate bundle; loaded at runtime; communicates via `postMessage` |
260-
| `libdxfrw-converter` | GPL-2.0 | **No** worker isolation — parser runs on the main thread |
266+
| `libredwg-converter` (main bundle) | GPL | Orchestrates parsing; GPL parser execution stays in worker |
267+
| `libredwg-parser-worker.js` | GPL | Separate bundle; loaded at runtime; communicates via `postMessage` |
261268

262-
When `useWorker: true` is configured and the worker scripts are deployed separately:
269+
When `useWorker: true` is configured and the worker script is deployed separately:
263270

264-
1. GPL parser code is bundled only into the worker scripts, not into your main application bundle.
271+
1. GPL parser code is bundled only into the worker script, not into your main application bundle.
265272
2. The worker and main thread exchange data through `postMessage` (file bytes in, parsed JSON model out)—a runtime boundary rather than static linking of GPL code into the MIT core.
266-
3. Your MIT-licensed application code can stay under MIT, while the GPL worker bundles remain separate distributable components that must comply with GPL on their own (source availability, license notice, etc.).
273+
3. Your MIT-licensed application code can stay under MIT, while the GPL worker bundle remains a separate distributable component that must comply with GPL on its own (source availability, license notice, etc.).
267274

268275
**Important caveats**
269276

270277
- **Prefer `AcDbNativeDxfConverter` for DXF** to avoid GPL entirely for that format.
271278
- **Worker scripts are still GPL.** You must satisfy GPL obligations for those bundles (e.g., provide corresponding source and license notices when you distribute them).
272-
- **DXF via `dxf-json-converter` on the main thread does not isolate GPL code.** That package can parse on the main thread when `useWorker: false`; that mode links GPL parser code into the same JavaScript context as your app. Use `useWorker: true` if you must use it and want worker-based isolation.
273279
- **DWG via LibreDWG is worker-only.** `@mlightcad/libredwg-converter` requires a Web Worker; it cannot run on the main thread.
274-
- **`@mlightcad/libdxfrw-converter` is different.** It does not provide a worker-based parser bundle; using it loads GPL libdxfrw code on the main thread. Prefer `@mlightcad/libredwg-converter` with worker mode if copyleft isolation matters for your deployment.
275280
- **This is an architectural description, not legal advice.** Interpretation of GPL in browser/Web Worker contexts may vary by jurisdiction and use case. Consult qualified legal counsel for your product if license compliance is critical.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"lint:fix": "nx run-many -t lint:fix",
2525
"publish:package": "pnpm -r publish --access public --no-git-checks",
2626
"release": "node tools/release.mjs",
27+
"setup:private": "node tools/setup-private-packages.mjs",
2728
"sync:versions": "node tools/sync-versions.mjs",
2829
"sync:versions:check": "node tools/sync-versions.mjs --check",
2930
"test": "jest",
@@ -59,7 +60,7 @@
5960
"typedoc": "^0.27.4",
6061
"typescript": "^5.5.2",
6162
"typescript-eslint": "^8.4.0",
62-
"vite": "^6.4.3",
63+
"vite": "6.4.3",
6364
"vite-plugin-strip-comments": "^0.0.10"
6465
},
6566
"lint-staged": {

packages/data-model/__tests__/AcDbDatabaseConverterManager.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@ import {
22
AcDbDatabaseConverterManager,
33
AcDbFileType
44
} from '../src/database/AcDbDatabaseConverterManager'
5+
import { AcDbNativeDxfConverter } from '../src/dxf/AcDbNativeDxfConverter'
56

67
describe('AcDbDatabaseConverterManager', () => {
78
it('creates a singleton instance', () => {
89
const manager = AcDbDatabaseConverterManager.instance
910
expect(AcDbDatabaseConverterManager.createInstance()).toBe(manager)
1011
})
1112

13+
it('registers a native DXF converter by default', () => {
14+
const manager = AcDbDatabaseConverterManager.instance
15+
expect(manager.get(AcDbFileType.DXF)).toBeInstanceOf(AcDbNativeDxfConverter)
16+
})
17+
1218
it('replaces a DXF converter when register is called again', () => {
13-
// Mirrors production: data-model registers AcDbNativeDxfConverter by default,
19+
// Mirrors production: the manager registers AcDbNativeDxfConverter by default,
1420
// then apps may replace it (e.g. with AcDbDxfConverter from dxf-json-converter).
1521
const manager = AcDbDatabaseConverterManager.instance
1622
const nativeDefault = { read: jest.fn(), name: 'native' } as any

packages/data-model/__tests__/AcDbEntity.spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ describe('AcDbEntity.color resolution', () => {
175175
acdbHostApplicationServices().workingDatabase = db
176176
})
177177

178-
it('uses CECOLOR when entity color is explicitly ByBlock', () => {
178+
it('resolves ByBlock without INSERT owner to ACI 7 foreground, not CECOLOR', () => {
179179
addLayerWithColor('0', 0x101010)
180180
db.clayer = '0'
181181
db.cecolor = new AcCmColor().setRGBValue(0x336699)
@@ -188,10 +188,12 @@ describe('AcDbEntity.color resolution', () => {
188188
line.color.setByBlock()
189189

190190
expect(line.color.isByBlock).toBe(true)
191-
expect(line.resolvedColor.RGB).toBe(0x336699)
191+
expect(line.resolvedColor.isForeground).toBe(true)
192+
expect(line.resolvedColor.colorIndex).toBe(7)
193+
expect(line.resolvedColor.RGB).not.toBe(0x336699)
192194
})
193195

194-
it('resolves ByBlock through current layer when CECOLOR is ByLayer', () => {
196+
it('keeps ByBlock as foreground even when CECOLOR is ByLayer', () => {
195197
addLayerWithColor('ENTITY_LAYER', 0x00ff00)
196198
addLayerWithColor('CURRENT_LAYER', 0x112233)
197199
db.clayer = 'CURRENT_LAYER'
@@ -204,7 +206,9 @@ describe('AcDbEntity.color resolution', () => {
204206
line.layer = 'ENTITY_LAYER'
205207
line.color.setByBlock()
206208

207-
expect(line.resolvedColor.RGB).toBe(0x112233)
209+
expect(line.resolvedColor.isForeground).toBe(true)
210+
expect(line.resolvedColor.colorIndex).toBe(7)
211+
expect(line.resolvedColor.RGB).not.toBe(0x112233)
208212
})
209213

210214
it('resolves ByLayer against the entity layer color', () => {

0 commit comments

Comments
 (0)