@zealakit/css-doctor-binding 0.0.0-stage → 1.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zealamic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,48 @@
1
- # Temporary Holding Version
1
+ <div align="center">
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ # @zealakit/css-doctor-binding
4
+
5
+ **Native NAPI-RS bridge for the css-doctor LightningCSS engine.**
6
+
7
+ [English](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_CN.md)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ![css doctor](https://github.com/zealakit/css-doctor/blob/main/assets/images/css-doctor.jpg)
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @zealakit/css-doctor-binding
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```ts
24
+ import { analyzeCss, optimizeCss } from "@zealakit/css-doctor-binding";
25
+
26
+ const analysis = analyzeCss(".card { color: red; }");
27
+
28
+ const result = optimizeCss({
29
+ cssContent: ".card { color: red; } :root { --brand: red; }",
30
+ pageUsage: { home: ["card"] },
31
+ pageCoverage: { enabled: true, minPageRatio: 0.5 },
32
+ sizeBudget: { enabled: true, maxChunkSize: 40 * 1024, isolateVariables: true },
33
+ minify: true,
34
+ });
35
+
36
+ console.log(analysis.stats.selectorCount);
37
+ console.log(result.chunks);
38
+ ```
39
+
40
+ ## Safety and limitations
41
+
42
+ - Prebuilt binaries cover darwin-arm64, darwin-x64, linux-x64-gnu, linux-x64-musl, and win32-x64-msvc.
43
+ - The native API is low-level; prefer @zealakit/css-doctor-vite, next, rsbuild, nuxt, or remix for application builds.
44
+ - Never edit generated index.js, index.d.ts, index.d.cts, or *.node files by hand.
45
+
46
+ ## Full documentation
47
+
48
+ Project README: [English](https://github.com/zealakit/css-doctor/blob/main/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/README_CN.md)
package/README_CN.md ADDED
@@ -0,0 +1,48 @@
1
+ <div align="center">
2
+
3
+ # @zealakit/css-doctor-binding
4
+
5
+ **css-doctor LightningCSS 引擎的原生 NAPI-RS 桥接层。**
6
+
7
+ [English](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_CN.md)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ![css doctor](https://github.com/zealakit/css-doctor/blob/main/assets/images/css-doctor.jpg)
14
+
15
+ ## 安装
16
+
17
+ ```bash
18
+ pnpm add @zealakit/css-doctor-binding
19
+ ```
20
+
21
+ ## 使用
22
+
23
+ ```ts
24
+ import { analyzeCss, optimizeCss } from "@zealakit/css-doctor-binding";
25
+
26
+ const analysis = analyzeCss(".card { color: red; }");
27
+
28
+ const result = optimizeCss({
29
+ cssContent: ".card { color: red; } :root { --brand: red; }",
30
+ pageUsage: { home: ["card"] },
31
+ pageCoverage: { enabled: true, minPageRatio: 0.5 },
32
+ sizeBudget: { enabled: true, maxChunkSize: 40 * 1024, isolateVariables: true },
33
+ minify: true,
34
+ });
35
+
36
+ console.log(analysis.stats.selectorCount);
37
+ console.log(result.chunks);
38
+ ```
39
+
40
+ ## 安全与限制
41
+
42
+ - 预构建二进制支持 darwin-arm64、darwin-x64、linux-x64-gnu、linux-x64-musl 和 win32-x64-msvc。
43
+ - 原生 API 属于底层接口;应用构建推荐使用 @zealakit/css-doctor-vite、next、rsbuild、nuxt 或 remix。
44
+ - 不要手动修改生成的 index.js、index.d.ts、index.d.cts 或 *.node。
45
+
46
+ ## 完整文档
47
+
48
+ 项目 README:[English](https://github.com/zealakit/css-doctor/blob/main/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/README_CN.md)
package/README_VI.md ADDED
@@ -0,0 +1,48 @@
1
+ <div align="center">
2
+
3
+ # @zealakit/css-doctor-binding
4
+
5
+ **Cầu nối NAPI-RS native cho engine LightningCSS của css-doctor.**
6
+
7
+ [English](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/packages/binding/README_CN.md)
8
+
9
+ </div>
10
+
11
+ ---
12
+
13
+ ![css doctor](https://github.com/zealakit/css-doctor/blob/main/assets/images/css-doctor.jpg)
14
+
15
+ ## Cài đặt
16
+
17
+ ```bash
18
+ pnpm add @zealakit/css-doctor-binding
19
+ ```
20
+
21
+ ## Sử dụng
22
+
23
+ ```ts
24
+ import { analyzeCss, optimizeCss } from "@zealakit/css-doctor-binding";
25
+
26
+ const analysis = analyzeCss(".card { color: red; }");
27
+
28
+ const result = optimizeCss({
29
+ cssContent: ".card { color: red; } :root { --brand: red; }",
30
+ pageUsage: { home: ["card"] },
31
+ pageCoverage: { enabled: true, minPageRatio: 0.5 },
32
+ sizeBudget: { enabled: true, maxChunkSize: 40 * 1024, isolateVariables: true },
33
+ minify: true,
34
+ });
35
+
36
+ console.log(analysis.stats.selectorCount);
37
+ console.log(result.chunks);
38
+ ```
39
+
40
+ ## An toàn và giới hạn
41
+
42
+ - Binary dựng sẵn hỗ trợ darwin-arm64, darwin-x64, linux-x64-gnu, linux-x64-musl và win32-x64-msvc.
43
+ - API native là low-level; nên dùng @zealakit/css-doctor-vite, next, rsbuild, nuxt hoặc remix cho ứng dụng.
44
+ - Không chỉnh tay index.js, index.d.ts, index.d.cts hoặc *.node đã generate.
45
+
46
+ ## Tài liệu đầy đủ
47
+
48
+ README dự án: [English](https://github.com/zealakit/css-doctor/blob/main/README.md) | [Tiếng Việt](https://github.com/zealakit/css-doctor/blob/main/README_VI.md) | [简体中文](https://github.com/zealakit/css-doctor/blob/main/README_CN.md)
package/index.d.ts ADDED
@@ -0,0 +1,533 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /** The kind of a simple selector. */
7
+ export const enum JsSelectorKind {
8
+ /** A class selector such as `.button`. */
9
+ Class = 'class',
10
+ /** An ID selector such as `#app`. */
11
+ Id = 'id',
12
+ /** A type/tag selector such as `section`. */
13
+ Tag = 'tag',
14
+ /** An attribute selector such as `[data-state="open"]`. */
15
+ Attribute = 'attribute',
16
+ /** A pseudo-class such as `:hover`. */
17
+ PseudoClass = 'pseudo_class',
18
+ /** A pseudo-element such as `::before`. */
19
+ PseudoElement = 'pseudo_element',
20
+ /** The universal selector `*`. */
21
+ Universal = 'universal',
22
+ /** The CSS nesting selector `&`. */
23
+ Nesting = 'nesting'
24
+ }
25
+ /** Decoded CSS specificity. */
26
+ export interface JsSpecificity {
27
+ /** Number of ID selectors. */
28
+ ids: number
29
+ /** Number of class, attribute and pseudo-class selectors. */
30
+ classes: number
31
+ /** Number of type and pseudo-element selectors. */
32
+ types: number
33
+ }
34
+ /** A 1-based source location. */
35
+ export interface JsSourceLocation {
36
+ /** 1-based line number. */
37
+ line: number
38
+ /** 1-based column number. */
39
+ column: number
40
+ }
41
+ /** A non-fatal parser warning. */
42
+ export interface JsAnalysisWarning {
43
+ /** Human-readable description of the problem. */
44
+ message: string
45
+ /** Location of the problem, when known. */
46
+ location?: JsSourceLocation
47
+ }
48
+ /** A selector extracted from a style rule. */
49
+ export interface JsSelectorInfo {
50
+ /** Normalized selector text. */
51
+ raw: string
52
+ /** Simple-selector kinds present in the selector. */
53
+ kinds: Array<JsSelectorKind>
54
+ /** Class names without the leading dot. */
55
+ classes: Array<string>
56
+ /** ID names without the leading hash. */
57
+ ids: Array<string>
58
+ /** Local type/tag names. */
59
+ tags: Array<string>
60
+ /** Local attribute names. */
61
+ attributes: Array<string>
62
+ /** Pseudo-class names without the leading colon or arguments. */
63
+ pseudoClasses: Array<string>
64
+ /** Pseudo-element names without the leading `::` or arguments. */
65
+ pseudoElements: Array<string>
66
+ /** Tree combinators present (`" "`, `">"`, `"+"`, `"~"`). */
67
+ combinators: Array<string>
68
+ /** Decoded specificity. */
69
+ specificity: JsSpecificity
70
+ /** Index into `CssAnalysisResult.rules`. */
71
+ ruleIndex: number
72
+ /** Number of enclosing style rules. */
73
+ nestingDepth: number
74
+ }
75
+ /** A style rule and its selectors. */
76
+ export interface JsStyleRuleInfo {
77
+ /** Index of the rule in `CssAnalysisResult.rules`. */
78
+ index: number
79
+ /** Index of the enclosing style rule, when nested. */
80
+ parentRuleIndex?: number
81
+ /** Indices into `CssAnalysisResult.selectors`. */
82
+ selectorIndices: Array<number>
83
+ /** Number of normal declarations. */
84
+ declarationCount: number
85
+ /** Number of `!important` declarations. */
86
+ importantDeclarationCount: number
87
+ /** Number of enclosing style rules. */
88
+ nestingDepth: number
89
+ /** Location of the rule in the source. */
90
+ location: JsSourceLocation
91
+ }
92
+ /** Aggregate counters for an analysis run. */
93
+ export interface JsAnalysisStats {
94
+ /** Number of style rules. */
95
+ ruleCount: number
96
+ /** Number of selectors. */
97
+ selectorCount: number
98
+ /** Total number of normal declarations. */
99
+ declarationCount: number
100
+ /** Total number of `!important` declarations. */
101
+ importantDeclarationCount: number
102
+ /** Number of distinct class names. */
103
+ uniqueClassCount: number
104
+ /** Number of distinct ID names. */
105
+ uniqueIdCount: number
106
+ /** Number of distinct type/tag names. */
107
+ uniqueTagCount: number
108
+ /** Number of distinct attribute names. */
109
+ uniqueAttributeCount: number
110
+ /** Deepest style-rule nesting observed. */
111
+ maxNestingDepth: number
112
+ /** Number of parser warnings. */
113
+ warningCount: number
114
+ }
115
+ /** The complete result of analyzing a stylesheet. */
116
+ export interface JsCssAnalysisResult {
117
+ /** All selectors in document order. */
118
+ selectors: Array<JsSelectorInfo>
119
+ /** All style rules in document order. */
120
+ rules: Array<JsStyleRuleInfo>
121
+ /** Aggregate counters. */
122
+ stats: JsAnalysisStats
123
+ /** Recoverable parser warnings. */
124
+ warnings: Array<JsAnalysisWarning>
125
+ }
126
+ /**
127
+ * Analyzes a CSS string synchronously.
128
+ *
129
+ * # Errors
130
+ *
131
+ * Rejects with a JavaScript `Error` when the stylesheet cannot be parsed at
132
+ * all. Recoverable syntax errors are returned as `warnings` instead.
133
+ */
134
+ export declare function analyzeCss(cssContent: string): JsCssAnalysisResult
135
+ /**
136
+ * Analyzes a CSS string on the libuv thread pool and returns a `Promise`.
137
+ *
138
+ * This is the preferred entry point for large stylesheets because it does not
139
+ * block the Node.js event loop.
140
+ *
141
+ * # Errors
142
+ *
143
+ * Rejects with a JavaScript `Error` when the stylesheet cannot be parsed.
144
+ */
145
+ export declare function analyzeCssAsync(cssContent: string): Promise<JsCssAnalysisResult>
146
+ /**
147
+ * Analyzes a CSS string and returns the result as a JSON string.
148
+ *
149
+ * The JSON shape is identical to the object returned by `analyzeCss`.
150
+ *
151
+ * # Errors
152
+ *
153
+ * Rejects with a JavaScript `Error` when parsing or serialization fails.
154
+ */
155
+ export declare function analyzeCssJson(cssContent: string): string
156
+ /** Configuration for page-coverage chunk splitting. */
157
+ export interface JsChunkConfig {
158
+ /**
159
+ * Minimum share of pages that must use a rule before it is considered
160
+ * common. Range: 0.0..=1.0.
161
+ */
162
+ minPageRatio: number
163
+ /** Selectors or class names that should always stay in the common chunk. */
164
+ forceCommonSelectors: Array<string>
165
+ /** Minify serialized CSS. Defaults to `true`. */
166
+ minify?: boolean
167
+ }
168
+ /** Input for [`split_css_by_pages`]. */
169
+ export interface JsSplitInput {
170
+ /** Original CSS source. */
171
+ cssContent: string
172
+ /** Page/route name to class names used by that page. */
173
+ pageUsage: Record<string, Array<string>>
174
+ /** Splitting configuration. */
175
+ config: JsChunkConfig
176
+ }
177
+ /** Usage information for one selector. */
178
+ export interface JsSelectorStat {
179
+ /** Original selector text. */
180
+ selector: string
181
+ /** Matched class occurrences across pages. */
182
+ totalOccurrences: number
183
+ /** Number of pages using the selector. */
184
+ pageCount: number
185
+ /** Fraction of pages using the selector (0..1). */
186
+ coverageRatio: number
187
+ /** `common`, `dead`, or `page:<name>[,<name>...]`. */
188
+ targetChunk: string
189
+ }
190
+ /** Result of page-coverage chunk splitting. */
191
+ export interface JsSplitOutput {
192
+ /** CSS shared by pages reaching the coverage threshold, plus global rules. */
193
+ commonCss: string
194
+ /** Page name to page-specific CSS. */
195
+ pageChunks: Record<string, string>
196
+ /** Per-selector usage matrix. */
197
+ stats: Array<JsSelectorStat>
198
+ /** Number of dead selector occurrences removed. */
199
+ deadCodeCount: number
200
+ }
201
+ /**
202
+ * Splits a stylesheet into common and page-specific CSS chunks.
203
+ *
204
+ * # Errors
205
+ *
206
+ * Rejects with a JavaScript `Error` when the configuration is invalid or the
207
+ * stylesheet/AST cannot be processed.
208
+ */
209
+ export declare function splitCssByPages(input: JsSplitInput): JsSplitOutput
210
+ /** Configuration for the semantic page-coverage tier. */
211
+ export interface JsPageCoverageConfig {
212
+ /** Enable page-coverage splitting. Defaults to `true`. */
213
+ enabled?: boolean
214
+ /** Minimum page coverage for common rules. Defaults to `0.5`. */
215
+ minPageRatio?: number
216
+ /** Selectors or classes that always stay in the common chunk. */
217
+ forceCommon?: Array<string>
218
+ }
219
+ /** Configuration for the physical size-budget tier. */
220
+ export interface JsSizeBudgetConfig {
221
+ /** Enable size-budget splitting. Defaults to `true`. */
222
+ enabled?: boolean
223
+ /** Maximum serialized bytes per body chunk. Defaults to 60 KiB. */
224
+ maxChunkSize?: number
225
+ /** Isolate CSS variables before splitting. Defaults to `true`. */
226
+ isolateVariables?: boolean
227
+ }
228
+ /** Input for [`optimize_css`]. */
229
+ export interface JsPipelineInput {
230
+ /** Original CSS source. */
231
+ cssContent: string
232
+ /** Page/route name to class names used by that page. */
233
+ pageUsage: Record<string, Array<string>>
234
+ /** Optional tier 1 configuration. */
235
+ pageCoverage?: JsPageCoverageConfig
236
+ /** Optional tier 2 configuration. */
237
+ sizeBudget?: JsSizeBudgetConfig
238
+ /** Minify serialized CSS. Defaults to `true`. */
239
+ minify?: boolean
240
+ }
241
+ /** The stage that produced a pipeline chunk. */
242
+ export const enum JsPipelineChunkKind {
243
+ /** Shared/common rules. */
244
+ Common = 'common',
245
+ /** Page-specific rules. */
246
+ Page = 'page',
247
+ /** Isolated CSS variables. */
248
+ Variables = 'variables',
249
+ /** A size-budget part. */
250
+ Part = 'part'
251
+ }
252
+ /** One CSS chunk emitted by the pipeline. */
253
+ export interface JsChunkOutput {
254
+ /** Logical file stem, e.g. `common`, `page-home`, `common-vars`. */
255
+ name: string
256
+ /** Base chunk before physical splitting. */
257
+ sourceChunk: string
258
+ /** Serialized CSS. */
259
+ css: string
260
+ /** Stage/kind of this chunk. */
261
+ kind: JsPipelineChunkKind
262
+ /** Page that owns this chunk, when applicable. */
263
+ page?: string
264
+ /** Whether this chunk contains isolated CSS variables. */
265
+ variables: boolean
266
+ /** 1-based part index when produced by size splitting. */
267
+ part?: number
268
+ /** Serialized byte size. */
269
+ sizeBytes: number
270
+ /** True when an indivisible rule exceeds the budget. */
271
+ oversized: boolean
272
+ /** True when this chunk exists because of the size budget. */
273
+ splitDueToSize: boolean
274
+ }
275
+ /** Result of the two-tier optimization pipeline. */
276
+ export interface JsPipelineOutput {
277
+ /** Final chunks in load order. */
278
+ chunks: Array<JsChunkOutput>
279
+ /** Selector usage matrix from tier 1. */
280
+ stats: Array<JsSelectorStat>
281
+ /** Dead selector occurrences removed by tier 1. */
282
+ deadCodeCount: number
283
+ /** Pages discovered from `page_usage`. */
284
+ pages: Array<string>
285
+ /** Whether page-coverage splitting actually ran. */
286
+ pageCoverageApplied: boolean
287
+ /** Whether size-budget processing was enabled. */
288
+ sizeBudgetApplied: boolean
289
+ }
290
+ /**
291
+ * Runs the two-tier CSS optimization pipeline.
292
+ *
293
+ * # Errors
294
+ *
295
+ * Rejects with a JavaScript `Error` when the configuration is invalid or the
296
+ * stylesheet/AST cannot be processed.
297
+ */
298
+ export declare function optimizeCss(input: JsPipelineInput): JsPipelineOutput
299
+ /** Combined pipeline output + optimization report from a single native run. */
300
+ export interface JsOptimizeExplained {
301
+ pipeline: JsPipelineOutput
302
+ reportJson: string
303
+ }
304
+ /**
305
+ * Runs the optimization pipeline once and returns both chunks and a report.
306
+ *
307
+ * Prefer this over calling [`optimize_css`] and [`optimize_css_report`]
308
+ * separately to avoid double parsing/splitting.
309
+ *
310
+ * # Errors
311
+ *
312
+ * Rejects when the pipeline or report builder fails.
313
+ */
314
+ export declare function optimizeCssExplained(input: JsPipelineInput, maxSelectorDecisions?: number | undefined | null): JsOptimizeExplained
315
+ /**
316
+ * Runs the optimization pipeline and returns a versioned report JSON document
317
+ * that includes decisions, metrics, and chunk inventory.
318
+ *
319
+ * # Errors
320
+ *
321
+ * Rejects when the pipeline or report builder fails.
322
+ */
323
+ export declare function optimizeCssReport(input: JsPipelineInput, maxSelectorDecisions?: number | undefined | null): string
324
+ /** Lists built-in autofix rules as JSON. */
325
+ export declare function listCssFixes(): string
326
+ /** Autofix input. */
327
+ export interface JsFixInput {
328
+ cssContent: string
329
+ filePath?: string
330
+ dryRun?: boolean
331
+ rules?: Array<string>
332
+ includeReview?: boolean
333
+ }
334
+ /**
335
+ * Plans or applies safe CSS autofixes. Returns a JSON `FixApplicationResult`.
336
+ *
337
+ * # Errors
338
+ *
339
+ * Rejects for parse/serialize failures or unsafe rule selection.
340
+ */
341
+ export declare function applyCssFixes(input: JsFixInput): string
342
+ /** Optional weights for CSS Health Score dimensions (must be >= 0). */
343
+ export interface JsHealthWeights {
344
+ selectorComplexity?: number
345
+ duplicateRules?: number
346
+ cssSizeEfficiency?: number
347
+ deadCss?: number
348
+ variableConsistency?: number
349
+ }
350
+ /** Optional thresholds for CSS Health Score analyzers. */
351
+ export interface JsHealthThresholds {
352
+ highSpecificityClasses?: number
353
+ highSpecificityIds?: number
354
+ deepCombinatorCount?: number
355
+ deepNestingDepth?: number
356
+ longSelectorTokenCount?: number
357
+ largeStylesheetBytes?: number
358
+ criticalStylesheetBytes?: number
359
+ heavyRuleDeclarations?: number
360
+ manySelectors?: number
361
+ }
362
+ /** Input for [`evaluate_css_health`]. */
363
+ export interface JsHealthInput {
364
+ cssContent: string
365
+ filePath?: string
366
+ sizeBytes?: number
367
+ weights?: JsHealthWeights
368
+ thresholds?: JsHealthThresholds
369
+ }
370
+ /** One health diagnostic finding. */
371
+ export interface JsHealthDiagnostic {
372
+ code: string
373
+ severity: string
374
+ category: string
375
+ message: string
376
+ filePath?: string
377
+ location?: JsSourceLocation
378
+ selector?: string
379
+ remediation: string
380
+ certainty: string
381
+ }
382
+ /** Score metadata for one health dimension. */
383
+ export interface JsDimensionScore {
384
+ id: string
385
+ score?: number
386
+ weight: number
387
+ effectiveWeight: number
388
+ evaluated: boolean
389
+ issueCount: number
390
+ errorCount: number
391
+ warningCount: number
392
+ infoCount: number
393
+ diagnosticCodes: Array<string>
394
+ recommendations: Array<string>
395
+ note?: string
396
+ }
397
+ /** Aggregate counters for a health report. */
398
+ export interface JsHealthScoreSummary {
399
+ files: number
400
+ rules: number
401
+ selectors: number
402
+ declarations: number
403
+ sizeBytes: number
404
+ errors: number
405
+ warnings: number
406
+ suggestions: number
407
+ analysisMs: number
408
+ }
409
+ /** Complete CSS Health Score report. */
410
+ export interface JsHealthReport {
411
+ schemaVersion: number
412
+ overall: number
413
+ grade: string
414
+ status: string
415
+ dimensions: Array<JsDimensionScore>
416
+ summary: JsHealthScoreSummary
417
+ diagnostics: Array<JsHealthDiagnostic>
418
+ recommendations: Array<string>
419
+ }
420
+ /**
421
+ * Evaluates CSS Health Score for a single stylesheet.
422
+ *
423
+ * # Errors
424
+ *
425
+ * Rejects when configuration is invalid or CSS cannot be parsed.
426
+ */
427
+ export declare function evaluateCssHealth(input: JsHealthInput): JsHealthReport
428
+ /** One stylesheet entry for multi-file health evaluation. */
429
+ export interface JsHealthFileInput {
430
+ cssContent: string
431
+ filePath?: string
432
+ sizeBytes?: number
433
+ }
434
+ /** Multi-file health evaluation input. */
435
+ export interface JsHealthBatchInput {
436
+ files: Array<JsHealthFileInput>
437
+ weights?: JsHealthWeights
438
+ thresholds?: JsHealthThresholds
439
+ }
440
+ /**
441
+ * Evaluates and merges CSS Health Score across multiple stylesheets.
442
+ *
443
+ * # Errors
444
+ *
445
+ * Rejects when configuration is invalid or any stylesheet cannot be parsed.
446
+ */
447
+ export declare function evaluateCssHealthBatch(input: JsHealthBatchInput): JsHealthReport
448
+ /** File entry used when creating a baseline document. */
449
+ export interface JsBaselineFileInput {
450
+ path: string
451
+ cssContent: string
452
+ sizeBytes?: number
453
+ }
454
+ /** Optional Git metadata for a baseline. */
455
+ export interface JsBaselineGitMetadata {
456
+ commit?: string
457
+ branch?: string
458
+ dirty?: boolean
459
+ }
460
+ /** Optional project metadata for a baseline. */
461
+ export interface JsBaselineProjectMetadata {
462
+ name?: string
463
+ root?: string
464
+ }
465
+ /** Input for [`create_baseline`]. */
466
+ export interface JsBaselineCreateInput {
467
+ files: Array<JsBaselineFileInput>
468
+ toolVersion: string
469
+ createdAt?: string
470
+ patterns?: Array<string>
471
+ threshold?: number
472
+ project?: JsBaselineProjectMetadata
473
+ git?: JsBaselineGitMetadata
474
+ weights?: JsHealthWeights
475
+ thresholds?: JsHealthThresholds
476
+ }
477
+ /** Validation outcome for a baseline document. */
478
+ export interface JsBaselineValidationResult {
479
+ status: string
480
+ message?: string
481
+ }
482
+ /** Comparison tolerances for regression detection. */
483
+ export interface JsCompareOptions {
484
+ scoreTolerance?: number
485
+ sizeAbsoluteToleranceBytes?: number
486
+ sizeIncreasePercent?: number
487
+ countAbsoluteTolerance?: number
488
+ countIncreasePercent?: number
489
+ }
490
+ /** Minimum dimension score gate. */
491
+ export interface JsMinDimensionScore {
492
+ id: string
493
+ minScore: number
494
+ }
495
+ /** Quality-gate configuration for regression comparison. */
496
+ export interface JsQualityGateConfig {
497
+ minScore?: number
498
+ minDimensionScores?: Array<JsMinDimensionScore>
499
+ maxCssSize?: number
500
+ maxSizeIncreasePercent?: number
501
+ maxNewErrors?: number
502
+ maxNewWarnings?: number
503
+ failOnRegression?: boolean
504
+ failOnNewErrors?: boolean
505
+ failOnNewDiagnostics?: boolean
506
+ }
507
+ /**
508
+ * Creates a versioned baseline JSON document from CSS files.
509
+ *
510
+ * # Errors
511
+ *
512
+ * Rejects when configuration is invalid, CSS cannot be parsed, or
513
+ * serialization fails.
514
+ */
515
+ export declare function createBaseline(input: JsBaselineCreateInput): string
516
+ /**
517
+ * Validates a baseline JSON document.
518
+ *
519
+ * # Errors
520
+ *
521
+ * Rejects when the JSON cannot be parsed.
522
+ */
523
+ export declare function validateBaseline(baselineJson: string, toolVersion: string): JsBaselineValidationResult
524
+ /**
525
+ * Compares a stored baseline against a current baseline snapshot.
526
+ *
527
+ * Returns a versioned regression report as pretty JSON.
528
+ *
529
+ * # Errors
530
+ *
531
+ * Rejects when either document is invalid JSON or options are invalid.
532
+ */
533
+ export declare function compareBaselines(baselineJson: string, currentJson: string, options?: JsCompareOptions | undefined | null, gates?: JsQualityGateConfig | undefined | null): string
package/index.js ADDED
@@ -0,0 +1,330 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'css-doctor-binding.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./css-doctor-binding.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('@zealakit/css-doctor-binding-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'css-doctor-binding.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./css-doctor-binding.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('@zealakit/css-doctor-binding-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'css-doctor-binding.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./css-doctor-binding.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('@zealakit/css-doctor-binding-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'css-doctor-binding.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./css-doctor-binding.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('@zealakit/css-doctor-binding-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'css-doctor-binding.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./css-doctor-binding.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('@zealakit/css-doctor-binding-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'css-doctor-binding.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./css-doctor-binding.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('@zealakit/css-doctor-binding-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'css-doctor-binding.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./css-doctor-binding.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('@zealakit/css-doctor-binding-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'css-doctor-binding.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./css-doctor-binding.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('@zealakit/css-doctor-binding-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'css-doctor-binding.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./css-doctor-binding.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('@zealakit/css-doctor-binding-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'css-doctor-binding.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./css-doctor-binding.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'css-doctor-binding.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./css-doctor-binding.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'css-doctor-binding.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./css-doctor-binding.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'css-doctor-binding.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./css-doctor-binding.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'css-doctor-binding.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./css-doctor-binding.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'css-doctor-binding.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./css-doctor-binding.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'css-doctor-binding.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./css-doctor-binding.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'css-doctor-binding.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./css-doctor-binding.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'css-doctor-binding.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./css-doctor-binding.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('@zealakit/css-doctor-binding-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { JsSelectorKind, analyzeCss, analyzeCssAsync, analyzeCssJson, splitCssByPages, JsPipelineChunkKind, optimizeCss, optimizeCssExplained, optimizeCssReport, listCssFixes, applyCssFixes, evaluateCssHealth, evaluateCssHealthBatch, createBaseline, validateBaseline, compareBaselines } = nativeBinding
314
+
315
+ module.exports.JsSelectorKind = JsSelectorKind
316
+ module.exports.analyzeCss = analyzeCss
317
+ module.exports.analyzeCssAsync = analyzeCssAsync
318
+ module.exports.analyzeCssJson = analyzeCssJson
319
+ module.exports.splitCssByPages = splitCssByPages
320
+ module.exports.JsPipelineChunkKind = JsPipelineChunkKind
321
+ module.exports.optimizeCss = optimizeCss
322
+ module.exports.optimizeCssExplained = optimizeCssExplained
323
+ module.exports.optimizeCssReport = optimizeCssReport
324
+ module.exports.listCssFixes = listCssFixes
325
+ module.exports.applyCssFixes = applyCssFixes
326
+ module.exports.evaluateCssHealth = evaluateCssHealth
327
+ module.exports.evaluateCssHealthBatch = evaluateCssHealthBatch
328
+ module.exports.createBaseline = createBaseline
329
+ module.exports.validateBaseline = validateBaseline
330
+ module.exports.compareBaselines = compareBaselines
package/package.json CHANGED
@@ -1,6 +1,84 @@
1
1
  {
2
2
  "name": "@zealakit/css-doctor-binding",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.1.0",
4
+ "description": "Native Node.js bindings for the css-doctor CSS analysis engine",
5
+ "keywords": [
6
+ "css",
7
+ "css-doctor",
8
+ "css-analysis",
9
+ "css-optimizer",
10
+ "dead-code-elimination",
11
+ "unused-css",
12
+ "purgecss",
13
+ "critical-css",
14
+ "css-splitting",
15
+ "page-coverage",
16
+ "lightningcss",
17
+ "native-addon",
18
+ "napi",
19
+ "napi-rs",
20
+ "rust",
21
+ "nodejs",
22
+ "performance",
23
+ "web-performance",
24
+ "stylesheet",
25
+ "frontend"
26
+ ],
27
+ "author": "nqhed - Huy Edward Nguyen",
28
+ "license": "MIT",
29
+ "main": "index.js",
30
+ "types": "index.d.ts",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/zealakit/css-doctor.git",
34
+ "directory": "packages/binding"
35
+ },
36
+ "files": [
37
+ "index.js",
38
+ "index.d.ts",
39
+ "index.d.cts",
40
+ "*.node",
41
+ "README.md",
42
+ "README_VI.md",
43
+ "README_CN.md"
44
+ ],
45
+ "napi": {
46
+ "name": "css-doctor-binding",
47
+ "triples": {
48
+ "defaults": true
49
+ }
50
+ },
51
+ "devDependencies": {
52
+ "@napi-rs/cli": "^2.18.4",
53
+ "@types/node": "^22.20.5",
54
+ "tsx": "^4.23.15",
55
+ "typescript": "^5.9.3"
56
+ },
57
+ "engines": {
58
+ "node": ">=18"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "optionalDependencies": {
64
+ "@zealakit/css-doctor-binding-darwin-arm64": "1.1.0",
65
+ "@zealakit/css-doctor-binding-darwin-x64": "1.1.0",
66
+ "@zealakit/css-doctor-binding-linux-x64-gnu": "1.1.0",
67
+ "@zealakit/css-doctor-binding-linux-x64-musl": "1.1.0",
68
+ "@zealakit/css-doctor-binding-win32-x64-msvc": "1.1.0"
69
+ },
70
+ "bugs": {
71
+ "url": "https://github.com/zealakit/css-doctor/issues"
72
+ },
73
+ "homepage": "https://github.com/zealakit/css-doctor#readme",
74
+ "scripts": {
75
+ "build": "napi build --platform --release",
76
+ "build:debug": "napi build --platform",
77
+ "test": "pnpm build && pnpm typecheck && tsx test.ts",
78
+ "typecheck": "tsc --noEmit -p tsconfig.json",
79
+ "lint": "biome lint src test.ts",
80
+ "format": "biome format --write src test.ts",
81
+ "format:check": "biome format src test.ts",
82
+ "check": "biome check src test.ts"
83
+ }
6
84
  }