1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.isValidClassName = exports.isCSSVarProp = exports.generateScopedCSSVar = exports.getAlias = exports.getSourcePath = exports.getDeclStylable = exports.findRule = exports.findDeclaration = exports.removeUnusedRules = exports.createSubsetAst = exports.mergeRules = exports.scopeSelector = exports.transformMatchesOnRule = exports.expandCustomSelectors = exports.isValidDeclaration = exports.CUSTOM_SELECTOR_RE = void 0;
|
7 | const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
|
8 | const path_1 = require("path");
|
9 | const postcss_1 = __importDefault(require("postcss"));
|
10 | const selector_utils_1 = require("./selector-utils");
|
11 | const stylable_value_parsers_1 = require("./stylable-value-parsers");
|
12 | const replaceRuleSelector = require('postcss-selector-matches/dist/replaceRuleSelector');
|
13 | exports.CUSTOM_SELECTOR_RE = /:--[\w-]+/g;
|
14 | function isValidDeclaration(decl) {
|
15 | return typeof decl.value === 'string';
|
16 | }
|
17 | exports.isValidDeclaration = isValidDeclaration;
|
18 | function expandCustomSelectors(rule, customSelectors, diagnostics) {
|
19 | if (rule.selector.includes(':--')) {
|
20 | rule.selector = rule.selector.replace(exports.CUSTOM_SELECTOR_RE, (extensionName, _matches, selector) => {
|
21 | if (!customSelectors[extensionName] && diagnostics) {
|
22 | diagnostics.warn(rule, `The selector '${rule.selector}' is undefined`, {
|
23 | word: rule.selector,
|
24 | });
|
25 | return selector;
|
26 | }
|
27 |
|
28 | return ':matches(' + customSelectors[extensionName] + ')';
|
29 | });
|
30 | return (rule.selector = transformMatchesOnRule(rule, false));
|
31 | }
|
32 | return rule.selector;
|
33 | }
|
34 | exports.expandCustomSelectors = expandCustomSelectors;
|
35 | function transformMatchesOnRule(rule, lineBreak) {
|
36 | return replaceRuleSelector(rule, { lineBreak });
|
37 | }
|
38 | exports.transformMatchesOnRule = transformMatchesOnRule;
|
39 | function scopeSelector(scopeSelectorRule, targetSelectorRule, rootScopeLevel = false) {
|
40 | const scopingSelectorAst = selector_utils_1.parseSelector(scopeSelectorRule);
|
41 | const targetSelectorAst = selector_utils_1.parseSelector(targetSelectorRule);
|
42 | const nodes = [];
|
43 | targetSelectorAst.nodes.forEach((targetSelector) => {
|
44 | scopingSelectorAst.nodes.forEach((scopingSelector) => {
|
45 | const outputSelector = lodash_clonedeep_1.default(targetSelector);
|
46 | outputSelector.before = scopingSelector.before || outputSelector.before;
|
47 | const first = outputSelector.nodes[0];
|
48 | const parentRef = first.type === 'invalid' && first.value === '&';
|
49 | const globalSelector = first.type === 'nested-pseudo-class' && first.name === 'global';
|
50 | const startsWithScoping = rootScopeLevel
|
51 | ? scopingSelector.nodes.every((node, i) => {
|
52 | const o = outputSelector.nodes[i];
|
53 | for (const k in node) {
|
54 | if (node[k] !== o[k]) {
|
55 | return false;
|
56 | }
|
57 | }
|
58 | return true;
|
59 | })
|
60 | : false;
|
61 | if (first &&
|
62 | first.type !== 'spacing' &&
|
63 | !parentRef &&
|
64 | !startsWithScoping &&
|
65 | !globalSelector) {
|
66 | outputSelector.nodes.unshift(...lodash_clonedeep_1.default(scopingSelector.nodes), {
|
67 | type: 'spacing',
|
68 | value: ' ',
|
69 | });
|
70 | }
|
71 | selector_utils_1.traverseNode(outputSelector, (node, i, nodes) => {
|
72 | if (node.type === 'invalid' && node.value === '&') {
|
73 | nodes.splice(i, 1, ...lodash_clonedeep_1.default(scopingSelector.nodes));
|
74 | }
|
75 | });
|
76 | nodes.push(outputSelector);
|
77 | });
|
78 | });
|
79 | scopingSelectorAst.nodes = nodes;
|
80 | return {
|
81 | selector: selector_utils_1.stringifySelector(scopingSelectorAst),
|
82 | selectorAst: scopingSelectorAst,
|
83 | };
|
84 | }
|
85 | exports.scopeSelector = scopeSelector;
|
86 | function mergeRules(mixinAst, rule) {
|
87 | let mixinRoot = null;
|
88 | mixinAst.walkRules((mixinRule) => {
|
89 | if (mixinRule.selector === '&' && !mixinRoot) {
|
90 | mixinRoot = mixinRule;
|
91 | }
|
92 | else {
|
93 | const parentRule = mixinRule.parent;
|
94 | if (parentRule.type === 'atrule' && parentRule.name === 'keyframes') {
|
95 | return;
|
96 | }
|
97 | const out = scopeSelector(rule.selector, mixinRule.selector);
|
98 | mixinRule.selector = out.selector;
|
99 |
|
100 | }
|
101 | });
|
102 | if (mixinAst.nodes) {
|
103 | let nextRule = rule;
|
104 | let mixinEntry = null;
|
105 | rule.walkDecls(stylable_value_parsers_1.valueMapping.mixin, (decl) => {
|
106 | mixinEntry = decl;
|
107 | });
|
108 | if (!mixinEntry) {
|
109 | throw rule.error('missing mixin entry');
|
110 | }
|
111 |
|
112 | mixinAst.nodes.slice().forEach((node) => {
|
113 | if (node === mixinRoot) {
|
114 | node.walkDecls((node) => {
|
115 | rule.insertBefore(mixinEntry, node);
|
116 | });
|
117 | }
|
118 | else if (node.type === 'decl') {
|
119 | rule.insertBefore(mixinEntry, node);
|
120 | }
|
121 | else if (node.type === 'rule' || node.type === 'atrule') {
|
122 | if (rule.parent.last === nextRule) {
|
123 | rule.parent.append(node);
|
124 | }
|
125 | else {
|
126 | rule.parent.insertAfter(nextRule, node);
|
127 | }
|
128 | nextRule = node;
|
129 | }
|
130 | });
|
131 | }
|
132 | return rule;
|
133 | }
|
134 | exports.mergeRules = mergeRules;
|
135 | function createSubsetAst(root, selectorPrefix, mixinTarget, isRoot = false) {
|
136 |
|
137 | const prefixType = selector_utils_1.parseSelector(selectorPrefix).nodes[0].nodes[0];
|
138 | const containsPrefix = containsMatchInFirstChunk.bind(null, prefixType);
|
139 | const mixinRoot = mixinTarget ? mixinTarget : postcss_1.default.root();
|
140 | root.nodes.forEach((node) => {
|
141 | if (node.type === 'rule') {
|
142 | const ast = isRoot
|
143 | ? scopeSelector(selectorPrefix, node.selector, true).selectorAst
|
144 | : selector_utils_1.parseSelector(node.selector);
|
145 | const matchesSelectors = isRoot
|
146 | ? ast.nodes
|
147 | : ast.nodes.filter((node) => containsPrefix(node));
|
148 | if (matchesSelectors.length) {
|
149 | const selector = selector_utils_1.stringifySelector({
|
150 | ...ast,
|
151 | nodes: matchesSelectors.map((selectorNode) => {
|
152 | if (!isRoot) {
|
153 | selector_utils_1.fixChunkOrdering(selectorNode, prefixType);
|
154 | }
|
155 | return destructiveReplaceNode(selectorNode, prefixType, {
|
156 | type: 'invalid',
|
157 | value: '&',
|
158 | });
|
159 | }),
|
160 | });
|
161 | mixinRoot.append(node.clone({ selector }));
|
162 | }
|
163 | }
|
164 | else if (node.type === 'atrule') {
|
165 | if (node.name === 'media') {
|
166 | const mediaSubset = createSubsetAst(node, selectorPrefix, postcss_1.default.atRule({
|
167 | params: node.params,
|
168 | name: node.name,
|
169 | }), isRoot);
|
170 | if (mediaSubset.nodes) {
|
171 | mixinRoot.append(mediaSubset);
|
172 | }
|
173 | }
|
174 | else if (isRoot) {
|
175 | mixinRoot.append(node.clone());
|
176 | }
|
177 | }
|
178 | else {
|
179 |
|
180 | }
|
181 | });
|
182 | return mixinRoot;
|
183 | }
|
184 | exports.createSubsetAst = createSubsetAst;
|
185 | function removeUnusedRules(ast, meta, _import, usedFiles, resolvePath) {
|
186 | const isUnusedImport = !usedFiles.includes(_import.from);
|
187 | if (isUnusedImport) {
|
188 | const symbols = Object.keys(_import.named).concat(_import.defaultExport);
|
189 | ast.walkRules((rule) => {
|
190 | let shouldOutput = true;
|
191 | selector_utils_1.traverseNode(rule.selectorAst, (node) => {
|
192 |
|
193 | if (symbols.includes(node.name)) {
|
194 | return (shouldOutput = false);
|
195 | }
|
196 | const symbol = meta.mappedSymbols[node.name];
|
197 | if (symbol && (symbol._kind === 'class' || symbol._kind === 'element')) {
|
198 | let extend = symbol[stylable_value_parsers_1.valueMapping.extends] || symbol.alias;
|
199 | extend = extend && extend._kind !== 'import' ? extend.alias || extend : extend;
|
200 | if (extend &&
|
201 | extend._kind === 'import' &&
|
202 | !usedFiles.includes(resolvePath(meta.source, extend.import.from))) {
|
203 | return (shouldOutput = false);
|
204 | }
|
205 | }
|
206 | return undefined;
|
207 | });
|
208 |
|
209 | if (!shouldOutput && rule.selectorAst.nodes.length <= 1) {
|
210 | rule.remove();
|
211 | }
|
212 | });
|
213 | }
|
214 | }
|
215 | exports.removeUnusedRules = removeUnusedRules;
|
216 | function findDeclaration(importNode, test) {
|
217 | const fromIndex = importNode.rule.nodes.findIndex(test);
|
218 | return importNode.rule.nodes[fromIndex];
|
219 | }
|
220 | exports.findDeclaration = findDeclaration;
|
221 |
|
222 | function findRule(root, selector, test = (statement) => statement.prop === stylable_value_parsers_1.valueMapping.extends) {
|
223 | let found = null;
|
224 | root.walkRules(selector, (rule) => {
|
225 | const declarationIndex = rule.nodes ? rule.nodes.findIndex(test) : -1;
|
226 | if (rule.isSimpleSelector && !!~declarationIndex) {
|
227 | found = rule.nodes[declarationIndex];
|
228 | }
|
229 | });
|
230 | return found;
|
231 | }
|
232 | exports.findRule = findRule;
|
233 | function getDeclStylable(decl) {
|
234 | if (decl.stylable) {
|
235 | return decl.stylable;
|
236 | }
|
237 | else {
|
238 | decl.stylable = decl.stylable ? decl.stylable : { sourceValue: '' };
|
239 | return decl.stylable;
|
240 | }
|
241 | }
|
242 | exports.getDeclStylable = getDeclStylable;
|
243 | function destructiveReplaceNode(ast, matchNode, replacementNode) {
|
244 | selector_utils_1.traverseNode(ast, (node) => {
|
245 | if (selector_utils_1.isNodeMatch(node, matchNode)) {
|
246 | node.type = 'selector';
|
247 | node.nodes = [replacementNode];
|
248 | }
|
249 | });
|
250 | return ast;
|
251 | }
|
252 | function containsMatchInFirstChunk(prefixType, selectorNode) {
|
253 | let isMatch = false;
|
254 | selector_utils_1.traverseNode(selectorNode, (node) => {
|
255 | if (node.type === 'operator' || node.type === 'spacing') {
|
256 | return false;
|
257 | }
|
258 | else if (node.type === 'nested-pseudo-class') {
|
259 | return true;
|
260 | }
|
261 | else if (selector_utils_1.isNodeMatch(node, prefixType)) {
|
262 | isMatch = true;
|
263 | return false;
|
264 | }
|
265 | return undefined;
|
266 | });
|
267 | return isMatch;
|
268 | }
|
269 | function getSourcePath(root, diagnostics) {
|
270 | const source = (root.source && root.source.input.file) || '';
|
271 | if (!source) {
|
272 | diagnostics.error(root, 'missing source filename');
|
273 | }
|
274 | else if (!path_1.isAbsolute(source)) {
|
275 | throw new Error('source filename is not absolute path: "' + source + '"');
|
276 | }
|
277 | return source;
|
278 | }
|
279 | exports.getSourcePath = getSourcePath;
|
280 | function getAlias(symbol) {
|
281 | if (symbol._kind === 'class' || symbol._kind === 'element') {
|
282 | if (!symbol[stylable_value_parsers_1.valueMapping.extends]) {
|
283 | return symbol.alias;
|
284 | }
|
285 | }
|
286 | return undefined;
|
287 | }
|
288 | exports.getAlias = getAlias;
|
289 | function generateScopedCSSVar(namespace, varName) {
|
290 | return `--${namespace}-${varName}`;
|
291 | }
|
292 | exports.generateScopedCSSVar = generateScopedCSSVar;
|
293 | function isCSSVarProp(value) {
|
294 | return value.startsWith('--');
|
295 | }
|
296 | exports.isCSSVarProp = isCSSVarProp;
|
297 | function isValidClassName(className) {
|
298 | const test = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/g;
|
299 | return !!className.match(test);
|
300 | }
|
301 | exports.isValidClassName = isValidClassName;
|
302 |
|
\ | No newline at end of file |