@zslabs/atomic-css-modules 0.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/CHANGELOG.md +10 -0
- package/GUIDE.md +32 -0
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/dist/atom-key.d.ts +19 -0
- package/dist/atom-key.js +72 -0
- package/dist/atom-key.js.map +1 -0
- package/dist/atoms.d.ts +8 -0
- package/dist/atoms.js +33 -0
- package/dist/atoms.js.map +1 -0
- package/dist/declaration-utils.d.ts +37 -0
- package/dist/declaration-utils.js +99 -0
- package/dist/declaration-utils.js.map +1 -0
- package/dist/file-scan-cache.d.ts +21 -0
- package/dist/file-scan-cache.js +122 -0
- package/dist/file-scan-cache.js.map +1 -0
- package/dist/hash.d.ts +15 -0
- package/dist/hash.js +38 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/process.d.ts +2 -0
- package/dist/process.js +19 -0
- package/dist/process.js.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.js +107 -0
- package/dist/registry.js.map +1 -0
- package/dist/report.d.ts +7 -0
- package/dist/report.js +67 -0
- package/dist/report.js.map +1 -0
- package/dist/rewrite.d.ts +2 -0
- package/dist/rewrite.js +482 -0
- package/dist/rewrite.js.map +1 -0
- package/dist/rule-context.d.ts +35 -0
- package/dist/rule-context.js +86 -0
- package/dist/rule-context.js.map +1 -0
- package/dist/scan.d.ts +2 -0
- package/dist/scan.js +177 -0
- package/dist/scan.js.map +1 -0
- package/dist/selector-utils.d.ts +34 -0
- package/dist/selector-utils.js +156 -0
- package/dist/selector-utils.js.map +1 -0
- package/dist/shorthand-groups.d.ts +7 -0
- package/dist/shorthand-groups.js +85 -0
- package/dist/shorthand-groups.js.map +1 -0
- package/dist/skip-comment.d.ts +6 -0
- package/dist/skip-comment.js +48 -0
- package/dist/skip-comment.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/vite-plugin.d.ts +27 -0
- package/dist/vite-plugin.js +231 -0
- package/dist/vite-plugin.js.map +1 -0
- package/package.json +75 -0
package/dist/scan.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { transform } from 'lightningcss';
|
|
2
|
+
import { atomClassNameForKey, atomKeyString, buildAtomKey } from './atom-key.js';
|
|
3
|
+
import { declarationProperty, flattenDeclarations, isComposesDeclaration, } from './declaration-utils.js';
|
|
4
|
+
import { allocateUniqueClassName } from './hash.js';
|
|
5
|
+
import { RuleContextTracker } from './rule-context.js';
|
|
6
|
+
import { classifyEligibleGroup, classifySelector, printSelectorList, skipReasonForSelector, skipReasonForSelectors, } from './selector-utils.js';
|
|
7
|
+
import { findShorthandConflicts } from './shorthand-groups.js';
|
|
8
|
+
import { hasAtomicSkipComment } from './skip-comment.js';
|
|
9
|
+
function ineligibleRuleInfo(context) {
|
|
10
|
+
return {
|
|
11
|
+
eligible: false,
|
|
12
|
+
condition: context.condition,
|
|
13
|
+
nested: context.nested,
|
|
14
|
+
pseudo: null,
|
|
15
|
+
selector: [],
|
|
16
|
+
atomKeys: [],
|
|
17
|
+
atomHashes: [],
|
|
18
|
+
decisions: [],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function collectAtoms(block, context, classification, atoms, taken, debugNames) {
|
|
22
|
+
const flatDeclarations = flattenDeclarations(block);
|
|
23
|
+
const shorthandConflicts = findShorthandConflicts(flatDeclarations
|
|
24
|
+
.filter(({ declaration }) => !isComposesDeclaration(declaration))
|
|
25
|
+
.map(({ declaration }) => declarationProperty(declaration)));
|
|
26
|
+
const atomKeys = [];
|
|
27
|
+
const atomHashes = [];
|
|
28
|
+
const decisions = [];
|
|
29
|
+
for (const { declaration, important } of flatDeclarations) {
|
|
30
|
+
if (isComposesDeclaration(declaration)) {
|
|
31
|
+
decisions.push({ action: 'composes' });
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const property = declarationProperty(declaration);
|
|
35
|
+
if (shorthandConflicts.has(property)) {
|
|
36
|
+
decisions.push({ action: 'keep', important });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const key = buildAtomKey({
|
|
40
|
+
property,
|
|
41
|
+
declaration,
|
|
42
|
+
important,
|
|
43
|
+
pseudo: classification.pseudo,
|
|
44
|
+
condition: context.condition,
|
|
45
|
+
});
|
|
46
|
+
const keyString = atomKeyString(key);
|
|
47
|
+
let atom = atoms.get(keyString);
|
|
48
|
+
if (!atom) {
|
|
49
|
+
const desired = atomClassNameForKey(key, declaration, debugNames);
|
|
50
|
+
const hash = allocateUniqueClassName(taken, desired);
|
|
51
|
+
taken.add(hash);
|
|
52
|
+
atom = { hash, className: hash, key, keyString, declaration };
|
|
53
|
+
atoms.set(keyString, atom);
|
|
54
|
+
}
|
|
55
|
+
atomKeys.push(keyString);
|
|
56
|
+
atomHashes.push(atom.hash);
|
|
57
|
+
decisions.push({ action: 'hoist', atomKey: keyString });
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
atomKeys,
|
|
61
|
+
atomHashes,
|
|
62
|
+
decisions,
|
|
63
|
+
shorthandConflict: shorthandConflicts.size > 0,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function recordShorthandSkip(skips, filePath, selector, shorthandConflict) {
|
|
67
|
+
if (!shorthandConflict)
|
|
68
|
+
return;
|
|
69
|
+
skips.push({
|
|
70
|
+
filePath,
|
|
71
|
+
selector: printSelectorList([selector]),
|
|
72
|
+
reason: 'shorthand-conflict',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function scanStyleLikeRule(rule, context, atoms, taken, rules, skips, file, debugNames) {
|
|
76
|
+
const loc = rule.type === 'style' || rule.type === 'nested-declarations'
|
|
77
|
+
? rule.value.loc
|
|
78
|
+
: null;
|
|
79
|
+
if (loc && hasAtomicSkipComment(file.code, loc)) {
|
|
80
|
+
const selectors = rule.type === 'style'
|
|
81
|
+
? rule.value.selectors.flatMap((selector) => context.resolveAll(selector))
|
|
82
|
+
: context.selectors;
|
|
83
|
+
rules.push(ineligibleRuleInfo(context));
|
|
84
|
+
skips.push({
|
|
85
|
+
filePath: file.filePath,
|
|
86
|
+
selector: printSelectorList(selectors),
|
|
87
|
+
reason: 'skip-comment',
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (rule.type === 'nested-declarations') {
|
|
92
|
+
let anyEligible = false;
|
|
93
|
+
for (const parentSelector of context.selectors) {
|
|
94
|
+
const classification = classifySelector(parentSelector);
|
|
95
|
+
if (!classification.eligible) {
|
|
96
|
+
skips.push({
|
|
97
|
+
filePath: file.filePath,
|
|
98
|
+
selector: printSelectorList([parentSelector]),
|
|
99
|
+
reason: skipReasonForSelector(parentSelector),
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
anyEligible = true;
|
|
104
|
+
const collected = collectAtoms(rule.value.declarations, context, classification, atoms, taken, debugNames);
|
|
105
|
+
rules.push({
|
|
106
|
+
eligible: true,
|
|
107
|
+
condition: context.condition,
|
|
108
|
+
nested: context.nested,
|
|
109
|
+
pseudo: classification.pseudo,
|
|
110
|
+
selector: classification.strippedSelector,
|
|
111
|
+
atomKeys: collected.atomKeys,
|
|
112
|
+
atomHashes: collected.atomHashes,
|
|
113
|
+
decisions: collected.decisions,
|
|
114
|
+
});
|
|
115
|
+
recordShorthandSkip(skips, file.filePath, classification.strippedSelector, collected.shorthandConflict);
|
|
116
|
+
}
|
|
117
|
+
if (!anyEligible)
|
|
118
|
+
rules.push(ineligibleRuleInfo(context));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (rule.type !== 'style')
|
|
122
|
+
return;
|
|
123
|
+
const resolved = rule.value.selectors.flatMap((selector) => context.resolveAll(selector));
|
|
124
|
+
const classifications = classifyEligibleGroup(resolved);
|
|
125
|
+
if (!classifications) {
|
|
126
|
+
rules.push(ineligibleRuleInfo(context));
|
|
127
|
+
skips.push({
|
|
128
|
+
filePath: file.filePath,
|
|
129
|
+
selector: printSelectorList(resolved),
|
|
130
|
+
reason: skipReasonForSelectors(resolved),
|
|
131
|
+
});
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (const classification of classifications) {
|
|
135
|
+
const collected = collectAtoms(rule.value.declarations, context, classification, atoms, taken, debugNames);
|
|
136
|
+
rules.push({
|
|
137
|
+
eligible: true,
|
|
138
|
+
condition: context.condition,
|
|
139
|
+
nested: context.nested,
|
|
140
|
+
pseudo: classification.pseudo,
|
|
141
|
+
selector: classification.strippedSelector,
|
|
142
|
+
atomKeys: collected.atomKeys,
|
|
143
|
+
atomHashes: collected.atomHashes,
|
|
144
|
+
decisions: collected.decisions,
|
|
145
|
+
});
|
|
146
|
+
recordShorthandSkip(skips, file.filePath, classification.strippedSelector, collected.shorthandConflict);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function scanFile(file, atoms, taken, skips, debugNames) {
|
|
150
|
+
const tracker = new RuleContextTracker();
|
|
151
|
+
const rules = [];
|
|
152
|
+
transform({
|
|
153
|
+
filename: file.filePath,
|
|
154
|
+
code: Buffer.from(file.code, 'utf8'),
|
|
155
|
+
visitor: {
|
|
156
|
+
Rule(rule) {
|
|
157
|
+
const context = tracker.enter(rule);
|
|
158
|
+
if (!context)
|
|
159
|
+
return;
|
|
160
|
+
scanStyleLikeRule(rule, context, atoms, taken, rules, skips, file, debugNames);
|
|
161
|
+
},
|
|
162
|
+
RuleExit(rule) {
|
|
163
|
+
tracker.exit(rule);
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
return { filePath: file.filePath, rules };
|
|
168
|
+
}
|
|
169
|
+
export function scanFiles(files, options = {}) {
|
|
170
|
+
const atoms = new Map();
|
|
171
|
+
const taken = new Set();
|
|
172
|
+
const skips = [];
|
|
173
|
+
const debugNames = options.debugNames === true;
|
|
174
|
+
const scannedFiles = files.map((file) => scanFile(file, atoms, taken, skips, debugNames));
|
|
175
|
+
return { atoms, files: scannedFiles, skips };
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=scan.js.map
|
package/dist/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rules for deciding whether a StyleRule's selector is eligible for
|
|
3
|
+
* atomization, per GUIDE.md "What selectors are supported".
|
|
4
|
+
*/
|
|
5
|
+
import type { Selector, SelectorList } from 'lightningcss';
|
|
6
|
+
import type { AtomPseudo, SkipReason } from './types.js';
|
|
7
|
+
export interface SelectorClassification {
|
|
8
|
+
eligible: boolean;
|
|
9
|
+
/** The simple trailing pseudo carried by this selector, if any. */
|
|
10
|
+
pseudo: AtomPseudo | null;
|
|
11
|
+
/** The selector with any trailing simple pseudo removed. */
|
|
12
|
+
strippedSelector: Selector;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Classifies a single (non-grouped) selector. CSS Modules only allows
|
|
16
|
+
* `composes` on a single local class, so combinators, extra classes,
|
|
17
|
+
* elements, and attributes are rejected. A trailing simple pseudo
|
|
18
|
+
* (`.button:hover`) is still eligible; the pseudo is hoisted onto the atom.
|
|
19
|
+
*/
|
|
20
|
+
export declare function classifySelector(selector: Selector): SelectorClassification;
|
|
21
|
+
/**
|
|
22
|
+
* Resolves a nested selector against its parent. `&` is replaced with the
|
|
23
|
+
* parent selector; a nested selector with no `&` is treated as a descendant.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveNesting(parent: Selector, nested: Selector): Selector;
|
|
26
|
+
/** Comma-separated selector groups (`.a, .b { ... }`) can be split when every selector is eligible. */
|
|
27
|
+
export declare function isGroupedSelectorList(selectorList: SelectorList): boolean;
|
|
28
|
+
/** Classifies every selector in a list. Returns null if any selector is ineligible. */
|
|
29
|
+
export declare function classifyEligibleGroup(selectors: SelectorList): SelectorClassification[] | null;
|
|
30
|
+
export declare function skipReasonForSelector(selector: Selector): SkipReason;
|
|
31
|
+
export declare function skipReasonForSelectors(selectors: SelectorList): SkipReason;
|
|
32
|
+
export declare function printSelectorList(selectors: SelectorList): string;
|
|
33
|
+
export declare function selectorKey(selector: Selector): string;
|
|
34
|
+
export declare function selectorsEqual(a: Selector, b: Selector): boolean;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { transform } from 'lightningcss';
|
|
2
|
+
/**
|
|
3
|
+
* Fields on a pseudo-class/element component that indicate it takes an
|
|
4
|
+
* argument (a nested selector, an nth-child formula, a language tag, etc).
|
|
5
|
+
* Anything with one of these is a "functional" pseudo and can't be safely
|
|
6
|
+
* hoisted onto a shared atomic class - see GUIDE.md "What selectors are supported".
|
|
7
|
+
* Rather than hand-listing which pseudo kinds are "simple", this is derived
|
|
8
|
+
* structurally from whatever lightningcss actually parsed: a pseudo with none
|
|
9
|
+
* of these argument fields is simple, regardless of its kind name.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Fields that are always present on a parsed pseudo (or harmless extras
|
|
13
|
+
* like a vendor prefix / custom name) and do not mean the pseudo takes
|
|
14
|
+
* arguments. Anything else — `selectors`, `a`/`b`, `arguments`, etc. —
|
|
15
|
+
* makes it functional and ineligible to hoist.
|
|
16
|
+
*
|
|
17
|
+
* Do not treat `type` as an argument field: every LightningCSS selector
|
|
18
|
+
* component has `type: "pseudo-class" | "pseudo-element"`.
|
|
19
|
+
*/
|
|
20
|
+
const SIMPLE_PSEUDO_KEYS = new Set(['type', 'kind', 'vendorPrefix', 'name']);
|
|
21
|
+
function isPseudoComponent(component) {
|
|
22
|
+
return (component.type === 'pseudo-class' || component.type === 'pseudo-element');
|
|
23
|
+
}
|
|
24
|
+
/** True for a pseudo-class/element with no functional arguments, e.g. `:hover` or `::before`, but not `:not(...)` or `:nth-child(...)`. */
|
|
25
|
+
function isSimplePseudo(component) {
|
|
26
|
+
return Object.keys(component).every((key) => SIMPLE_PSEUDO_KEYS.has(key));
|
|
27
|
+
}
|
|
28
|
+
const NOT_ELIGIBLE = {
|
|
29
|
+
eligible: false,
|
|
30
|
+
pseudo: null,
|
|
31
|
+
strippedSelector: [],
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Classifies a single (non-grouped) selector. CSS Modules only allows
|
|
35
|
+
* `composes` on a single local class, so combinators, extra classes,
|
|
36
|
+
* elements, and attributes are rejected. A trailing simple pseudo
|
|
37
|
+
* (`.button:hover`) is still eligible; the pseudo is hoisted onto the atom.
|
|
38
|
+
*/
|
|
39
|
+
export function classifySelector(selector) {
|
|
40
|
+
if (selector.length === 0)
|
|
41
|
+
return NOT_ELIGIBLE;
|
|
42
|
+
let classCount = 0;
|
|
43
|
+
let trailingPseudo = null;
|
|
44
|
+
for (let index = 0; index < selector.length; index++) {
|
|
45
|
+
const component = selector[index];
|
|
46
|
+
if (!component)
|
|
47
|
+
return NOT_ELIGIBLE;
|
|
48
|
+
if (component.type === 'class') {
|
|
49
|
+
classCount += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const isTrailing = index === selector.length - 1;
|
|
53
|
+
if (isTrailing &&
|
|
54
|
+
isPseudoComponent(component) &&
|
|
55
|
+
isSimplePseudo(component)) {
|
|
56
|
+
trailingPseudo = component;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
return NOT_ELIGIBLE;
|
|
60
|
+
}
|
|
61
|
+
if (classCount !== 1)
|
|
62
|
+
return NOT_ELIGIBLE;
|
|
63
|
+
return {
|
|
64
|
+
eligible: true,
|
|
65
|
+
pseudo: trailingPseudo,
|
|
66
|
+
strippedSelector: trailingPseudo ? selector.slice(0, -1) : selector,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Resolves a nested selector against its parent. `&` is replaced with the
|
|
71
|
+
* parent selector; a nested selector with no `&` is treated as a descendant.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveNesting(parent, nested) {
|
|
74
|
+
if (nested.some((component) => component.type === 'nesting')) {
|
|
75
|
+
return nested.flatMap((component) => component.type === 'nesting' ? parent : [component]);
|
|
76
|
+
}
|
|
77
|
+
return [...parent, { type: 'combinator', value: 'descendant' }, ...nested];
|
|
78
|
+
}
|
|
79
|
+
/** Comma-separated selector groups (`.a, .b { ... }`) can be split when every selector is eligible. */
|
|
80
|
+
export function isGroupedSelectorList(selectorList) {
|
|
81
|
+
return selectorList.length > 1;
|
|
82
|
+
}
|
|
83
|
+
/** Classifies every selector in a list. Returns null if any selector is ineligible. */
|
|
84
|
+
export function classifyEligibleGroup(selectors) {
|
|
85
|
+
const items = selectors.map((selector) => classifySelector(selector));
|
|
86
|
+
if (items.length === 0 || items.some((item) => !item.eligible))
|
|
87
|
+
return null;
|
|
88
|
+
return items;
|
|
89
|
+
}
|
|
90
|
+
export function skipReasonForSelector(selector) {
|
|
91
|
+
let classCount = 0;
|
|
92
|
+
let simplePseudoCount = 0;
|
|
93
|
+
let hasCombinator = false;
|
|
94
|
+
let hasFunctionalPseudo = false;
|
|
95
|
+
for (const component of selector) {
|
|
96
|
+
if (component.type === 'combinator') {
|
|
97
|
+
hasCombinator = true;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (component.type === 'class') {
|
|
101
|
+
classCount += 1;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (component.type === 'nesting')
|
|
105
|
+
continue;
|
|
106
|
+
if (isPseudoComponent(component)) {
|
|
107
|
+
if (isSimplePseudo(component))
|
|
108
|
+
simplePseudoCount += 1;
|
|
109
|
+
else
|
|
110
|
+
hasFunctionalPseudo = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (hasCombinator)
|
|
114
|
+
return 'combinator';
|
|
115
|
+
if (hasFunctionalPseudo)
|
|
116
|
+
return 'functional-pseudo';
|
|
117
|
+
if (simplePseudoCount > 1)
|
|
118
|
+
return 'chained-pseudo';
|
|
119
|
+
if (classCount > 1)
|
|
120
|
+
return 'compound';
|
|
121
|
+
return 'element';
|
|
122
|
+
}
|
|
123
|
+
export function skipReasonForSelectors(selectors) {
|
|
124
|
+
if (selectors.length > 1)
|
|
125
|
+
return 'mixed-group';
|
|
126
|
+
return skipReasonForSelector(selectors[0] ?? []);
|
|
127
|
+
}
|
|
128
|
+
export function printSelectorList(selectors) {
|
|
129
|
+
if (selectors.length === 0)
|
|
130
|
+
return '';
|
|
131
|
+
const result = transform({
|
|
132
|
+
filename: 'selector.css',
|
|
133
|
+
code: Buffer.from('._{color:red}'),
|
|
134
|
+
visitor: {
|
|
135
|
+
StyleSheetExit(sheet) {
|
|
136
|
+
const rule = sheet.rules[0];
|
|
137
|
+
if (rule?.type === 'style')
|
|
138
|
+
rule.value.selectors = selectors;
|
|
139
|
+
return sheet;
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
const css = Buffer.from(result.code).toString('utf8');
|
|
144
|
+
const match = /^([^{]+)\{/.exec(css);
|
|
145
|
+
return (match?.[1] ?? '')
|
|
146
|
+
.trim()
|
|
147
|
+
.replace(/\s*,\s*/g, ', ')
|
|
148
|
+
.replace(/\s+/g, ' ');
|
|
149
|
+
}
|
|
150
|
+
export function selectorKey(selector) {
|
|
151
|
+
return JSON.stringify(selector);
|
|
152
|
+
}
|
|
153
|
+
export function selectorsEqual(a, b) {
|
|
154
|
+
return selectorKey(a) === selectorKey(b);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=selector-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-utils.js","sourceRoot":"","sources":["../src/selector-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Properties in one rule that are unsafe to atomize because they write the
|
|
3
|
+
* same longhand: a shorthand plus one of its longhands, or two shorthands
|
|
4
|
+
* that overlap (e.g. `border-width` + `border-top`). Sibling longhands
|
|
5
|
+
* (`font-size` + `font-family`) do not overlap and are safe.
|
|
6
|
+
*/
|
|
7
|
+
export declare function findShorthandConflicts(properties: readonly string[]): Set<string>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shorthand/longhand property groupings, derived from MDN's `mdn-data`
|
|
3
|
+
* dataset (the same data browsers and MDN docs are generated from) rather
|
|
4
|
+
* than a hand-maintained list. If a rule declares a shorthand alongside one
|
|
5
|
+
* of its own longhands, neither is safe to atomize (see GUIDE.md "Shorthand
|
|
6
|
+
* and longhand").
|
|
7
|
+
*/
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const cssProperties = require('mdn-data/css/properties.json');
|
|
11
|
+
function listedLonghands(info) {
|
|
12
|
+
const names = new Set();
|
|
13
|
+
for (const field of [info.initial, info.computed]) {
|
|
14
|
+
if (!Array.isArray(field))
|
|
15
|
+
continue;
|
|
16
|
+
for (const longhand of field)
|
|
17
|
+
names.add(longhand);
|
|
18
|
+
}
|
|
19
|
+
return [...names];
|
|
20
|
+
}
|
|
21
|
+
/** Direct + nested longhands for every MDN shorthand. */
|
|
22
|
+
const shorthandLonghands = new Map();
|
|
23
|
+
function collectLonghands(property, seen) {
|
|
24
|
+
const cached = shorthandLonghands.get(property);
|
|
25
|
+
if (cached && seen.size === 0)
|
|
26
|
+
return cached;
|
|
27
|
+
const info = cssProperties[property];
|
|
28
|
+
if (!info)
|
|
29
|
+
return new Set();
|
|
30
|
+
const children = listedLonghands(info);
|
|
31
|
+
if (children.length === 0)
|
|
32
|
+
return new Set();
|
|
33
|
+
const longhands = new Set();
|
|
34
|
+
for (const child of children) {
|
|
35
|
+
if (seen.has(child))
|
|
36
|
+
continue;
|
|
37
|
+
seen.add(child);
|
|
38
|
+
longhands.add(child);
|
|
39
|
+
for (const nested of collectLonghands(child, seen))
|
|
40
|
+
longhands.add(nested);
|
|
41
|
+
}
|
|
42
|
+
return longhands;
|
|
43
|
+
}
|
|
44
|
+
for (const property of Object.keys(cssProperties)) {
|
|
45
|
+
const longhands = collectLonghands(property, new Set());
|
|
46
|
+
if (longhands.size > 0)
|
|
47
|
+
shorthandLonghands.set(property, longhands);
|
|
48
|
+
}
|
|
49
|
+
/** Longhands a property sets: itself if it is a longhand, else its expansion. */
|
|
50
|
+
function coverage(property) {
|
|
51
|
+
return shorthandLonghands.get(property) ?? new Set([property]);
|
|
52
|
+
}
|
|
53
|
+
function setsOverlap(left, right) {
|
|
54
|
+
for (const value of left) {
|
|
55
|
+
if (right.has(value))
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Properties in one rule that are unsafe to atomize because they write the
|
|
62
|
+
* same longhand: a shorthand plus one of its longhands, or two shorthands
|
|
63
|
+
* that overlap (e.g. `border-width` + `border-top`). Sibling longhands
|
|
64
|
+
* (`font-size` + `font-family`) do not overlap and are safe.
|
|
65
|
+
*/
|
|
66
|
+
export function findShorthandConflicts(properties) {
|
|
67
|
+
const conflicts = new Set();
|
|
68
|
+
for (let i = 0; i < properties.length; i++) {
|
|
69
|
+
const left = properties[i];
|
|
70
|
+
if (left === undefined)
|
|
71
|
+
continue;
|
|
72
|
+
const leftCoverage = coverage(left);
|
|
73
|
+
for (let j = i + 1; j < properties.length; j++) {
|
|
74
|
+
const right = properties[j];
|
|
75
|
+
if (right === undefined)
|
|
76
|
+
continue;
|
|
77
|
+
if (!setsOverlap(leftCoverage, coverage(right)))
|
|
78
|
+
continue;
|
|
79
|
+
conflicts.add(left);
|
|
80
|
+
conflicts.add(right);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return conflicts;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=shorthand-groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shorthand-groups.js","sourceRoot":"","sources":["../src/shorthand-groups.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect an `atomic: skip` CSS comment from source text. LightningCSS drops
|
|
3
|
+
* comments from the AST, so we look next to the rule's source location.
|
|
4
|
+
*/
|
|
5
|
+
import type { Location2 } from 'lightningcss';
|
|
6
|
+
export declare function hasAtomicSkipComment(code: string, loc: Location2): boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const SKIP_BODY = /^atomic:\s*skip$/i;
|
|
2
|
+
function locOffset(code, loc) {
|
|
3
|
+
let line = 0;
|
|
4
|
+
let index = 0;
|
|
5
|
+
while (line < loc.line && index < code.length) {
|
|
6
|
+
if (code[index] === '\n')
|
|
7
|
+
line += 1;
|
|
8
|
+
index += 1;
|
|
9
|
+
}
|
|
10
|
+
return Math.min(code.length, index + Math.max(loc.column, 1) - 1);
|
|
11
|
+
}
|
|
12
|
+
function isSkipBody(body) {
|
|
13
|
+
return SKIP_BODY.test(body.trim());
|
|
14
|
+
}
|
|
15
|
+
function commentBefore(code, offset) {
|
|
16
|
+
let index = offset - 1;
|
|
17
|
+
while (index >= 0 && /\s/.test(code[index] ?? ''))
|
|
18
|
+
index -= 1;
|
|
19
|
+
if (index < 1 || code[index] !== '/' || code[index - 1] !== '*')
|
|
20
|
+
return null;
|
|
21
|
+
const start = code.lastIndexOf('/*', index - 1);
|
|
22
|
+
if (start === -1)
|
|
23
|
+
return null;
|
|
24
|
+
return code.slice(start + 2, index - 1);
|
|
25
|
+
}
|
|
26
|
+
function firstBlockComment(code, offset) {
|
|
27
|
+
const open = code.indexOf('{', offset);
|
|
28
|
+
if (open === -1)
|
|
29
|
+
return null;
|
|
30
|
+
let index = open + 1;
|
|
31
|
+
while (index < code.length && /\s/.test(code[index] ?? ''))
|
|
32
|
+
index += 1;
|
|
33
|
+
if (code.slice(index, index + 2) !== '/*')
|
|
34
|
+
return null;
|
|
35
|
+
const close = code.indexOf('*/', index + 2);
|
|
36
|
+
if (close === -1)
|
|
37
|
+
return null;
|
|
38
|
+
return code.slice(index + 2, close);
|
|
39
|
+
}
|
|
40
|
+
export function hasAtomicSkipComment(code, loc) {
|
|
41
|
+
const offset = locOffset(code, loc);
|
|
42
|
+
const before = commentBefore(code, offset);
|
|
43
|
+
if (before !== null && isSkipBody(before))
|
|
44
|
+
return true;
|
|
45
|
+
const inside = firstBlockComment(code, offset);
|
|
46
|
+
return inside !== null && isSkipBody(inside);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=skip-comment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skip-comment.js","sourceRoot":"","sources":["../src/skip-comment.ts"],"names":[],"mappings":"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"}
|