@animus-ui/extract 0.1.0 → 0.1.1

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.
Binary file
Binary file
Binary file
@@ -0,0 +1,104 @@
1
+ /* auto-generated by NAPI-RS */
2
+ /* eslint-disable */
3
+ export declare class ExtractEngine {
4
+ constructor(options?: EngineOptions | undefined | null)
5
+ /**
6
+ * Parse-once fact extraction over the file set; facts and sources are
7
+ * RETAINED on the handle for subsequent per-file calls. Returns the
8
+ * fact manifest (files + parseCount) as JSON.
9
+ */
10
+ analyze(fileEntriesJson: string): string
11
+ /** Reset all retained build state. */
12
+ clearCache(): void
13
+ get parseCount(): number
14
+ /**
15
+ * Per-file transformation from retained source + facts (no-config
16
+ * subset: variants/compounds/states; system/custom payloads need the
17
+ * row-07 config inputs and FAIL LOUD). Returns {code, hasComponents}
18
+ * JSON. Import decisions come from surviving chain/payload metadata;
19
+ * consumed-import stripping and directive handling are the ported v1
20
+ * semantics.
21
+ */
22
+ transformFile(path: string): string
23
+ }
24
+
25
+ /**
26
+ * Chain discovery over a file set: parse once per file (parallel), walk
27
+ * every stored AST, return owned facts. The v2 spine's first real surface;
28
+ * consumed by the parity comparison tooling.
29
+ */
30
+ export declare function discoverChains(fileEntriesJson: string): string
31
+
32
+ /**
33
+ * Engine options (row 07 Task 07.3 — replaces the RF-53 hardcodes).
34
+ * All fields optional; absent = v1 defaults.
35
+ */
36
+ export interface EngineOptions {
37
+ /** Class-identity prefix (v1 default "animus"). */
38
+ prefix?: string
39
+ /** Runtime import source (v1 default "@animus-ui/system"). */
40
+ runtimeImport?: string
41
+ /** CSS virtual module id (v1 default "virtual:animus/styles.css"). */
42
+ cssModuleId?: string
43
+ /**
44
+ * System-props virtual module id (v1 EmitterConfig default
45
+ * "virtual:animus/system-props").
46
+ */
47
+ systemPropsModuleId?: string
48
+ /** Flat theme scales JSON (v1 analyzeProject `theme_json`). */
49
+ themeJson?: string
50
+ /** Token-alias variable map JSON (v1 `variable_map_json`). */
51
+ variableMapJson?: string
52
+ /** Contextual vars JSON (v1 `contextual_vars_json`). */
53
+ contextualVarsJson?: string
54
+ /** Prop config map JSON (v1 `config_json`). */
55
+ configJson?: string
56
+ /** Group registry JSON (v1 `group_registry_json`). */
57
+ groupRegistryJson?: string
58
+ /** Selector aliases JSON (v1 `selector_aliases_json`). */
59
+ selectorAliasesJson?: string
60
+ /** Global style blocks JSON (v1 `global_style_blocks_json`). */
61
+ globalStyleBlocksJson?: string
62
+ /**
63
+ * Keyframes blocks JSON (v1 `keyframes_blocks_json` — feeds BOTH the
64
+ * global sheet and the static keyframes registry, v1 Phase 2a).
65
+ */
66
+ keyframesJson?: string
67
+ /** Package resolution JSON (v1 `package_resolution_json`). */
68
+ packageResolutionJson?: string
69
+ /** Path aliases JSON (`{aliases: [...]}` wrapper, v1 shape). */
70
+ pathAliasesJson?: string
71
+ /** v1 `dev_mode`: retain all components (skip reconciliation pruning). */
72
+ devMode?: boolean
73
+ }
74
+
75
+ /**
76
+ * Build/probe identity: proves the v2 binary loads and its oxc linkage
77
+ * parses. Consumed by the dual-build verification and the parity harness
78
+ * engine registry.
79
+ */
80
+ export declare function engineVersion(): string
81
+
82
+ /**
83
+ * Full per-file fact extraction (increment 11): chains + eagerly evaluated
84
+ * stages + statics + raw usage facts + compose families — one parse per
85
+ * file. The store (and every AST) is dropped when this call returns; the
86
+ * D4-relevant invariant is that no program() read happens after
87
+ * cross-file facts resolve.
88
+ */
89
+ export declare function extractFacts(fileEntriesJson: string): string
90
+
91
+ export declare function loadSystemModule(systemPath: string, rootDir: string, exportName?: string | undefined | null): NapiSystemConfig
92
+
93
+ export interface NapiSystemConfig {
94
+ propConfig: string
95
+ groupRegistry: string
96
+ scalesJson: string
97
+ variableMapJson: string
98
+ variableCss: string
99
+ contextualVarsJson: string
100
+ selectorAliases?: string
101
+ selectorOrder?: string
102
+ globalStyleBlocks?: string
103
+ keyframesBlocks?: string
104
+ }
@@ -0,0 +1,594 @@
1
+ // prettier-ignore
2
+ /* eslint-disable */
3
+ // @ts-nocheck
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ const { readFileSync } = require('fs')
7
+ let nativeBinding = null
8
+ const loadErrors = []
9
+
10
+ const isMusl = () => {
11
+ let musl = false
12
+ if (process.platform === 'linux') {
13
+ musl = isMuslFromFilesystem()
14
+ if (musl === null) {
15
+ musl = isMuslFromReport()
16
+ }
17
+ if (musl === null) {
18
+ musl = isMuslFromChildProcess()
19
+ }
20
+ }
21
+ return musl
22
+ }
23
+
24
+ const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')
25
+
26
+ const isMuslFromFilesystem = () => {
27
+ try {
28
+ return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl')
29
+ } catch {
30
+ return null
31
+ }
32
+ }
33
+
34
+ const isMuslFromReport = () => {
35
+ let report = null
36
+ if (process.report && typeof process.report.getReport === 'function') {
37
+ process.report.excludeNetwork = true
38
+ report = process.report.getReport()
39
+ }
40
+ if (!report) {
41
+ return null
42
+ }
43
+ if (report.header && report.header.glibcVersionRuntime) {
44
+ return false
45
+ }
46
+ if (Array.isArray(report.sharedObjects)) {
47
+ if (report.sharedObjects.some(isFileMusl)) {
48
+ return true
49
+ }
50
+ }
51
+ return false
52
+ }
53
+
54
+ const isMuslFromChildProcess = () => {
55
+ try {
56
+ return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
57
+ } catch (e) {
58
+ // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false
59
+ return false
60
+ }
61
+ }
62
+
63
+ function requireNative() {
64
+ if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
65
+ try {
66
+ return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
67
+ } catch (err) {
68
+ loadErrors.push(err)
69
+ }
70
+ } else if (process.platform === 'android') {
71
+ if (process.arch === 'arm64') {
72
+ try {
73
+ return require('./animus-extract-v2.android-arm64.node')
74
+ } catch (e) {
75
+ loadErrors.push(e)
76
+ }
77
+ try {
78
+ const binding = require('animus-extract-v2-binding-android-arm64')
79
+ const bindingPackageVersion = require('animus-extract-v2-binding-android-arm64/package.json').version
80
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
81
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
82
+ }
83
+ return binding
84
+ } catch (e) {
85
+ loadErrors.push(e)
86
+ }
87
+ } else if (process.arch === 'arm') {
88
+ try {
89
+ return require('./animus-extract-v2.android-arm-eabi.node')
90
+ } catch (e) {
91
+ loadErrors.push(e)
92
+ }
93
+ try {
94
+ const binding = require('animus-extract-v2-binding-android-arm-eabi')
95
+ const bindingPackageVersion = require('animus-extract-v2-binding-android-arm-eabi/package.json').version
96
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
97
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
98
+ }
99
+ return binding
100
+ } catch (e) {
101
+ loadErrors.push(e)
102
+ }
103
+ } else {
104
+ loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`))
105
+ }
106
+ } else if (process.platform === 'win32') {
107
+ if (process.arch === 'x64') {
108
+ if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
109
+ try {
110
+ return require('./animus-extract-v2.win32-x64-gnu.node')
111
+ } catch (e) {
112
+ loadErrors.push(e)
113
+ }
114
+ try {
115
+ const binding = require('animus-extract-v2-binding-win32-x64-gnu')
116
+ const bindingPackageVersion = require('animus-extract-v2-binding-win32-x64-gnu/package.json').version
117
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
118
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
119
+ }
120
+ return binding
121
+ } catch (e) {
122
+ loadErrors.push(e)
123
+ }
124
+ } else {
125
+ try {
126
+ return require('./animus-extract-v2.win32-x64-msvc.node')
127
+ } catch (e) {
128
+ loadErrors.push(e)
129
+ }
130
+ try {
131
+ const binding = require('animus-extract-v2-binding-win32-x64-msvc')
132
+ const bindingPackageVersion = require('animus-extract-v2-binding-win32-x64-msvc/package.json').version
133
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
134
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
135
+ }
136
+ return binding
137
+ } catch (e) {
138
+ loadErrors.push(e)
139
+ }
140
+ }
141
+ } else if (process.arch === 'ia32') {
142
+ try {
143
+ return require('./animus-extract-v2.win32-ia32-msvc.node')
144
+ } catch (e) {
145
+ loadErrors.push(e)
146
+ }
147
+ try {
148
+ const binding = require('animus-extract-v2-binding-win32-ia32-msvc')
149
+ const bindingPackageVersion = require('animus-extract-v2-binding-win32-ia32-msvc/package.json').version
150
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
151
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
152
+ }
153
+ return binding
154
+ } catch (e) {
155
+ loadErrors.push(e)
156
+ }
157
+ } else if (process.arch === 'arm64') {
158
+ try {
159
+ return require('./animus-extract-v2.win32-arm64-msvc.node')
160
+ } catch (e) {
161
+ loadErrors.push(e)
162
+ }
163
+ try {
164
+ const binding = require('animus-extract-v2-binding-win32-arm64-msvc')
165
+ const bindingPackageVersion = require('animus-extract-v2-binding-win32-arm64-msvc/package.json').version
166
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
167
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
168
+ }
169
+ return binding
170
+ } catch (e) {
171
+ loadErrors.push(e)
172
+ }
173
+ } else {
174
+ loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`))
175
+ }
176
+ } else if (process.platform === 'darwin') {
177
+ try {
178
+ return require('./animus-extract-v2.darwin-universal.node')
179
+ } catch (e) {
180
+ loadErrors.push(e)
181
+ }
182
+ try {
183
+ const binding = require('animus-extract-v2-binding-darwin-universal')
184
+ const bindingPackageVersion = require('animus-extract-v2-binding-darwin-universal/package.json').version
185
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
186
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
187
+ }
188
+ return binding
189
+ } catch (e) {
190
+ loadErrors.push(e)
191
+ }
192
+ if (process.arch === 'x64') {
193
+ try {
194
+ return require('./animus-extract-v2.darwin-x64.node')
195
+ } catch (e) {
196
+ loadErrors.push(e)
197
+ }
198
+ try {
199
+ const binding = require('animus-extract-v2-binding-darwin-x64')
200
+ const bindingPackageVersion = require('animus-extract-v2-binding-darwin-x64/package.json').version
201
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
202
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
203
+ }
204
+ return binding
205
+ } catch (e) {
206
+ loadErrors.push(e)
207
+ }
208
+ } else if (process.arch === 'arm64') {
209
+ try {
210
+ return require('./animus-extract-v2.darwin-arm64.node')
211
+ } catch (e) {
212
+ loadErrors.push(e)
213
+ }
214
+ try {
215
+ const binding = require('animus-extract-v2-binding-darwin-arm64')
216
+ const bindingPackageVersion = require('animus-extract-v2-binding-darwin-arm64/package.json').version
217
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
218
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
219
+ }
220
+ return binding
221
+ } catch (e) {
222
+ loadErrors.push(e)
223
+ }
224
+ } else {
225
+ loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`))
226
+ }
227
+ } else if (process.platform === 'freebsd') {
228
+ if (process.arch === 'x64') {
229
+ try {
230
+ return require('./animus-extract-v2.freebsd-x64.node')
231
+ } catch (e) {
232
+ loadErrors.push(e)
233
+ }
234
+ try {
235
+ const binding = require('animus-extract-v2-binding-freebsd-x64')
236
+ const bindingPackageVersion = require('animus-extract-v2-binding-freebsd-x64/package.json').version
237
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
238
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
239
+ }
240
+ return binding
241
+ } catch (e) {
242
+ loadErrors.push(e)
243
+ }
244
+ } else if (process.arch === 'arm64') {
245
+ try {
246
+ return require('./animus-extract-v2.freebsd-arm64.node')
247
+ } catch (e) {
248
+ loadErrors.push(e)
249
+ }
250
+ try {
251
+ const binding = require('animus-extract-v2-binding-freebsd-arm64')
252
+ const bindingPackageVersion = require('animus-extract-v2-binding-freebsd-arm64/package.json').version
253
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
254
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
255
+ }
256
+ return binding
257
+ } catch (e) {
258
+ loadErrors.push(e)
259
+ }
260
+ } else {
261
+ loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`))
262
+ }
263
+ } else if (process.platform === 'linux') {
264
+ if (process.arch === 'x64') {
265
+ if (isMusl()) {
266
+ try {
267
+ return require('./animus-extract-v2.linux-x64-musl.node')
268
+ } catch (e) {
269
+ loadErrors.push(e)
270
+ }
271
+ try {
272
+ const binding = require('animus-extract-v2-binding-linux-x64-musl')
273
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-x64-musl/package.json').version
274
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
275
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
276
+ }
277
+ return binding
278
+ } catch (e) {
279
+ loadErrors.push(e)
280
+ }
281
+ } else {
282
+ try {
283
+ return require('./animus-extract-v2.linux-x64-gnu.node')
284
+ } catch (e) {
285
+ loadErrors.push(e)
286
+ }
287
+ try {
288
+ const binding = require('animus-extract-v2-binding-linux-x64-gnu')
289
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-x64-gnu/package.json').version
290
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
291
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
292
+ }
293
+ return binding
294
+ } catch (e) {
295
+ loadErrors.push(e)
296
+ }
297
+ }
298
+ } else if (process.arch === 'arm64') {
299
+ if (isMusl()) {
300
+ try {
301
+ return require('./animus-extract-v2.linux-arm64-musl.node')
302
+ } catch (e) {
303
+ loadErrors.push(e)
304
+ }
305
+ try {
306
+ const binding = require('animus-extract-v2-binding-linux-arm64-musl')
307
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-arm64-musl/package.json').version
308
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
309
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
310
+ }
311
+ return binding
312
+ } catch (e) {
313
+ loadErrors.push(e)
314
+ }
315
+ } else {
316
+ try {
317
+ return require('./animus-extract-v2.linux-arm64-gnu.node')
318
+ } catch (e) {
319
+ loadErrors.push(e)
320
+ }
321
+ try {
322
+ const binding = require('animus-extract-v2-binding-linux-arm64-gnu')
323
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-arm64-gnu/package.json').version
324
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
325
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
326
+ }
327
+ return binding
328
+ } catch (e) {
329
+ loadErrors.push(e)
330
+ }
331
+ }
332
+ } else if (process.arch === 'arm') {
333
+ if (isMusl()) {
334
+ try {
335
+ return require('./animus-extract-v2.linux-arm-musleabihf.node')
336
+ } catch (e) {
337
+ loadErrors.push(e)
338
+ }
339
+ try {
340
+ const binding = require('animus-extract-v2-binding-linux-arm-musleabihf')
341
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-arm-musleabihf/package.json').version
342
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
343
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
344
+ }
345
+ return binding
346
+ } catch (e) {
347
+ loadErrors.push(e)
348
+ }
349
+ } else {
350
+ try {
351
+ return require('./animus-extract-v2.linux-arm-gnueabihf.node')
352
+ } catch (e) {
353
+ loadErrors.push(e)
354
+ }
355
+ try {
356
+ const binding = require('animus-extract-v2-binding-linux-arm-gnueabihf')
357
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-arm-gnueabihf/package.json').version
358
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
359
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
360
+ }
361
+ return binding
362
+ } catch (e) {
363
+ loadErrors.push(e)
364
+ }
365
+ }
366
+ } else if (process.arch === 'loong64') {
367
+ if (isMusl()) {
368
+ try {
369
+ return require('./animus-extract-v2.linux-loong64-musl.node')
370
+ } catch (e) {
371
+ loadErrors.push(e)
372
+ }
373
+ try {
374
+ const binding = require('animus-extract-v2-binding-linux-loong64-musl')
375
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-loong64-musl/package.json').version
376
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
377
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
378
+ }
379
+ return binding
380
+ } catch (e) {
381
+ loadErrors.push(e)
382
+ }
383
+ } else {
384
+ try {
385
+ return require('./animus-extract-v2.linux-loong64-gnu.node')
386
+ } catch (e) {
387
+ loadErrors.push(e)
388
+ }
389
+ try {
390
+ const binding = require('animus-extract-v2-binding-linux-loong64-gnu')
391
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-loong64-gnu/package.json').version
392
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
393
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
394
+ }
395
+ return binding
396
+ } catch (e) {
397
+ loadErrors.push(e)
398
+ }
399
+ }
400
+ } else if (process.arch === 'riscv64') {
401
+ if (isMusl()) {
402
+ try {
403
+ return require('./animus-extract-v2.linux-riscv64-musl.node')
404
+ } catch (e) {
405
+ loadErrors.push(e)
406
+ }
407
+ try {
408
+ const binding = require('animus-extract-v2-binding-linux-riscv64-musl')
409
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-riscv64-musl/package.json').version
410
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
411
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
412
+ }
413
+ return binding
414
+ } catch (e) {
415
+ loadErrors.push(e)
416
+ }
417
+ } else {
418
+ try {
419
+ return require('./animus-extract-v2.linux-riscv64-gnu.node')
420
+ } catch (e) {
421
+ loadErrors.push(e)
422
+ }
423
+ try {
424
+ const binding = require('animus-extract-v2-binding-linux-riscv64-gnu')
425
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-riscv64-gnu/package.json').version
426
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
427
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
428
+ }
429
+ return binding
430
+ } catch (e) {
431
+ loadErrors.push(e)
432
+ }
433
+ }
434
+ } else if (process.arch === 'ppc64') {
435
+ try {
436
+ return require('./animus-extract-v2.linux-ppc64-gnu.node')
437
+ } catch (e) {
438
+ loadErrors.push(e)
439
+ }
440
+ try {
441
+ const binding = require('animus-extract-v2-binding-linux-ppc64-gnu')
442
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-ppc64-gnu/package.json').version
443
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
444
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
445
+ }
446
+ return binding
447
+ } catch (e) {
448
+ loadErrors.push(e)
449
+ }
450
+ } else if (process.arch === 's390x') {
451
+ try {
452
+ return require('./animus-extract-v2.linux-s390x-gnu.node')
453
+ } catch (e) {
454
+ loadErrors.push(e)
455
+ }
456
+ try {
457
+ const binding = require('animus-extract-v2-binding-linux-s390x-gnu')
458
+ const bindingPackageVersion = require('animus-extract-v2-binding-linux-s390x-gnu/package.json').version
459
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
460
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
461
+ }
462
+ return binding
463
+ } catch (e) {
464
+ loadErrors.push(e)
465
+ }
466
+ } else {
467
+ loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`))
468
+ }
469
+ } else if (process.platform === 'openharmony') {
470
+ if (process.arch === 'arm64') {
471
+ try {
472
+ return require('./animus-extract-v2.openharmony-arm64.node')
473
+ } catch (e) {
474
+ loadErrors.push(e)
475
+ }
476
+ try {
477
+ const binding = require('animus-extract-v2-binding-openharmony-arm64')
478
+ const bindingPackageVersion = require('animus-extract-v2-binding-openharmony-arm64/package.json').version
479
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
480
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
481
+ }
482
+ return binding
483
+ } catch (e) {
484
+ loadErrors.push(e)
485
+ }
486
+ } else if (process.arch === 'x64') {
487
+ try {
488
+ return require('./animus-extract-v2.openharmony-x64.node')
489
+ } catch (e) {
490
+ loadErrors.push(e)
491
+ }
492
+ try {
493
+ const binding = require('animus-extract-v2-binding-openharmony-x64')
494
+ const bindingPackageVersion = require('animus-extract-v2-binding-openharmony-x64/package.json').version
495
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
496
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
497
+ }
498
+ return binding
499
+ } catch (e) {
500
+ loadErrors.push(e)
501
+ }
502
+ } else if (process.arch === 'arm') {
503
+ try {
504
+ return require('./animus-extract-v2.openharmony-arm.node')
505
+ } catch (e) {
506
+ loadErrors.push(e)
507
+ }
508
+ try {
509
+ const binding = require('animus-extract-v2-binding-openharmony-arm')
510
+ const bindingPackageVersion = require('animus-extract-v2-binding-openharmony-arm/package.json').version
511
+ if (bindingPackageVersion !== '0.0.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
512
+ throw new Error(`Native binding package version mismatch, expected 0.0.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
513
+ }
514
+ return binding
515
+ } catch (e) {
516
+ loadErrors.push(e)
517
+ }
518
+ } else {
519
+ loadErrors.push(new Error(`Unsupported architecture on OpenHarmony: ${process.arch}`))
520
+ }
521
+ } else {
522
+ loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`))
523
+ }
524
+ }
525
+
526
+ nativeBinding = requireNative()
527
+
528
+ // NAPI_RS_FORCE_WASI is a tri-state flag:
529
+ // unset / any other value → native binding preferred, WASI is only a fallback
530
+ // 'true' → force WASI fallback even if native loaded
531
+ // 'error' → force WASI and throw if no WASI binding is found
532
+ // Treating any non-empty string as truthy (the historical behavior) meant
533
+ // NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
534
+ // the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
535
+ const forceWasi =
536
+ process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'
537
+
538
+ if (!nativeBinding || forceWasi) {
539
+ let wasiBinding = null
540
+ let wasiBindingError = null
541
+ try {
542
+ wasiBinding = require('./animus-extract-v2.wasi.cjs')
543
+ nativeBinding = wasiBinding
544
+ } catch (err) {
545
+ if (forceWasi) {
546
+ wasiBindingError = err
547
+ }
548
+ }
549
+ if (!nativeBinding || forceWasi) {
550
+ try {
551
+ wasiBinding = require('animus-extract-v2-binding-wasm32-wasi')
552
+ nativeBinding = wasiBinding
553
+ } catch (err) {
554
+ if (forceWasi) {
555
+ if (!wasiBindingError) {
556
+ wasiBindingError = err
557
+ } else {
558
+ wasiBindingError.cause = err
559
+ }
560
+ loadErrors.push(err)
561
+ }
562
+ }
563
+ }
564
+ if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) {
565
+ const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error')
566
+ error.cause = wasiBindingError
567
+ throw error
568
+ }
569
+ }
570
+
571
+ if (!nativeBinding) {
572
+ if (loadErrors.length > 0) {
573
+ const error = new Error(
574
+ `Cannot find native binding. ` +
575
+ `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
576
+ 'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
577
+ )
578
+ // assign instead of the `new Error(message, { cause })` options form,
579
+ // which Node < 16.9 silently ignores
580
+ error.cause = loadErrors.reduce((err, cur) => {
581
+ cur.cause = err
582
+ return cur
583
+ })
584
+ throw error
585
+ }
586
+ throw new Error(`Failed to load native binding`)
587
+ }
588
+
589
+ module.exports = nativeBinding
590
+ module.exports.ExtractEngine = nativeBinding.ExtractEngine
591
+ module.exports.discoverChains = nativeBinding.discoverChains
592
+ module.exports.engineVersion = nativeBinding.engineVersion
593
+ module.exports.extractFacts = nativeBinding.extractFacts
594
+ module.exports.loadSystemModule = nativeBinding.loadSystemModule
package/dist/index.cjs ADDED
@@ -0,0 +1,393 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let fs = require("fs");
3
+ let _animus_ui_properties = require("@animus-ui/properties");
4
+ //#region pipeline/assemble-stylesheet.ts
5
+ /**
6
+ * The 7 Animus cascade layers. Always prefixed with `anm-` to avoid
7
+ * collision with other frameworks' layer names (e.g., Tailwind's `base`).
8
+ */
9
+ const ANIMUS_LAYERS = [
10
+ "anm-global",
11
+ "anm-base",
12
+ "anm-variants",
13
+ "anm-compounds",
14
+ "anm-states",
15
+ "anm-system",
16
+ "anm-custom"
17
+ ];
18
+ /**
19
+ * Build the `@layer` declaration line.
20
+ *
21
+ * When `isCustom` is false (default layers), uses ANIMUS_LAYERS directly.
22
+ * When `isCustom` is true, passes names through as-is — the consumer already
23
+ * wrote the final names including the `anm-` prefixed entries.
24
+ */
25
+ function buildLayerDeclaration(layers, isCustom) {
26
+ return `@layer ${(isCustom ? layers : [...ANIMUS_LAYERS]).join(", ")};\n`;
27
+ }
28
+ /**
29
+ * Validate that a consumer `layers` array contains all 7 Animus layers
30
+ * in the correct relative order. Consumer layers may be interleaved.
31
+ *
32
+ * @throws Error with descriptive message on violation
33
+ */
34
+ function validateLayerOrder(layers) {
35
+ const expected = [...ANIMUS_LAYERS];
36
+ let cursor = 0;
37
+ for (const layer of layers) if (cursor < expected.length && layer === expected[cursor]) cursor++;
38
+ if (cursor < expected.length) {
39
+ const missing = expected.slice(cursor);
40
+ const found = expected.slice(0, cursor);
41
+ if (!expected.every((l) => layers.includes(l))) {
42
+ const absent = expected.filter((l) => !layers.includes(l));
43
+ throw new Error(`[animus-extract] Custom layers missing required layers: ${absent.join(", ")}. All 7 Animus layers must be present: ${expected.join(", ")}`);
44
+ }
45
+ throw new Error(`[animus-extract] Custom layers have wrong order. Found ${found.join(", ")} but then expected ${missing[0]}. Required order: (${expected.join(" < ")}). You may interleave custom layers but must preserve this subsequence.`);
46
+ }
47
+ }
48
+ /**
49
+ * Strip a leading `@layer ...;` declaration line from CSS if present.
50
+ * The Rust crate embeds this in prod-mode output; we strip it so the
51
+ * shared assembler controls placement.
52
+ */
53
+ function stripLeadingLayerDeclaration(css) {
54
+ return css.replace(/^@layer\s+[^;{]+;\s*\n?/, "");
55
+ }
56
+ function assembleStylesheet(options) {
57
+ const hasCustomLayers = !!options.layers;
58
+ const layers = options.layers ?? ANIMUS_LAYERS;
59
+ if (options.layers) validateLayerOrder(options.layers);
60
+ const declaration = buildLayerDeclaration(layers, hasCustomLayers);
61
+ const variables = options.variableCss || "";
62
+ const componentCss = options.componentCss ? stripLeadingLayerDeclaration(options.componentCss) : "";
63
+ const body = [options.globalCss || "", componentCss].filter(Boolean).join("\n");
64
+ if (options.split) return {
65
+ declaration,
66
+ variables,
67
+ body
68
+ };
69
+ return [
70
+ declaration,
71
+ variables,
72
+ body
73
+ ].filter(Boolean).join("\n");
74
+ }
75
+ //#endregion
76
+ //#region pipeline/discover-packages.ts
77
+ /**
78
+ * Extract external DS package names from `includes` declarations in the system file.
79
+ *
80
+ * Supports two forms:
81
+ * - Primary (1.0+): `createSystem({ includes: [identifier, ...] })` constructor arg
82
+ * - Legacy: `.includes([identifier, ...])` chain method (RC migration fallback)
83
+ *
84
+ * For each identifier found, traces back to its import declaration and returns
85
+ * the import specifier. Only packages explicitly declared via `includes` are treated
86
+ * as external DS dependencies.
87
+ *
88
+ * Falls back to empty array if no `includes` declaration is found.
89
+ */
90
+ function extractSystemFilePackages(systemFilePath) {
91
+ let source;
92
+ try {
93
+ source = (0, fs.readFileSync)(systemFilePath, "utf-8");
94
+ } catch {
95
+ return [];
96
+ }
97
+ const identifiers = /* @__PURE__ */ new Set();
98
+ const constructorRegex = /createSystem\s*\(\s*\{[^}]*?\bincludes\s*:\s*\[([^\]]*)\]/gs;
99
+ const chainRegex = /\.includes\s*\(\s*\[([^\]]*)\]\s*\)/gs;
100
+ const collectIdentifiers = (regex) => {
101
+ let match;
102
+ while ((match = regex.exec(source)) !== null) {
103
+ const inner = match[1];
104
+ for (const token of inner.split(",")) {
105
+ const id = token.trim();
106
+ if (id && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(id)) identifiers.add(id);
107
+ }
108
+ }
109
+ };
110
+ collectIdentifiers(constructorRegex);
111
+ collectIdentifiers(chainRegex);
112
+ if (identifiers.size === 0) return [];
113
+ const importMap = /* @__PURE__ */ new Map();
114
+ const importRegex = /^\s*import\s+(?:([a-zA-Z_$][a-zA-Z0-9_$]*)\s*,\s*)?(?:\{([^}]*)\}|([a-zA-Z_$][a-zA-Z0-9_$]*))\s+from\s+['"]([^'"]+)['"]/gm;
115
+ let importMatch;
116
+ while ((importMatch = importRegex.exec(source)) !== null) {
117
+ const [, comboDefault, namedImports, defaultImport, specifier] = importMatch;
118
+ if (comboDefault) importMap.set(comboDefault, specifier);
119
+ if (defaultImport) importMap.set(defaultImport, specifier);
120
+ if (namedImports) for (const binding of namedImports.split(",")) {
121
+ const parts = binding.trim().split(/\s+as\s+/);
122
+ const localName = (parts[1] || parts[0]).trim();
123
+ if (localName) importMap.set(localName, specifier);
124
+ }
125
+ }
126
+ const packages = /* @__PURE__ */ new Set();
127
+ for (const id of identifiers) {
128
+ const specifier = importMap.get(id);
129
+ if (specifier && !specifier.startsWith(".")) {
130
+ const pkgName = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
131
+ packages.add(pkgName);
132
+ }
133
+ }
134
+ return Array.from(packages);
135
+ }
136
+ //#endregion
137
+ //#region pipeline/mdx-preprocessor.ts
138
+ /**
139
+ * MDX source preprocessor for the extraction pipeline.
140
+ *
141
+ * MDX files are first-class consumers of ds-built components but are not
142
+ * directly parseable by OXC (which the scanner uses for .tsx/.jsx). This
143
+ * module compiles MDX sources to scanner-consumable JSX using @mdx-js/mdx.
144
+ *
145
+ * @mdx-js/mdx is declared as `peerDependenciesMeta.optional` on the
146
+ * plugin packages that import this module. The dynamic import with
147
+ * .catch() ensures non-MDX consumers (who configure `extensions` to
148
+ * exclude .mdx) never trigger the resolution — zero install-footprint
149
+ * cost for them.
150
+ *
151
+ * The `DEFAULT_EXTENSIONS` constant is the shared source of truth for
152
+ * both `@animus-ui/vite-plugin` and `@animus-ui/next-plugin`. Each plugin
153
+ * imports it directly; independent redeclaration of default extensions
154
+ * is considered a regression.
155
+ */
156
+ const DEFAULT_EXTENSIONS = [
157
+ ".ts",
158
+ ".tsx",
159
+ ".js",
160
+ ".jsx",
161
+ ".mdx"
162
+ ];
163
+ /**
164
+ * Preprocess an MDX source string into scanner-consumable JSX.
165
+ *
166
+ * - Returns `{ kind: 'ok', source }` with JSX-compiled output on success.
167
+ * - Returns `{ kind: 'missing-dep' }` if @mdx-js/mdx is not resolvable
168
+ * (consumer needs to install it).
169
+ * - Returns `{ kind: 'error', error }` on compile failure (e.g. malformed
170
+ * MDX syntax). Plugins SHALL warn + skip affected files; the build
171
+ * continues with remaining files.
172
+ */
173
+ async function preprocessMdx(source, filename) {
174
+ const mdxMod = await import("@mdx-js/mdx").catch(() => null);
175
+ if (mdxMod === null) return { kind: "missing-dep" };
176
+ try {
177
+ const vfile = await mdxMod.compile(source, {
178
+ outputFormat: "program",
179
+ development: false,
180
+ jsx: true
181
+ });
182
+ return {
183
+ kind: "ok",
184
+ source: `/* @mdx-source: ${filename} */\n${String(vfile)}`
185
+ };
186
+ } catch (err) {
187
+ return {
188
+ kind: "error",
189
+ error: err instanceof Error ? err.message : String(err)
190
+ };
191
+ }
192
+ }
193
+ //#endregion
194
+ //#region pipeline/prefix.ts
195
+ /**
196
+ * Apply namespace prefix to a variable map, CSS variable declarations, and theme JSON.
197
+ *
198
+ * Variable map: `{ "colors.ember": "--color-ember" }` -> `{ "colors.ember": "--prefix-color-ember" }`
199
+ * Variable CSS: `--color-ember: #FF2800` -> `--prefix-color-ember: #FF2800`
200
+ * `var(--color-ember)` -> `var(--prefix-color-ember)`
201
+ * Theme JSON: `{ "colors.ember": "var(--color-ember)" }` -> `{ "colors.ember": "var(--prefix-color-ember)" }`
202
+ */
203
+ function applyPrefix(prefix, variableMapJson, variableCss, themeJson, contextualVarsJson) {
204
+ if (!prefix) return {
205
+ variableMapJson,
206
+ variableCss,
207
+ themeJson,
208
+ contextualVarsJson
209
+ };
210
+ const varRefRe = /var\(--([a-zA-Z][\w-]*)\)/g;
211
+ const map = JSON.parse(variableMapJson);
212
+ const prefixed = {};
213
+ for (const [key, varName] of Object.entries(map)) prefixed[key] = varName.startsWith("--") ? `--${prefix}-${varName.slice(2)}` : varName;
214
+ let css = variableCss;
215
+ css = css.replace(/--([a-zA-Z][\w-]*)\s*:/g, `--${prefix}-$1:`);
216
+ css = css.replace(varRefRe, `var(--${prefix}-$1)`);
217
+ const result = {
218
+ variableMapJson: JSON.stringify(prefixed),
219
+ variableCss: css
220
+ };
221
+ if (themeJson) result.themeJson = themeJson.replace(varRefRe, `var(--${prefix}-$1)`);
222
+ if (contextualVarsJson) {
223
+ const ctxVars = JSON.parse(contextualVarsJson);
224
+ const prefixedCtx = {};
225
+ for (const [scale, names] of Object.entries(ctxVars)) prefixedCtx[scale] = names.map((name) => `${prefix}-${name}`);
226
+ result.contextualVarsJson = JSON.stringify(prefixedCtx);
227
+ }
228
+ return result;
229
+ }
230
+ //#endregion
231
+ //#region pipeline/utils.ts
232
+ /** Convert camelCase CSS property names to kebab-case. */
233
+ function camelToKebab(str) {
234
+ return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
235
+ }
236
+ //#endregion
237
+ //#region pipeline/resolve-global-styles.ts
238
+ /**
239
+ * Resolve {scale.path} and {scale.path/alpha} token aliases in a CSS value string.
240
+ * Mirrors the Rust theme_resolver's resolve_token_aliases logic.
241
+ */
242
+ function resolveTokenAliases(value, flat, variableMap) {
243
+ if (!value.includes("{")) return value;
244
+ return value.replace(/\{([^}]+)\}/g, (_match, content) => {
245
+ const slashIdx = content.indexOf("/");
246
+ const tokenPath = slashIdx >= 0 ? content.slice(0, slashIdx) : content;
247
+ const alpha = slashIdx >= 0 ? Number.parseInt(content.slice(slashIdx + 1), 10) : null;
248
+ const flatKey = tokenPath;
249
+ let resolved;
250
+ if (variableMap[flatKey]) resolved = `var(${variableMap[flatKey]})`;
251
+ else if (flat[flatKey] != null) resolved = flat[flatKey];
252
+ else return `{${content}}`;
253
+ if (alpha === 0) return "transparent";
254
+ if (alpha != null && alpha !== 100) return `color-mix(in srgb, ${resolved} ${alpha}%, transparent)`;
255
+ return resolved;
256
+ });
257
+ }
258
+ /**
259
+ * Resolve a single CSS value through prop config: scale lookup, transform, token aliases.
260
+ */
261
+ function resolveValue(raw, config, flat, variableMap, transforms) {
262
+ let resolved = String(raw);
263
+ if (config?.scale) {
264
+ const key = config.scale + "." + raw;
265
+ if (flat[key] != null) resolved = flat[key];
266
+ }
267
+ if (config?.transform && transforms[config.transform]) {
268
+ const fn = transforms[config.transform];
269
+ const input = typeof resolved === "string" && !Number.isNaN(Number(resolved)) ? Number(resolved) : resolved;
270
+ resolved = String(fn(input));
271
+ }
272
+ return resolveTokenAliases(resolved, flat, variableMap);
273
+ }
274
+ /**
275
+ * Resolve a block of selectors -> style objects using prop config + theme.
276
+ * @keyframes selectors are resolved with full prop config support.
277
+ */
278
+ function resolveBlock(selectors, propConfig, flat, variableMap, transforms) {
279
+ const rules = [];
280
+ for (const [selector, styleObj] of Object.entries(selectors)) {
281
+ if (selector.startsWith("@keyframes")) {
282
+ const frames = [];
283
+ for (const [pct, frameStyles] of Object.entries(styleObj)) if (typeof frameStyles === "object" && frameStyles !== null) {
284
+ const decls = [];
285
+ for (const [prop, raw] of Object.entries(frameStyles)) {
286
+ const cfg = propConfig[prop];
287
+ const cssProps = cfg?.properties?.length ? cfg.properties : cfg ? [cfg.property] : [prop];
288
+ const resolved = resolveValue(raw, cfg, flat, variableMap, transforms);
289
+ for (const cssProp of cssProps) decls.push(` ${camelToKebab(cssProp)}: ${resolved};`);
290
+ }
291
+ frames.push(` ${pct} {\n${decls.join("\n")}\n }`);
292
+ }
293
+ rules.push(`${selector} {\n${frames.join("\n")}\n}`);
294
+ continue;
295
+ }
296
+ const decls = [];
297
+ for (const [prop, raw] of Object.entries(styleObj)) {
298
+ const config = propConfig[prop];
299
+ const cssProps = config?.properties?.length ? config.properties : config ? [config.property] : [prop];
300
+ const resolved = resolveValue(raw, config, flat, variableMap, transforms);
301
+ for (const cssProp of cssProps) decls.push(` ${camelToKebab(cssProp)}: ${resolved};`);
302
+ }
303
+ if (decls.length) rules.push(`${selector} {\n${decls.join("\n")}\n}`);
304
+ }
305
+ return rules.join("\n\n");
306
+ }
307
+ /**
308
+ * Resolve global style blocks into CSS strings.
309
+ *
310
+ * Takes the global style map (block name -> selectors -> props -> values),
311
+ * resolves prop shorthand, scale lookups, transforms, and token aliases,
312
+ * and returns a map of block name -> resolved CSS string.
313
+ */
314
+ function resolveGlobalStyles(globalStyles, propConfig, flat, variableMap, transforms) {
315
+ const result = {};
316
+ for (const [name, block] of Object.entries(globalStyles)) {
317
+ const resolved = resolveBlock(block, propConfig, flat, variableMap, transforms);
318
+ if (resolved) result[name] = resolved;
319
+ }
320
+ return result;
321
+ }
322
+ //#endregion
323
+ //#region pipeline/resolve-transforms.ts
324
+ /**
325
+ * Resolve __TRANSFORM__ placeholders in extracted CSS.
326
+ *
327
+ * Pattern: `__TRANSFORM__name__rawValue__` -> transform function result.
328
+ * The Rust crate emits these placeholders for CSS values that require
329
+ * JS transform functions (e.g., size, grid) which can't be evaluated in Rust.
330
+ */
331
+ function resolveTransformPlaceholders(css, transforms) {
332
+ return css.replace(/__TRANSFORM__(\w+)__(.+?)__/g, (_, name, rawValue) => {
333
+ const fn = transforms[name];
334
+ if (!fn) return rawValue;
335
+ const result = fn(rawValue !== "" && !Number.isNaN(Number(rawValue)) ? Number(rawValue) : rawValue);
336
+ return typeof result === "object" ? JSON.stringify(result) : String(result);
337
+ });
338
+ }
339
+ //#endregion
340
+ //#region pipeline/unit-fallback.ts
341
+ /**
342
+ * Append `px` to bare numeric values in CSS declarations for properties
343
+ * that expect length units. Unitless properties are preserved as-is.
344
+ * Numbers inside CSS function calls (cubic-bezier, rgb, calc, etc.) are skipped.
345
+ */
346
+ function applyUnitFallback(css) {
347
+ return css.replace(/([a-z-]+)\s*:\s*([^;{}]+);/g, (match, prop, value) => {
348
+ if (_animus_ui_properties.UNITLESS_PROPERTIES.has(prop)) return match;
349
+ let depth = 0;
350
+ let fixed = "";
351
+ let i = 0;
352
+ while (i < value.length) if (value[i] === "(") {
353
+ depth++;
354
+ fixed += value[i];
355
+ i++;
356
+ } else if (value[i] === ")") {
357
+ depth--;
358
+ fixed += value[i];
359
+ i++;
360
+ } else if (depth > 0) {
361
+ fixed += value[i];
362
+ i++;
363
+ } else {
364
+ const numMatch = value.slice(i).match(/^(-?\d+\.?\d*)/);
365
+ if (numMatch) {
366
+ const num = numMatch[1];
367
+ const after = value[i + num.length];
368
+ if (after && /[a-z%]/i.test(after)) fixed += num;
369
+ else fixed += num + "px";
370
+ i += num.length;
371
+ } else {
372
+ fixed += value[i];
373
+ i++;
374
+ }
375
+ }
376
+ return fixed !== value ? `${prop}:${fixed};` : match;
377
+ });
378
+ }
379
+ //#endregion
380
+ exports.ANIMUS_LAYERS = ANIMUS_LAYERS;
381
+ exports.DEFAULT_EXTENSIONS = DEFAULT_EXTENSIONS;
382
+ exports.applyPrefix = applyPrefix;
383
+ exports.applyUnitFallback = applyUnitFallback;
384
+ exports.assembleStylesheet = assembleStylesheet;
385
+ exports.camelToKebab = camelToKebab;
386
+ exports.extractSystemFilePackages = extractSystemFilePackages;
387
+ exports.preprocessMdx = preprocessMdx;
388
+ exports.resolveGlobalStyles = resolveGlobalStyles;
389
+ exports.resolveTokenAliases = resolveTokenAliases;
390
+ exports.resolveTransformPlaceholders = resolveTransformPlaceholders;
391
+ exports.resolveValue = resolveValue;
392
+ exports.stripLeadingLayerDeclaration = stripLeadingLayerDeclaration;
393
+ exports.validateLayerOrder = validateLayerOrder;
package/index-v2.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Type surface for the `@animus-ui/extract/engine-v2` subpath.
3
+ *
4
+ * The runtime entry (`index-v2.js`) is a hand-written CJS loader that assigns
5
+ * the whole napi binary to `module.exports` (`module.exports = loadNative()`)
6
+ * so it can fail loud with an actionable message when the binary is absent
7
+ * (extraction-diagnostics §V2 boundary error reporting). Because that whole-
8
+ * object assignment is opaque to `cjs-module-lexer`, the *value* has no
9
+ * statically-detectable named exports — so the value is typed opaquely here
10
+ * (`unknown`). Declaring the napi functions/class as named value exports would
11
+ * make `attw` report every one as missing at runtime ("Named exports").
12
+ *
13
+ * The napi-generated declarations at `crates/extract-v2/index.d.ts` describe
14
+ * the real shape; they are re-exposed as *type-only* members so consumers can
15
+ * still name the engine's types. The subpath is consumed via CJS `require`
16
+ * (see vite-plugin's `requireEngine`), which returns the full binding object.
17
+ *
18
+ * No `types` export condition is used for `./engine-v2` (root CLAUDE.md § Key
19
+ * Rules: bun's createRequire matches `types` as a runtime target and loads
20
+ * `.d.ts` as JS); TypeScript sibling-declaration substitution supplies these
21
+ * types from the `.js` entry instead.
22
+ */
23
+ import type * as ExtractV2 from './crates/extract-v2/index';
24
+
25
+ declare namespace engineV2 {
26
+ export type ExtractEngine = ExtractV2.ExtractEngine;
27
+ export type EngineOptions = ExtractV2.EngineOptions;
28
+ export type NapiSystemConfig = ExtractV2.NapiSystemConfig;
29
+ }
30
+
31
+ declare const engineV2: unknown;
32
+
33
+ export = engineV2;
package/index-v2.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * v2 engine loader. The npm surface stays @animus-ui/extract — one
3
+ * package, two engines; plugins select via the `engine` option.
4
+ *
5
+ * Fail-loud contract: a missing binary must produce an actionable
6
+ * error, never a silent fallback to the other engine
7
+ * (extraction-diagnostics §V2 boundary error reporting).
8
+ */
9
+ const { existsSync } = require('fs');
10
+ const { join } = require('path');
11
+
12
+ function loadNative() {
13
+ const { platform, arch } = process;
14
+ const candidates = [
15
+ `animus-extract-v2.${platform}-${arch}.node`,
16
+ `animus-extract-v2.${platform}-${arch}-gnu.node`,
17
+ `animus-extract-v2.${platform}-${arch}-msvc.node`,
18
+ ];
19
+ for (const name of candidates) {
20
+ const p = join(__dirname, 'crates/extract-v2', name);
21
+ if (existsSync(p)) return require(p);
22
+ }
23
+ throw new Error(
24
+ `@animus-ui/extract engine v2: native binary not found for ${platform}-${arch} ` +
25
+ `(looked for ${candidates.join(', ')} under crates/extract-v2/). ` +
26
+ `Published releases ship this binary for darwin-arm64, linux-x64-gnu and ` +
27
+ `linux-arm64-gnu — reinstall the package, or set engine: 'v1' in the plugin ` +
28
+ `options as the escape hatch (this workspace's fixtures honor ANIMUS_ENGINE=v1). ` +
29
+ `In the animus workspace, build it with: vp run build:extract-v2.`
30
+ );
31
+ }
32
+
33
+ module.exports = loadNative();
package/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // @ts-nocheck
4
4
  /* auto-generated by NAPI-RS */
5
5
 
6
- const { readFileSync } = require('node:fs')
6
+ const { readFileSync } = require('fs')
7
7
  let nativeBinding = null
8
8
  const loadErrors = []
9
9
 
@@ -33,7 +33,7 @@ const isMuslFromFilesystem = () => {
33
33
 
34
34
  const isMuslFromReport = () => {
35
35
  let report = null
36
- if (typeof process.report?.getReport === 'function') {
36
+ if (process.report && typeof process.report.getReport === 'function') {
37
37
  process.report.excludeNetwork = true
38
38
  report = process.report.getReport()
39
39
  }
@@ -105,7 +105,7 @@ function requireNative() {
105
105
  }
106
106
  } else if (process.platform === 'win32') {
107
107
  if (process.arch === 'x64') {
108
- if (process.config?.variables?.shlib_suffix === 'dll.a' || process.config?.variables?.node_target_type === 'shared_library') {
108
+ if ((process.config && process.config.variables && process.config.variables.shlib_suffix === 'dll.a') || (process.config && process.config.variables && process.config.variables.node_target_type === 'shared_library')) {
109
109
  try {
110
110
  return require('./animus-extract.win32-x64-gnu.node')
111
111
  } catch (e) {
@@ -525,23 +525,33 @@ function requireNative() {
525
525
 
526
526
  nativeBinding = requireNative()
527
527
 
528
- if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
528
+ // NAPI_RS_FORCE_WASI is a tri-state flag:
529
+ // unset / any other value → native binding preferred, WASI is only a fallback
530
+ // 'true' → force WASI fallback even if native loaded
531
+ // 'error' → force WASI and throw if no WASI binding is found
532
+ // Treating any non-empty string as truthy (the historical behavior) meant
533
+ // NAPI_RS_FORCE_WASI=false, NAPI_RS_FORCE_WASI=0, etc. inadvertently triggered
534
+ // the WASI path, causing ENOENT for packages shipped without a .wasi.cjs file.
535
+ const forceWasi =
536
+ process.env.NAPI_RS_FORCE_WASI === 'true' || process.env.NAPI_RS_FORCE_WASI === 'error'
537
+
538
+ if (!nativeBinding || forceWasi) {
529
539
  let wasiBinding = null
530
540
  let wasiBindingError = null
531
541
  try {
532
542
  wasiBinding = require('./animus-extract.wasi.cjs')
533
543
  nativeBinding = wasiBinding
534
544
  } catch (err) {
535
- if (process.env.NAPI_RS_FORCE_WASI) {
545
+ if (forceWasi) {
536
546
  wasiBindingError = err
537
547
  }
538
548
  }
539
- if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
549
+ if (!nativeBinding || forceWasi) {
540
550
  try {
541
551
  wasiBinding = require('@animus-ui/extract-wasm32-wasi')
542
552
  nativeBinding = wasiBinding
543
553
  } catch (err) {
544
- if (process.env.NAPI_RS_FORCE_WASI) {
554
+ if (forceWasi) {
545
555
  if (!wasiBindingError) {
546
556
  wasiBindingError = err
547
557
  } else {
@@ -560,17 +570,18 @@ if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
560
570
 
561
571
  if (!nativeBinding) {
562
572
  if (loadErrors.length > 0) {
563
- throw new Error(
573
+ const error = new Error(
564
574
  `Cannot find native binding. ` +
565
575
  `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
566
576
  'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
567
- {
568
- cause: loadErrors.reduce((err, cur) => {
569
- cur.cause = err
570
- return cur
571
- }),
572
- },
573
577
  )
578
+ // assign instead of the `new Error(message, { cause })` options form,
579
+ // which Node < 16.9 silently ignores
580
+ error.cause = loadErrors.reduce((err, cur) => {
581
+ cur.cause = err
582
+ return cur
583
+ })
584
+ throw error
574
585
  }
575
586
  throw new Error(`Failed to load native binding`)
576
587
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animus-ui/extract",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Animus static CSS extraction pipeline (Rust/NAPI)",
5
5
  "keywords": [
6
6
  "animus",
@@ -24,7 +24,11 @@
24
24
  "index.js",
25
25
  "index.d.ts",
26
26
  "*.node",
27
- "dist"
27
+ "dist",
28
+ "index-v2.js",
29
+ "index-v2.d.ts",
30
+ "crates/extract-v2/*.node",
31
+ "crates/extract-v2/index.d.ts"
28
32
  ],
29
33
  "main": "index.js",
30
34
  "types": "index.d.ts",
@@ -36,27 +40,33 @@
36
40
  },
37
41
  "./pipeline": {
38
42
  "types": "./dist/index.d.ts",
39
- "import": "./dist/index.mjs",
40
- "require": "./dist/index.mjs",
41
- "default": "./dist/index.mjs"
43
+ "default": "./dist/index.cjs"
44
+ },
45
+ "./engine-v2": {
46
+ "import": "./index-v2.js",
47
+ "require": "./index-v2.js",
48
+ "default": "./index-v2.js"
42
49
  }
43
50
  },
44
51
  "publishConfig": {
45
52
  "access": "public"
46
53
  },
47
54
  "scripts": {
48
- "build": "napi build --platform --release && bun run build:ts",
55
+ "build": "napi build --platform --release && bun run build:v2 && bun run build:ts",
56
+ "build:v1": "napi build --platform --release",
49
57
  "build:ts": "tsdown && tsgo -p tsconfig.build.json",
50
58
  "build:debug": "napi build --platform",
51
- "compile": "tsgo -p tsconfig.build.json --noEmit"
59
+ "compile": "tsgo -p tsconfig.build.json --noEmit",
60
+ "build:v2": "cd crates/extract-v2 && bunx napi build --platform --release",
61
+ "build:v2:debug": "cd crates/extract-v2 && bunx napi build --platform"
52
62
  },
53
63
  "dependencies": {
54
- "@animus-ui/properties": "0.1.0"
64
+ "@animus-ui/properties": "0.1.1"
55
65
  },
56
66
  "devDependencies": {
57
67
  "@animus-ui/system": "workspace:*",
58
68
  "@mdx-js/mdx": "^3.0.0",
59
- "@napi-rs/cli": "^3.0.0"
69
+ "@napi-rs/cli": "^3.7.3"
60
70
  },
61
71
  "peerDependencies": {
62
72
  "@mdx-js/mdx": "^3.0.0"
@@ -67,9 +77,9 @@
67
77
  }
68
78
  },
69
79
  "optionalDependencies": {
70
- "@animus-ui/extract-darwin-arm64": "0.1.0",
71
- "@animus-ui/extract-linux-arm64-gnu": "0.1.0",
72
- "@animus-ui/extract-linux-x64-gnu": "0.1.0"
80
+ "@animus-ui/extract-darwin-arm64": "0.1.1",
81
+ "@animus-ui/extract-linux-arm64-gnu": "0.1.1",
82
+ "@animus-ui/extract-linux-x64-gnu": "0.1.1"
73
83
  },
74
84
  "napi": {
75
85
  "binaryName": "animus-extract",