UNPKG

11.9 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.validateAllowedNodesUntil = exports.listOptions = exports.strategies = exports.groupValues = exports.getStringValue = exports.getFormatterArgs = exports.getNamedArgs = exports.SBTypesParsers = exports.STYLABLE_NAMED_MATCHER = exports.STYLABLE_VALUE_MATCHER = exports.stValuesMap = exports.stValues = exports.mixinDeclRegExp = exports.valueMapping = exports.rootValueMapping = exports.valueParserWarnings = void 0;
7const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
8const pseudo_states_1 = require("./pseudo-states");
9const selector_utils_1 = require("./selector-utils");
10exports.valueParserWarnings = {
11 VALUE_CANNOT_BE_STRING() {
12 return 'value can not be a string (remove quotes?)';
13 },
14 CSS_MIXIN_FORCE_NAMED_PARAMS() {
15 return 'CSS mixins must use named parameters (e.g. "func(name value, [name value, ...])")';
16 },
17 INVALID_NAMED_IMPORT_AS(name) {
18 return `Invalid named import "as" with name "${name}"`;
19 },
20 INVALID_NESTED_KEYFRAMES(name) {
21 return `Invalid nested keyframes import "${name}"`;
22 },
23};
24exports.rootValueMapping = {
25 vars: ':vars',
26 import: ':import',
27 stScope: 'st-scope',
28 namespace: 'namespace',
29};
30exports.valueMapping = {
31 from: '-st-from',
32 named: '-st-named',
33 default: '-st-default',
34 root: '-st-root',
35 states: '-st-states',
36 extends: '-st-extends',
37 mixin: '-st-mixin',
38 partialMixin: '-st-partial-mixin',
39 global: '-st-global',
40};
41exports.mixinDeclRegExp = new RegExp(`(${exports.valueMapping.mixin})|(${exports.valueMapping.partialMixin})`);
42exports.stValues = Object.keys(exports.valueMapping).map((key) => exports.valueMapping[key]);
43exports.stValuesMap = Object.keys(exports.valueMapping).reduce((acc, key) => {
44 acc[exports.valueMapping[key]] = true;
45 return acc;
46}, {});
47exports.STYLABLE_VALUE_MATCHER = /^-st-/;
48exports.STYLABLE_NAMED_MATCHER = new RegExp(`^${exports.valueMapping.named}-(.+)`);
49exports.SBTypesParsers = {
50 '-st-root'(value) {
51 return value === 'false' ? false : true;
52 },
53 '-st-global'(decl, _diagnostics) {
54 // Experimental
55 const selector = selector_utils_1.parseSelector(decl.value.replace(/^['"]/, '').replace(/['"]$/, ''));
56 return selector.nodes[0].nodes;
57 },
58 '-st-states'(value, decl, diagnostics) {
59 if (!value) {
60 return {};
61 }
62 return pseudo_states_1.processPseudoStates(value, decl, diagnostics);
63 },
64 '-st-extends'(value) {
65 const ast = postcss_value_parser_1.default(value);
66 const types = [];
67 ast.walk((node) => {
68 if (node.type === 'function') {
69 const args = getNamedArgs(node);
70 types.push({
71 symbolName: node.value,
72 args,
73 });
74 return false;
75 }
76 else if (node.type === 'word') {
77 types.push({
78 symbolName: node.value,
79 args: null,
80 });
81 }
82 return undefined;
83 }, false);
84 return {
85 ast,
86 types,
87 };
88 },
89 '-st-named'(value, node, diagnostics) {
90 const namedMap = {};
91 const keyframesMap = {};
92 if (value) {
93 handleNamedTokens(postcss_value_parser_1.default(value), { namedMap, keyframesMap }, 'namedMap', node, diagnostics);
94 }
95 return { namedMap, keyframesMap };
96 },
97 '-st-mixin'(mixinNode, strategy, diagnostics) {
98 const ast = postcss_value_parser_1.default(mixinNode.value);
99 const mixins = [];
100 function reportWarning(message, options) {
101 if (diagnostics) {
102 diagnostics.warn(mixinNode, message, options);
103 }
104 }
105 ast.nodes.forEach((node) => {
106 const strat = strategy(node.value);
107 if (node.type === 'function') {
108 mixins.push({
109 type: node.value,
110 options: exports.strategies[strat](node, reportWarning),
111 });
112 }
113 else if (node.type === 'word') {
114 mixins.push({
115 type: node.value,
116 options: strat === 'named' ? {} : [],
117 });
118 }
119 else if (node.type === 'string' && diagnostics) {
120 diagnostics.error(mixinNode, exports.valueParserWarnings.VALUE_CANNOT_BE_STRING(), {
121 word: mixinNode.value,
122 });
123 }
124 });
125 return mixins;
126 },
127 '-st-partial-mixin'(mixinNode, strategy, diagnostics) {
128 return exports.SBTypesParsers['-st-mixin'](mixinNode, strategy, diagnostics).map((mixin) => {
129 mixin.partial = true;
130 return mixin;
131 });
132 },
133};
134function handleNamedTokens(tokens, buckets, key = 'namedMap', node, diagnostics) {
135 const { nodes } = tokens;
136 for (let i = 0; i < nodes.length; i++) {
137 const token = nodes[i];
138 if (token.type === 'word') {
139 const space = nodes[i + 1];
140 const as = nodes[i + 2];
141 const spaceAfter = nodes[i + 3];
142 const asName = nodes[i + 4];
143 if (isImportAs(space, as)) {
144 if ((spaceAfter === null || spaceAfter === void 0 ? void 0 : spaceAfter.type) === 'space' && (asName === null || asName === void 0 ? void 0 : asName.type) === 'word') {
145 buckets[key][asName.value] = token.value;
146 i += 4; //ignore next 4 tokens
147 }
148 else {
149 i += !asName ? 3 : 2;
150 diagnostics.warn(node, exports.valueParserWarnings.INVALID_NAMED_IMPORT_AS(token.value));
151 continue;
152 }
153 }
154 else {
155 buckets[key][token.value] = token.value;
156 }
157 }
158 else if (token.type === 'function' && token.value === 'keyframes') {
159 if (key === 'keyframesMap') {
160 diagnostics.warn(node, exports.valueParserWarnings.INVALID_NESTED_KEYFRAMES(postcss_value_parser_1.default.stringify(token)));
161 }
162 handleNamedTokens(token, buckets, 'keyframesMap', node, diagnostics);
163 }
164 }
165}
166function isImportAs(space, as) {
167 return (space === null || space === void 0 ? void 0 : space.type) === 'space' && (as === null || as === void 0 ? void 0 : as.type) === 'word' && (as === null || as === void 0 ? void 0 : as.value) === 'as';
168}
169function getNamedArgs(node) {
170 const args = [];
171 if (node.nodes.length) {
172 args.push([]);
173 node.nodes.forEach((node) => {
174 if (node.type === 'div') {
175 args.push([]);
176 }
177 else {
178 const { sourceIndex, ...clone } = node;
179 args[args.length - 1].push(clone);
180 }
181 });
182 }
183 // handle trailing comma
184 return args.length && args[args.length - 1].length === 0 ? args.slice(0, -1) : args;
185}
186exports.getNamedArgs = getNamedArgs;
187function getFormatterArgs(node, allowComments = false, _reportWarning, perserveQuotes = false) {
188 const argsResult = [];
189 let currentArg = '';
190 let argIndex = 0;
191 for (const currentNode of node.nodes) {
192 if (currentNode.type === 'div' && currentNode.value === ',') {
193 checkEmptyArg();
194 argIndex++;
195 argsResult.push(currentArg.trim());
196 currentArg = '';
197 }
198 else if (currentNode.type === 'comment') {
199 if (allowComments) {
200 currentArg +=
201 currentNode.resolvedValue || postcss_value_parser_1.default.stringify(currentNode);
202 }
203 }
204 else if (currentNode.type === 'string') {
205 currentArg += perserveQuotes
206 ? postcss_value_parser_1.default.stringify(currentNode)
207 : currentNode.value;
208 }
209 else {
210 currentArg += currentNode.resolvedValue || postcss_value_parser_1.default.stringify(currentNode);
211 }
212 }
213 checkEmptyArg();
214 argsResult.push(currentArg.trim());
215 let i = argsResult.length;
216 while (i--) {
217 if (argsResult[i] === '') {
218 argsResult.pop();
219 }
220 else {
221 return argsResult;
222 }
223 }
224 return argsResult;
225 function checkEmptyArg() {
226 if (currentArg.trim() === '' && _reportWarning) {
227 _reportWarning(`${postcss_value_parser_1.default.stringify(node)}: argument at index ${argIndex} is empty`);
228 }
229 }
230}
231exports.getFormatterArgs = getFormatterArgs;
232function getStringValue(nodes) {
233 return postcss_value_parser_1.default.stringify(nodes, (node) => {
234 if (node.resolvedValue !== undefined) {
235 return node.resolvedValue;
236 }
237 else {
238 // TODO: warn
239 return undefined;
240 }
241 });
242}
243exports.getStringValue = getStringValue;
244function groupValues(nodes, divType = 'div') {
245 const grouped = [];
246 let current = [];
247 nodes.forEach((n) => {
248 if (n.type === divType) {
249 grouped.push(current);
250 current = [];
251 }
252 else {
253 current.push(n);
254 }
255 });
256 const last = grouped[grouped.length - 1];
257 if ((last && last !== current && current.length) || (!last && current.length)) {
258 grouped.push(current);
259 }
260 return grouped;
261}
262exports.groupValues = groupValues;
263exports.strategies = {
264 named: (node, reportWarning) => {
265 const named = {};
266 getNamedArgs(node).forEach((mixinArgsGroup) => {
267 const argsDivider = mixinArgsGroup[1];
268 if (mixinArgsGroup.length < 3 || (argsDivider && argsDivider.type !== 'space')) {
269 if (reportWarning) {
270 const argValue = mixinArgsGroup[0];
271 reportWarning(exports.valueParserWarnings.CSS_MIXIN_FORCE_NAMED_PARAMS(), {
272 word: argValue.value,
273 });
274 }
275 return;
276 }
277 named[mixinArgsGroup[0].value] = stringifyParam(mixinArgsGroup.slice(2));
278 });
279 return named;
280 },
281 args: (node, reportWarning) => {
282 return getFormatterArgs(node, true, reportWarning).map((value) => ({ value }));
283 },
284};
285function stringifyParam(nodes) {
286 return postcss_value_parser_1.default.stringify(nodes, (n) => {
287 if (n.type === 'function') {
288 return postcss_value_parser_1.default.stringify(n);
289 }
290 else if (n.type === 'div') {
291 return null;
292 }
293 else if (n.type === 'string') {
294 return n.value;
295 }
296 else {
297 return undefined;
298 }
299 });
300}
301function listOptions(node) {
302 return groupValues(node.nodes)
303 .map((nodes) => postcss_value_parser_1.default.stringify(nodes, (n) => {
304 if (n.type === 'div') {
305 return null;
306 }
307 else if (n.type === 'string') {
308 return n.value;
309 }
310 else {
311 return undefined;
312 }
313 }))
314 .filter((x) => typeof x === 'string');
315}
316exports.listOptions = listOptions;
317function validateAllowedNodesUntil(node, i, untilType = 'div', allowed = ['comment']) {
318 i = 1;
319 let current = node.nodes[i];
320 while (current && current.type !== untilType) {
321 if (!allowed.includes(current.type)) {
322 return false;
323 }
324 i++;
325 current = node.nodes[i];
326 }
327 return true;
328}
329exports.validateAllowedNodesUntil = validateAllowedNodesUntil;
330//# sourceMappingURL=stylable-value-parsers.js.map
\No newline at end of file