UNPKG

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