UNPKG

13.2 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.createWarningRule = exports.isCompRoot = exports.isChildOfAtRule = exports.fixChunkOrdering = exports.matchSelectorTarget = exports.filterChunkNodesByType = exports.separateChunks = exports.getOriginDefinition = exports.separateChunks2 = exports.mergeChunks = exports.isNodeMatch = exports.matchAtMedia = exports.matchAtKeyframes = exports.isImport = exports.isSimpleSelector = exports.createSimpleSelectorChecker = exports.isRootValid = exports.isGlobal = exports.createChecker = exports.traverseNode = exports.stringifySelector = exports.parseSelector = void 0;
26const postcss = __importStar(require("postcss"));
27const css_selector_tokenizer_1 = __importDefault(require("css-selector-tokenizer"));
28const stylable_value_parsers_1 = require("./stylable-value-parsers");
29function parseSelector(selector) {
30 return css_selector_tokenizer_1.default.parse(selector);
31}
32exports.parseSelector = parseSelector;
33function stringifySelector(ast) {
34 return css_selector_tokenizer_1.default.stringify(ast);
35}
36exports.stringifySelector = stringifySelector;
37function traverseNode(node, visitor, index = 0, nodes = [node]) {
38 if (!node) {
39 return;
40 }
41 const cNodes = node.nodes;
42 let doNext = visitor(node, index, nodes);
43 if (doNext === false) {
44 return false;
45 }
46 if (doNext === true) {
47 return true;
48 }
49 if (cNodes) {
50 for (let i = 0; i < node.nodes.length; i++) {
51 doNext = traverseNode(node.nodes[i], visitor, i, node.nodes);
52 if (doNext === false) {
53 return false;
54 }
55 }
56 }
57}
58exports.traverseNode = traverseNode;
59function createChecker(types) {
60 return () => {
61 let index = 0;
62 return (node) => {
63 const matcher = types[index];
64 if (Array.isArray(matcher)) {
65 return matcher.includes(node.type);
66 }
67 else if (matcher !== node.type) {
68 return false;
69 }
70 if (types[index] !== node.type) {
71 return false;
72 }
73 index++;
74 return true;
75 };
76 };
77}
78exports.createChecker = createChecker;
79function isGlobal(node) {
80 return node.type === 'nested-pseudo-class' && node.name === 'global';
81}
82exports.isGlobal = isGlobal;
83function isRootValid(ast, rootName) {
84 let isValid = true;
85 traverseNode(ast, (node, index, nodes) => {
86 if (node.type === 'nested-pseudo-class') {
87 return true;
88 }
89 if (node.type === 'class' && node.name === rootName) {
90 let isLastScopeGlobal = false;
91 for (let i = 0; i < index; i++) {
92 const part = nodes[i];
93 if (isGlobal(part)) {
94 isLastScopeGlobal = true;
95 }
96 if (part.type === 'spacing' && !isLastScopeGlobal) {
97 isValid = false;
98 }
99 if (part.type === 'element' || (part.type === 'class' && part.value !== 'root')) {
100 isLastScopeGlobal = false;
101 }
102 }
103 }
104 return undefined;
105 });
106 return isValid;
107}
108exports.isRootValid = isRootValid;
109exports.createSimpleSelectorChecker = createChecker([
110 'selectors',
111 'selector',
112 ['element', 'class'],
113]);
114function isSimpleSelector(selectorAst) {
115 const isSimpleSelectorASTNode = exports.createSimpleSelectorChecker();
116 const isSimple = traverseNode(selectorAst, (node) => isSimpleSelectorASTNode(node) !== false /*stop on complex selector */);
117 return isSimple;
118}
119exports.isSimpleSelector = isSimpleSelector;
120function isImport(ast) {
121 const selectors = ast.nodes[0];
122 const selector = selectors && selectors.nodes[0];
123 return selector && selector.type === 'pseudo-class' && selector.name === 'import';
124}
125exports.isImport = isImport;
126function matchAtKeyframes(selector) {
127 return selector.match(/^@keyframes\s*(.*)/);
128}
129exports.matchAtKeyframes = matchAtKeyframes;
130function matchAtMedia(selector) {
131 return selector.match(/^@media\s*(.*)/);
132}
133exports.matchAtMedia = matchAtMedia;
134function isNodeMatch(nodeA, nodeB) {
135 return nodeA.type === nodeB.type && nodeA.name === nodeB.name;
136}
137exports.isNodeMatch = isNodeMatch;
138function mergeChunks(chunks) {
139 const ast = { type: 'selectors', nodes: [] };
140 let i = 0;
141 for (const selectorChunks of chunks) {
142 ast.nodes[i] = { type: 'selector', nodes: [] };
143 for (const chunk of selectorChunks) {
144 if (chunk.type !== 'selector') {
145 ast.nodes[i].nodes.push(chunk);
146 }
147 else {
148 ast.nodes[i].before = chunk.before;
149 }
150 for (const node of chunk.nodes) {
151 ast.nodes[i].nodes.push(node);
152 }
153 }
154 i++;
155 }
156 return ast;
157}
158exports.mergeChunks = mergeChunks;
159function separateChunks2(selectorNode) {
160 const selectors = [];
161 selectorNode.nodes.map(({ nodes, before }) => {
162 selectors.push([{ type: 'selector', nodes: [], before }]);
163 nodes.forEach((node) => {
164 if (node.type === 'operator') {
165 const chunks = selectors[selectors.length - 1];
166 chunks.push({ ...node, nodes: [] });
167 }
168 else if (node.type === 'spacing') {
169 const chunks = selectors[selectors.length - 1];
170 chunks.push({ ...node, nodes: [] });
171 }
172 else {
173 const chunks = selectors[selectors.length - 1];
174 chunks[chunks.length - 1].nodes.push(node);
175 }
176 });
177 });
178 return selectors;
179}
180exports.separateChunks2 = separateChunks2;
181function getOriginDefinition(resolved) {
182 for (const r of resolved) {
183 const { symbol } = r;
184 if (symbol._kind === 'class' || symbol._kind === 'element') {
185 if (symbol.alias && !symbol[stylable_value_parsers_1.valueMapping.extends]) {
186 continue;
187 }
188 else {
189 return r;
190 }
191 }
192 }
193 return resolved[0];
194}
195exports.getOriginDefinition = getOriginDefinition;
196function separateChunks(selectorNode) {
197 const selectors = [];
198 traverseNode(selectorNode, (node) => {
199 if (node.type === 'selectors') {
200 // skip
201 }
202 else if (node.type === 'selector') {
203 selectors.push([{ type: 'selector', nodes: [] }]);
204 }
205 else if (node.type === 'operator') {
206 const chunks = selectors[selectors.length - 1];
207 chunks.push({ type: node.type, operator: node.operator, nodes: [] });
208 }
209 else if (node.type === 'spacing') {
210 const chunks = selectors[selectors.length - 1];
211 chunks.push({ type: node.type, value: node.value, nodes: [] });
212 }
213 else {
214 const chunks = selectors[selectors.length - 1];
215 chunks[chunks.length - 1].nodes.push(node);
216 }
217 });
218 return selectors;
219}
220exports.separateChunks = separateChunks;
221function getLastChunk(selectorChunk) {
222 return selectorChunk[selectorChunk.length - 1];
223}
224function filterChunkNodesByType(chunk, typeOptions) {
225 return chunk.nodes.filter((node) => {
226 return node.type && typeOptions.includes(node.type);
227 });
228}
229exports.filterChunkNodesByType = filterChunkNodesByType;
230function isPseudoDiff(a, b) {
231 const aNodes = a.pseudo;
232 const bNodes = b.pseudo;
233 if (!aNodes || !bNodes || aNodes.length !== bNodes.length) {
234 return false;
235 }
236 return aNodes.every((node, index) => isNodeMatch(node, bNodes[index]));
237}
238function groupClassesAndPseudoElements(nodes) {
239 const nodesWithPseudos = [];
240 nodes.forEach((node) => {
241 if (node.type === 'class' || node.type === 'element') {
242 nodesWithPseudos.push({ ...node, pseudo: [] });
243 }
244 else if (node.type === 'pseudo-element') {
245 nodesWithPseudos[nodesWithPseudos.length - 1].pseudo.push({ ...node });
246 }
247 });
248 const nodesNoDuplicates = [];
249 nodesWithPseudos.forEach((node) => {
250 if (node.pseudo.length ||
251 !nodesWithPseudos.find((n) => isNodeMatch(n, node) && node !== n)) {
252 nodesNoDuplicates.push(node);
253 }
254 });
255 return nodesNoDuplicates;
256}
257const containsInTheEnd = (originalElements, currentMatchingElements) => {
258 const offset = originalElements.length - currentMatchingElements.length;
259 let arraysEqual = false;
260 if (offset >= 0 && currentMatchingElements.length > 0) {
261 arraysEqual = true;
262 for (let i = 0; i < currentMatchingElements.length; i++) {
263 const a = originalElements[i + offset];
264 const b = currentMatchingElements[i];
265 if (a.name !== b.name || a.type !== b.type || !isPseudoDiff(a, b)) {
266 arraysEqual = false;
267 break;
268 }
269 }
270 }
271 return arraysEqual;
272};
273function matchSelectorTarget(sourceSelector, targetSelector) {
274 const a = separateChunks(parseSelector(sourceSelector));
275 const b = separateChunks(parseSelector(targetSelector));
276 if (a.length > 1) {
277 throw new Error('source selector must not be composed of more than one compound selector');
278 }
279 const lastChunkA = getLastChunk(a[0]);
280 const relevantChunksA = groupClassesAndPseudoElements(filterChunkNodesByType(lastChunkA, ['class', 'element', 'pseudo-element']));
281 return b.some((compoundSelector) => {
282 const lastChunkB = getLastChunk(compoundSelector);
283 let relevantChunksB = groupClassesAndPseudoElements(filterChunkNodesByType(lastChunkB, ['class', 'element', 'pseudo-element']));
284 relevantChunksB = relevantChunksB.filter((nodeB) => relevantChunksA.find((nodeA) => isNodeMatch(nodeA, nodeB)));
285 return containsInTheEnd(relevantChunksA, relevantChunksB);
286 });
287}
288exports.matchSelectorTarget = matchSelectorTarget;
289function fixChunkOrdering(selectorNode, prefixType) {
290 let startChunkIndex = 0;
291 let moved = false;
292 traverseNode(selectorNode, (node, index, nodes) => {
293 if (node.type === 'operator' || node.type === 'spacing') {
294 startChunkIndex = index + 1;
295 moved = false;
296 }
297 else if (isNodeMatch(node, prefixType)) {
298 if (index > 0 && !moved) {
299 moved = true;
300 nodes.splice(index, 1);
301 nodes.splice(startChunkIndex, 0, node);
302 }
303 // return false;
304 }
305 return undefined;
306 });
307}
308exports.fixChunkOrdering = fixChunkOrdering;
309function isChildOfAtRule(rule, atRuleName) {
310 return (!!rule.parent &&
311 rule.parent.type === 'atrule' &&
312 rule.parent.name === atRuleName);
313}
314exports.isChildOfAtRule = isChildOfAtRule;
315function isCompRoot(name) {
316 return name.charAt(0).match(/[A-Z]/);
317}
318exports.isCompRoot = isCompRoot;
319function createWarningRule(extendedNode, scopedExtendedNode, extendedFile, extendingNode, scopedExtendingNode, extendingFile, useScoped = false) {
320 const message = `"class extending component '.${extendingNode} => ${scopedExtendingNode}' in stylesheet '${extendingFile}' was set on a node that does not extend '.${extendedNode} => ${scopedExtendedNode}' from stylesheet '${extendedFile}'" !important`;
321 return postcss.rule({
322 selector: `.${useScoped ? scopedExtendingNode : extendingNode}:not(.${useScoped ? scopedExtendedNode : extendedNode})::before`,
323 nodes: [
324 postcss.decl({
325 prop: 'content',
326 value: message,
327 }),
328 postcss.decl({
329 prop: 'display',
330 value: `block !important`,
331 }),
332 postcss.decl({
333 prop: 'font-family',
334 value: `monospace !important`,
335 }),
336 postcss.decl({
337 prop: 'background-color',
338 value: `red !important`,
339 }),
340 postcss.decl({
341 prop: 'color',
342 value: `white !important`,
343 }),
344 ],
345 });
346}
347exports.createWarningRule = createWarningRule;
348//# sourceMappingURL=selector-utils.js.map
\No newline at end of file