@ismail-elkorchi/css-parser 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.
- package/README.md +69 -57
- package/dist/public/mod.d.ts +51 -17
- package/dist/public/mod.js +81 -27
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# @ismail-elkorchi/css-parser
|
|
2
2
|
|
|
3
|
-
Deterministic CSS parsing and selector
|
|
3
|
+
Deterministic CSS parsing and selector utilities for automation across Node, Deno, Bun, and modern browsers.
|
|
4
|
+
|
|
5
|
+
No runtime dependencies: this package ships with zero runtime dependencies.
|
|
6
|
+
|
|
7
|
+
## When To Use
|
|
8
|
+
|
|
9
|
+
- You need deterministic CSS parse/serialize output.
|
|
10
|
+
- You need selector querying without browser-engine side effects.
|
|
11
|
+
- You need explicit resource budgets for untrusted stylesheets.
|
|
12
|
+
|
|
13
|
+
## When Not To Use
|
|
14
|
+
|
|
15
|
+
- You need browser layout/cascade computation.
|
|
16
|
+
- You need stylesheet sanitization and policy enforcement in one step.
|
|
17
|
+
- You need script or DOM runtime semantics.
|
|
4
18
|
|
|
5
19
|
## Install
|
|
6
20
|
|
|
@@ -12,25 +26,31 @@ npm install @ismail-elkorchi/css-parser
|
|
|
12
26
|
deno add jsr:@ismail-elkorchi/css-parser
|
|
13
27
|
```
|
|
14
28
|
|
|
29
|
+
## Import
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { parse } from "@ismail-elkorchi/css-parser";
|
|
33
|
+
```
|
|
34
|
+
|
|
15
35
|
```txt
|
|
16
36
|
import { parse } from "jsr:@ismail-elkorchi/css-parser";
|
|
17
37
|
```
|
|
18
38
|
|
|
19
|
-
##
|
|
39
|
+
## Copy/Paste Examples
|
|
40
|
+
|
|
41
|
+
### Example 1: Parse CSS
|
|
20
42
|
|
|
21
43
|
```ts
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
budgets: { maxInputBytes: 4096, maxNodes: 256, maxDepth: 32 }
|
|
33
|
-
});
|
|
44
|
+
import { parse } from "@ismail-elkorchi/css-parser";
|
|
45
|
+
|
|
46
|
+
const tree = parse(".card { color: red; }");
|
|
47
|
+
console.log(tree.kind);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Example 2: Parse streaming input
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { parseStream } from "@ismail-elkorchi/css-parser";
|
|
34
54
|
|
|
35
55
|
const stream = new ReadableStream({
|
|
36
56
|
start(controller) {
|
|
@@ -39,62 +59,54 @@ const stream = new ReadableStream({
|
|
|
39
59
|
}
|
|
40
60
|
});
|
|
41
61
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const selector = compileSelectorList("#content .card");
|
|
47
|
-
const root = {
|
|
48
|
-
kind: "document",
|
|
49
|
-
children: [{ kind: "element", tagName: "main", attributes: [{ name: "id", value: "content" }], children: [] }]
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
console.log(querySelectorAll(selector, root).length);
|
|
53
|
-
console.log(serialize(parsed));
|
|
54
|
-
console.log(serialize(streamed));
|
|
62
|
+
const tree = await parseStream(stream, { budgets: { maxInputBytes: 4096, maxBufferedBytes: 512 } });
|
|
63
|
+
console.log(tree.kind);
|
|
55
64
|
```
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
npm run examples:run
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Options / API Reference
|
|
64
|
-
|
|
65
|
-
- [Options and API reference](./docs/reference/options.md)
|
|
66
|
+
### Example 3: Query selectors
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
```ts
|
|
69
|
+
import { compileSelectorList, querySelectorAll } from "@ismail-elkorchi/css-parser";
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
const selector = compileSelectorList(".card");
|
|
72
|
+
console.log(selector.supported, querySelectorAll(selector, { kind: "document", children: [] }).length);
|
|
73
|
+
```
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
### Example 4: Extract render signals
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- You need runtime execution of scripts or DOM behavior.
|
|
77
|
+
```ts
|
|
78
|
+
import { extractRenderSignals, parse } from "@ismail-elkorchi/css-parser";
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
const tree = parse(".card { color: red; }");
|
|
81
|
+
console.log(extractRenderSignals(tree).length >= 0);
|
|
82
|
+
```
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
Run packaged examples:
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
```bash
|
|
87
|
+
npm run examples:run
|
|
88
|
+
```
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
- Deno (stable)
|
|
87
|
-
- Bun (stable)
|
|
88
|
-
- Modern evergreen browsers (smoke-tested)
|
|
90
|
+
## Compatibility
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
Runtime compatibility matrix:
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
| Runtime | Status |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| Node.js | Supported |
|
|
97
|
+
| Deno | Supported |
|
|
98
|
+
| Bun | Supported |
|
|
99
|
+
| Browser (evergreen) | Supported |
|
|
93
100
|
|
|
94
|
-
##
|
|
101
|
+
## Security and Safety Notes
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
Parsing is not sanitization. For untrusted input:
|
|
104
|
+
- configure strict budgets,
|
|
105
|
+
- handle `BudgetExceededError` explicitly,
|
|
106
|
+
- apply separate policy checks before execution or rendering.
|
|
97
107
|
|
|
98
|
-
##
|
|
108
|
+
## Documentation
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
- [Docs index](./docs/index.md)
|
|
111
|
+
- [First parse success tutorial](./docs/tutorial/first-parse.md)
|
|
112
|
+
- [Options reference](./docs/reference/options.md)
|
package/dist/public/mod.d.ts
CHANGED
|
@@ -3,33 +3,67 @@ export type { BudgetExceededPayload, BudgetOptions, CompiledSelector, CompiledSe
|
|
|
3
3
|
export declare class BudgetExceededError extends Error {
|
|
4
4
|
readonly payload: BudgetExceededPayload;
|
|
5
5
|
constructor(payload: BudgetExceededPayload);
|
|
6
|
-
}
|
|
6
|
+
} /**
|
|
7
|
+
* Represents a structured public error for `PatchPlanningError` failure cases.
|
|
8
|
+
*/
|
|
7
9
|
export declare class PatchPlanningError extends Error {
|
|
8
10
|
readonly payload: PatchPlanningErrorPayload;
|
|
9
11
|
constructor(payload: PatchPlanningErrorPayload);
|
|
10
12
|
}
|
|
11
|
-
export declare function parse(css: string, options?: ParseOptions): StyleSheetTree;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export declare function
|
|
13
|
+
export declare function parse(css: string, options?: ParseOptions): StyleSheetTree; /**
|
|
14
|
+
* Parses input deterministically for the `parseFragment` public API.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseFragment(css: string, contextTagName: string, options?: ParseOptions): FragmentTree; /**
|
|
17
|
+
* Parses input deterministically for the `parseRuleList` public API.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseRuleList(css: string, options?: ParseOptions): FragmentTree; /**
|
|
20
|
+
* Parses input deterministically for the `parseDeclarationList` public API.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseDeclarationList(css: string, options?: ParseOptions): FragmentTree; /**
|
|
23
|
+
* Returns deterministic public metadata for `getParseErrorSpecRef`.
|
|
24
|
+
*/
|
|
15
25
|
export declare function getParseErrorSpecRef(parseErrorId: string): string;
|
|
16
|
-
export declare function tokenize(css: string, options?: TokenizeOptions): readonly Token[];
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
export declare function tokenize(css: string, options?: TokenizeOptions): readonly Token[]; /**
|
|
27
|
+
* Tokenizes input deterministically for the `tokenizeStream` public API.
|
|
28
|
+
*/
|
|
29
|
+
export declare function tokenizeStream(stream: ReadableStream<Uint8Array>, options?: TokenizeOptions): AsyncIterable<Token>; /**
|
|
30
|
+
* Parses input deterministically for the `parseBytes` public API.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseBytes(bytes: Uint8Array, options?: ParseOptions): StyleSheetTree; /**
|
|
33
|
+
* Parses input deterministically for the `parseStream` public API.
|
|
34
|
+
*/
|
|
19
35
|
export declare function parseStream(stream: ReadableStream<Uint8Array>, options?: ParseOptions): Promise<StyleSheetTree>;
|
|
20
36
|
export declare function serialize(treeOrNode: StyleSheetTree | FragmentTree | CssNode): string;
|
|
21
|
-
export declare function walk(tree: StyleSheetTree | FragmentTree, visitor: NodeVisitor): void;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export declare function
|
|
37
|
+
export declare function walk(tree: StyleSheetTree | FragmentTree, visitor: NodeVisitor): void; /**
|
|
38
|
+
* Traverses parsed data deterministically for the `walkByType` public API.
|
|
39
|
+
*/
|
|
40
|
+
export declare function walkByType(tree: StyleSheetTree | FragmentTree, type: string, visitor: NodeVisitor): void; /**
|
|
41
|
+
* Traverses parsed data deterministically for the `findById` public API.
|
|
42
|
+
*/
|
|
43
|
+
export declare function findById(tree: StyleSheetTree | FragmentTree, id: NodeId): CssNode | null; /**
|
|
44
|
+
* Traverses parsed data deterministically for the `findAllByType` public API.
|
|
45
|
+
*/
|
|
46
|
+
export declare function findAllByType(tree: StyleSheetTree | FragmentTree, type: string): IterableIterator<CssNode>; /**
|
|
47
|
+
* Provides deterministic public behavior for `outline`.
|
|
48
|
+
*/
|
|
25
49
|
export declare function outline(tree: StyleSheetTree | FragmentTree): Outline;
|
|
26
50
|
export declare function chunk(tree: StyleSheetTree | FragmentTree, options?: ChunkOptions): Chunk[];
|
|
27
|
-
export declare function applyPatchPlan(originalCss: string, plan: PatchPlan): string;
|
|
51
|
+
export declare function applyPatchPlan(originalCss: string, plan: PatchPlan): string; /**
|
|
52
|
+
* Computes deterministic public output for `computePatch`.
|
|
53
|
+
*/
|
|
28
54
|
export declare function computePatch(originalCss: string, edits: readonly Edit[]): PatchPlan;
|
|
29
55
|
export declare function compileSelectorList(selectorText: string): CompiledSelectorList;
|
|
30
|
-
export declare function extractStyleRuleSignals(cssOrTree: string | StyleSheetTree, options?: StyleSignalOptions): readonly StyleRuleSignal[];
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
export declare function extractStyleRuleSignals(cssOrTree: string | StyleSheetTree, options?: StyleSignalOptions): readonly StyleRuleSignal[]; /**
|
|
57
|
+
* Extracts deterministic public data for `extractInlineStyleSignals`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function extractInlineStyleSignals(styleText: string): readonly StyleDeclarationSignal[]; /**
|
|
60
|
+
* Extracts deterministic public data for `extractRenderSignals`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function extractRenderSignals(cssOrTree: string | StyleSheetTree, options?: RenderSignalOptions): readonly RenderSignal[]; /**
|
|
63
|
+
* Extracts deterministic public data for `extractInlineRenderSignals`.
|
|
64
|
+
*/
|
|
33
65
|
export declare function extractInlineRenderSignals(styleText: string, options?: RenderSignalOptions): readonly RenderSignal[];
|
|
34
|
-
export declare function matchesSelector<TNode extends SelectorNodeLike>(selector: string | CompiledSelectorList, node: TNode, root: TNode, options?: SelectorQueryOptions): boolean;
|
|
66
|
+
export declare function matchesSelector<TNode extends SelectorNodeLike>(selector: string | CompiledSelectorList, node: TNode, root: TNode, options?: SelectorQueryOptions): boolean; /**
|
|
67
|
+
* Traverses parsed data deterministically for the `querySelectorAll` public API.
|
|
68
|
+
*/
|
|
35
69
|
export declare function querySelectorAll<TNode extends SelectorNodeLike>(selector: string | CompiledSelectorList, root: TNode, options?: SelectorQueryOptions): readonly TNode[];
|
package/dist/public/mod.js
CHANGED
|
@@ -18,7 +18,9 @@ const SUPPORTED_PARSE_CONTEXTS = new Set([
|
|
|
18
18
|
"declarationList",
|
|
19
19
|
"declaration",
|
|
20
20
|
"value"
|
|
21
|
-
]);
|
|
21
|
+
]); /**
|
|
22
|
+
* Represents a structured public error for `BudgetExceededError` failure cases.
|
|
23
|
+
*/
|
|
22
24
|
export class BudgetExceededError extends Error {
|
|
23
25
|
payload;
|
|
24
26
|
constructor(payload) {
|
|
@@ -26,7 +28,9 @@ export class BudgetExceededError extends Error {
|
|
|
26
28
|
this.name = "BudgetExceededError";
|
|
27
29
|
this.payload = payload;
|
|
28
30
|
}
|
|
29
|
-
}
|
|
31
|
+
} /**
|
|
32
|
+
* Represents a structured public error for `PatchPlanningError` failure cases.
|
|
33
|
+
*/
|
|
30
34
|
export class PatchPlanningError extends Error {
|
|
31
35
|
payload;
|
|
32
36
|
constructor(payload) {
|
|
@@ -418,7 +422,9 @@ function parseInternal(css, context, options = {}) {
|
|
|
418
422
|
errors: publicErrors,
|
|
419
423
|
...(trace ? { trace } : {})
|
|
420
424
|
};
|
|
421
|
-
}
|
|
425
|
+
} /**
|
|
426
|
+
* Parses input deterministically for the `parse` public API.
|
|
427
|
+
*/
|
|
422
428
|
export function parse(css, options = {}) {
|
|
423
429
|
if (options.context !== undefined && options.context !== "stylesheet") {
|
|
424
430
|
throw new Error("parse() only supports context \"stylesheet\"; use parseFragment() for other contexts");
|
|
@@ -433,7 +439,9 @@ export function parse(css, options = {}) {
|
|
|
433
439
|
errors: parsed.errors,
|
|
434
440
|
...(parsed.trace ? { trace: parsed.trace } : {})
|
|
435
441
|
};
|
|
436
|
-
}
|
|
442
|
+
} /**
|
|
443
|
+
* Parses input deterministically for the `parseFragment` public API.
|
|
444
|
+
*/
|
|
437
445
|
export function parseFragment(css, contextTagName, options = {}) {
|
|
438
446
|
const context = normalizeFragmentContext(contextTagName);
|
|
439
447
|
if (!SUPPORTED_PARSE_CONTEXTS.has(context)) {
|
|
@@ -449,13 +457,19 @@ export function parseFragment(css, contextTagName, options = {}) {
|
|
|
449
457
|
errors: parsed.errors,
|
|
450
458
|
...(parsed.trace ? { trace: parsed.trace } : {})
|
|
451
459
|
};
|
|
452
|
-
}
|
|
460
|
+
} /**
|
|
461
|
+
* Parses input deterministically for the `parseRuleList` public API.
|
|
462
|
+
*/
|
|
453
463
|
export function parseRuleList(css, options = {}) {
|
|
454
464
|
return parseFragment(css, "rule", options);
|
|
455
|
-
}
|
|
465
|
+
} /**
|
|
466
|
+
* Parses input deterministically for the `parseDeclarationList` public API.
|
|
467
|
+
*/
|
|
456
468
|
export function parseDeclarationList(css, options = {}) {
|
|
457
469
|
return parseFragment(css, "declarationList", options);
|
|
458
|
-
}
|
|
470
|
+
} /**
|
|
471
|
+
* Returns deterministic public metadata for `getParseErrorSpecRef`.
|
|
472
|
+
*/
|
|
459
473
|
export function getParseErrorSpecRef(parseErrorId) {
|
|
460
474
|
void parseErrorId;
|
|
461
475
|
return CSS_PARSE_ERRORS_SECTION_URL;
|
|
@@ -568,7 +582,9 @@ async function decodeStreamToText(stream, options) {
|
|
|
568
582
|
totalBytes: total,
|
|
569
583
|
maxBufferedObserved
|
|
570
584
|
};
|
|
571
|
-
}
|
|
585
|
+
} /**
|
|
586
|
+
* Tokenizes input deterministically for the `tokenize` public API.
|
|
587
|
+
*/
|
|
572
588
|
export function tokenize(css, options = {}) {
|
|
573
589
|
enforceBudget("maxInputBytes", options.budgets?.maxInputBytes, css.length);
|
|
574
590
|
const tokenized = tokenizeInternal(css, {
|
|
@@ -579,14 +595,18 @@ export function tokenize(css, options = {}) {
|
|
|
579
595
|
});
|
|
580
596
|
enforceBudget("maxTokens", options.budgets?.maxTokens, tokenized.tokens.length);
|
|
581
597
|
return tokenized.tokens.map((token) => toPublicToken(token));
|
|
582
|
-
}
|
|
598
|
+
} /**
|
|
599
|
+
* Tokenizes input deterministically for the `tokenizeStream` public API.
|
|
600
|
+
*/
|
|
583
601
|
export async function* tokenizeStream(stream, options = {}) {
|
|
584
602
|
const decoded = await decodeStreamToText(stream, options);
|
|
585
603
|
const tokens = tokenize(decoded.text, options);
|
|
586
604
|
for (const token of tokens) {
|
|
587
605
|
yield token;
|
|
588
606
|
}
|
|
589
|
-
}
|
|
607
|
+
} /**
|
|
608
|
+
* Parses input deterministically for the `parseBytes` public API.
|
|
609
|
+
*/
|
|
590
610
|
export function parseBytes(bytes, options = {}) {
|
|
591
611
|
enforceBudget("maxInputBytes", options.budgets?.maxInputBytes, bytes.byteLength);
|
|
592
612
|
const decoded = decodeCssBytes(bytes, {
|
|
@@ -609,7 +629,9 @@ export function parseBytes(bytes, options = {}) {
|
|
|
609
629
|
...parsed,
|
|
610
630
|
trace: withDecodeTrace
|
|
611
631
|
};
|
|
612
|
-
}
|
|
632
|
+
} /**
|
|
633
|
+
* Parses input deterministically for the `parseStream` public API.
|
|
634
|
+
*/
|
|
613
635
|
export async function parseStream(stream, options = {}) {
|
|
614
636
|
const budgets = options.budgets;
|
|
615
637
|
const decoded = await decodeStreamToText(stream, options);
|
|
@@ -645,7 +667,9 @@ function nodeFromTree(treeOrNode) {
|
|
|
645
667
|
return treeOrNode.root;
|
|
646
668
|
}
|
|
647
669
|
return treeOrNode;
|
|
648
|
-
}
|
|
670
|
+
} /**
|
|
671
|
+
* Serializes data deterministically for the `serialize` public API.
|
|
672
|
+
*/
|
|
649
673
|
export function serialize(treeOrNode) {
|
|
650
674
|
const node = nodeFromTree(treeOrNode);
|
|
651
675
|
const sanitized = sanitizeCssNode(node);
|
|
@@ -656,10 +680,14 @@ function walkNode(node, depth, visitor) {
|
|
|
656
680
|
for (const child of childNodes(node)) {
|
|
657
681
|
walkNode(child, depth + 1, visitor);
|
|
658
682
|
}
|
|
659
|
-
}
|
|
683
|
+
} /**
|
|
684
|
+
* Traverses parsed data deterministically for the `walk` public API.
|
|
685
|
+
*/
|
|
660
686
|
export function walk(tree, visitor) {
|
|
661
687
|
walkNode(tree.root, 0, visitor);
|
|
662
|
-
}
|
|
688
|
+
} /**
|
|
689
|
+
* Traverses parsed data deterministically for the `walkByType` public API.
|
|
690
|
+
*/
|
|
663
691
|
export function walkByType(tree, type, visitor) {
|
|
664
692
|
const normalizedType = type.toLowerCase();
|
|
665
693
|
walk(tree, (node, depth) => {
|
|
@@ -667,7 +695,9 @@ export function walkByType(tree, type, visitor) {
|
|
|
667
695
|
visitor(node, depth);
|
|
668
696
|
}
|
|
669
697
|
});
|
|
670
|
-
}
|
|
698
|
+
} /**
|
|
699
|
+
* Traverses parsed data deterministically for the `findById` public API.
|
|
700
|
+
*/
|
|
671
701
|
export function findById(tree, id) {
|
|
672
702
|
let matched = null;
|
|
673
703
|
walk(tree, (node) => {
|
|
@@ -676,7 +706,9 @@ export function findById(tree, id) {
|
|
|
676
706
|
}
|
|
677
707
|
});
|
|
678
708
|
return matched;
|
|
679
|
-
}
|
|
709
|
+
} /**
|
|
710
|
+
* Traverses parsed data deterministically for the `findAllByType` public API.
|
|
711
|
+
*/
|
|
680
712
|
export function* findAllByType(tree, type) {
|
|
681
713
|
const normalizedType = type.toLowerCase();
|
|
682
714
|
const found = [];
|
|
@@ -688,7 +720,9 @@ export function* findAllByType(tree, type) {
|
|
|
688
720
|
for (const node of found) {
|
|
689
721
|
yield node;
|
|
690
722
|
}
|
|
691
|
-
}
|
|
723
|
+
} /**
|
|
724
|
+
* Provides deterministic public behavior for `outline`.
|
|
725
|
+
*/
|
|
692
726
|
export function outline(tree) {
|
|
693
727
|
const entries = [];
|
|
694
728
|
walk(tree, (node, depth) => {
|
|
@@ -717,7 +751,9 @@ function countNodes(node) {
|
|
|
717
751
|
}
|
|
718
752
|
function topLevelNodes(tree) {
|
|
719
753
|
return tree.children.length > 0 ? tree.children : [tree.root];
|
|
720
|
-
}
|
|
754
|
+
} /**
|
|
755
|
+
* Provides deterministic public behavior for `chunk`.
|
|
756
|
+
*/
|
|
721
757
|
export function chunk(tree, options = {}) {
|
|
722
758
|
const maxChars = options.maxChars ?? 8192;
|
|
723
759
|
const maxNodes = options.maxNodes ?? 256;
|
|
@@ -845,7 +881,9 @@ function buildReplacement(spanByNode, nodeById, edit, sourceIndex) {
|
|
|
845
881
|
end: span.end,
|
|
846
882
|
replacementCss: edit.css
|
|
847
883
|
};
|
|
848
|
-
}
|
|
884
|
+
} /**
|
|
885
|
+
* Provides deterministic public behavior for `applyPatchPlan`.
|
|
886
|
+
*/
|
|
849
887
|
export function applyPatchPlan(originalCss, plan) {
|
|
850
888
|
let cursor = 0;
|
|
851
889
|
let output = "";
|
|
@@ -864,7 +902,9 @@ export function applyPatchPlan(originalCss, plan) {
|
|
|
864
902
|
output += step.text;
|
|
865
903
|
}
|
|
866
904
|
return output;
|
|
867
|
-
}
|
|
905
|
+
} /**
|
|
906
|
+
* Computes deterministic public output for `computePatch`.
|
|
907
|
+
*/
|
|
868
908
|
export function computePatch(originalCss, edits) {
|
|
869
909
|
if (edits.length === 0) {
|
|
870
910
|
const steps = [
|
|
@@ -1400,7 +1440,9 @@ function compileSingleSelector(selectorNode, selectorIndex) {
|
|
|
1400
1440
|
supported: unsupported.length === 0,
|
|
1401
1441
|
unsupportedParts: unsupported
|
|
1402
1442
|
};
|
|
1403
|
-
}
|
|
1443
|
+
} /**
|
|
1444
|
+
* Provides deterministic public behavior for `compileSelectorList`.
|
|
1445
|
+
*/
|
|
1404
1446
|
export function compileSelectorList(selectorText) {
|
|
1405
1447
|
const parsed = parseFragment(selectorText, "selectorList");
|
|
1406
1448
|
const selectorNodes = Array.isArray(parsed.root.children)
|
|
@@ -1536,7 +1578,9 @@ function classifyRenderSignalClass(declaration, options) {
|
|
|
1536
1578
|
}
|
|
1537
1579
|
}
|
|
1538
1580
|
return null;
|
|
1539
|
-
}
|
|
1581
|
+
} /**
|
|
1582
|
+
* Extracts deterministic public data for `extractStyleRuleSignals`.
|
|
1583
|
+
*/
|
|
1540
1584
|
export function extractStyleRuleSignals(cssOrTree, options = {}) {
|
|
1541
1585
|
const includeUnsupportedSelectors = options.includeUnsupportedSelectors === true;
|
|
1542
1586
|
const strictSelectors = options.strictSelectors === true;
|
|
@@ -1580,7 +1624,9 @@ export function extractStyleRuleSignals(cssOrTree, options = {}) {
|
|
|
1580
1624
|
});
|
|
1581
1625
|
});
|
|
1582
1626
|
return signals;
|
|
1583
|
-
}
|
|
1627
|
+
} /**
|
|
1628
|
+
* Extracts deterministic public data for `extractInlineStyleSignals`.
|
|
1629
|
+
*/
|
|
1584
1630
|
export function extractInlineStyleSignals(styleText) {
|
|
1585
1631
|
const fragment = parseDeclarationList(styleText);
|
|
1586
1632
|
const signals = [];
|
|
@@ -1594,7 +1640,9 @@ export function extractInlineStyleSignals(styleText) {
|
|
|
1594
1640
|
declarationOrder += 1;
|
|
1595
1641
|
}
|
|
1596
1642
|
return signals;
|
|
1597
|
-
}
|
|
1643
|
+
} /**
|
|
1644
|
+
* Extracts deterministic public data for `extractRenderSignals`.
|
|
1645
|
+
*/
|
|
1598
1646
|
export function extractRenderSignals(cssOrTree, options = {}) {
|
|
1599
1647
|
const ruleSignals = extractStyleRuleSignals(cssOrTree, options);
|
|
1600
1648
|
const renderSignals = [];
|
|
@@ -1619,7 +1667,9 @@ export function extractRenderSignals(cssOrTree, options = {}) {
|
|
|
1619
1667
|
}
|
|
1620
1668
|
}
|
|
1621
1669
|
return renderSignals;
|
|
1622
|
-
}
|
|
1670
|
+
} /**
|
|
1671
|
+
* Extracts deterministic public data for `extractInlineRenderSignals`.
|
|
1672
|
+
*/
|
|
1623
1673
|
export function extractInlineRenderSignals(styleText, options = {}) {
|
|
1624
1674
|
const declarations = extractInlineStyleSignals(styleText);
|
|
1625
1675
|
const renderSignals = [];
|
|
@@ -1664,7 +1714,9 @@ function resolveCompiledSelectorList(selector) {
|
|
|
1664
1714
|
}
|
|
1665
1715
|
}
|
|
1666
1716
|
return compiled;
|
|
1667
|
-
}
|
|
1717
|
+
} /**
|
|
1718
|
+
* Provides deterministic public behavior for `matchesSelector`.
|
|
1719
|
+
*/
|
|
1668
1720
|
export function matchesSelector(selector, node, root, options = {}) {
|
|
1669
1721
|
const compiled = resolveCompiledSelectorList(selector);
|
|
1670
1722
|
assertSelectorStrict(compiled, options.strict === true);
|
|
@@ -1681,7 +1733,9 @@ export function matchesSelector(selector, node, root, options = {}) {
|
|
|
1681
1733
|
}
|
|
1682
1734
|
}
|
|
1683
1735
|
return false;
|
|
1684
|
-
}
|
|
1736
|
+
} /**
|
|
1737
|
+
* Traverses parsed data deterministically for the `querySelectorAll` public API.
|
|
1738
|
+
*/
|
|
1685
1739
|
export function querySelectorAll(selector, root, options = {}) {
|
|
1686
1740
|
const compiled = resolveCompiledSelectorList(selector);
|
|
1687
1741
|
assertSelectorStrict(compiled, options.strict === true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ismail-elkorchi/css-parser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Deterministic CSS parser for automation workflows across Node, Deno, Bun, and modern browsers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"test:bench": "npm run build && node --expose-gc scripts/bench/run-bench.mjs",
|
|
49
49
|
"test:bench:stability": "npm run build && node --expose-gc scripts/bench/run-bench-stability.mjs",
|
|
50
50
|
"examples:run": "npm run build && node examples/run-all.mjs",
|
|
51
|
-
"check:fast": "npm run lint && npm run typecheck && npm run test:control && npm run examples:run",
|
|
51
|
+
"check:fast": "npm run lint && npm run typecheck && npm run test:control && npm run docs:required && npm run examples:run",
|
|
52
52
|
"docs:lint:jsr": "deno doc --lint --sloppy-imports jsr/mod.ts",
|
|
53
53
|
"docs:test:jsr": "deno test --doc --no-check --sloppy-imports jsr/mod.ts",
|
|
54
54
|
"smoke:node": "npm run build && node scripts/smoke/control.mjs --runtime=node --report=reports/smoke-node.json",
|
|
@@ -65,10 +65,13 @@
|
|
|
65
65
|
"realworld:bench:selectors:stability": "npm run build && node scripts/bench/run-selector-bench-stability.mjs",
|
|
66
66
|
"realworld:check": "node scripts/realworld/check-realworld-targets.mjs",
|
|
67
67
|
"eval:realworld": "npm run realworld:bench && npm run realworld:signals && npm run realworld:bench:selectors && npm run realworld:bench:selectors:stability && npm run realworld:check && node scripts/realworld/eval-realworld.mjs",
|
|
68
|
-
"mutation:pilot": "npm run build && node scripts/mutation/run-pilot.mjs --config=scripts/mutation/pilot-config.json --out=docs/
|
|
68
|
+
"mutation:pilot": "npm run build && node scripts/mutation/run-pilot.mjs --config=scripts/mutation/pilot-config.json --out=docs/maintainers/mutation-pilot-report.json",
|
|
69
69
|
"eval:ci": "node scripts/eval/run-eval.mjs --profile=ci",
|
|
70
70
|
"eval:release": "node scripts/eval/run-eval.mjs --profile=release",
|
|
71
|
-
"eval:hard-gate": "node scripts/eval/run-eval.mjs --profile=hard-gate"
|
|
71
|
+
"eval:hard-gate": "node scripts/eval/run-eval.mjs --profile=hard-gate",
|
|
72
|
+
"docs:required": "node scripts/quality/doc-required.mjs",
|
|
73
|
+
"release:notes:dry-run": "node scripts/release/render-notes.mjs --dry-run",
|
|
74
|
+
"changelog:update:dry-run": "node scripts/release/update-changelog.mjs --dry-run"
|
|
72
75
|
},
|
|
73
76
|
"dependencies": {},
|
|
74
77
|
"overrides": {
|