UNPKG

15.1 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.evalDeclarationValue = exports.processDeclarationValue = exports.resolveArgumentsValue = exports.functionWarnings = void 0;
7const path_1 = require("path");
8const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
9const custom_values_1 = require("./custom-values");
10const native_reserved_lists_1 = require("./native-reserved-lists");
11const stylable_assets_1 = require("./stylable-assets");
12const stylable_utils_1 = require("./stylable-utils");
13const stylable_value_parsers_1 = require("./stylable-value-parsers");
14const utils_1 = require("./utils");
15exports.functionWarnings = {
16 FAIL_TO_EXECUTE_FORMATTER: (resolvedValue, message) => `failed to execute formatter "${resolvedValue}" with error: "${message}"`,
17 CYCLIC_VALUE: (cyclicChain) => `Cyclic value definition detected: "${cyclicChain
18 .map((s, i) => (i === cyclicChain.length - 1 ? '↻ ' : i === 0 ? '→ ' : '↪ ') + s)
19 .join('\n')}"`,
20 CANNOT_USE_AS_VALUE: (type, varName) => `${type} "${varName}" cannot be used as a variable`,
21 CANNOT_USE_JS_AS_VALUE: (varName) => `JavaScript import "${varName}" cannot be used as a variable`,
22 CANNOT_FIND_IMPORTED_VAR: (varName) => `cannot use unknown imported "${varName}"`,
23 MULTI_ARGS_IN_VALUE: (args) => `value function accepts only a single argument: "value(${args})"`,
24 COULD_NOT_RESOLVE_VALUE: (args) => `cannot resolve value function using the arguments provided: "${args}"`,
25 UNKNOWN_FORMATTER: (name) => `cannot find native function or custom formatter called ${name}`,
26 UNKNOWN_VAR: (name) => `unknown var "${name}"`,
27};
28function resolveArgumentsValue(options, transformer, meta, diagnostics, node, variableOverride, path, cssVarsMapping) {
29 const resolvedArgs = {};
30 for (const k in options) {
31 resolvedArgs[k] = evalDeclarationValue(transformer.resolver, options[k], meta, node, variableOverride, transformer.replaceValueHook, diagnostics, path, cssVarsMapping, undefined);
32 }
33 return resolvedArgs;
34}
35exports.resolveArgumentsValue = resolveArgumentsValue;
36function processDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough = [], cssVarsMapping, args = []) {
37 diagnostics = node ? diagnostics : undefined;
38 const customValues = custom_values_1.resolveCustomValues(meta, resolver);
39 const parsedValue = postcss_value_parser_1.default(value);
40 parsedValue.walk((parsedNode) => {
41 const { type, value } = parsedNode;
42 switch (type) {
43 case 'function':
44 if (value === 'value') {
45 const parsedArgs = stylable_value_parsers_1.strategies.args(parsedNode).map((x) => x.value);
46 if (parsedArgs.length >= 1) {
47 const varName = parsedArgs[0];
48 const getArgs = parsedArgs
49 .slice(1)
50 .map((arg) => evalDeclarationValue(resolver, arg, meta, node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, undefined));
51 if (variableOverride && variableOverride[varName]) {
52 return (parsedNode.resolvedValue = variableOverride[varName]);
53 }
54 const refUniqID = createUniqID(meta.source, varName);
55 if (passedThrough.includes(refUniqID)) {
56 // TODO: move diagnostic to original value usage instead of the end of the cyclic chain
57 return handleCyclicValues(passedThrough, refUniqID, diagnostics, node, value, parsedNode);
58 }
59 const varSymbol = meta.mappedSymbols[varName];
60 if (varSymbol && varSymbol._kind === 'var') {
61 const resolved = processDeclarationValue(resolver, utils_1.stripQuotation(varSymbol.text), meta, varSymbol.node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, getArgs);
62 const { outputValue, topLevelType, typeError } = resolved;
63 if (diagnostics && node) {
64 const argsAsString = parsedArgs.join(', ');
65 if (typeError) {
66 diagnostics.warn(node, exports.functionWarnings.COULD_NOT_RESOLVE_VALUE(argsAsString));
67 }
68 else if (!topLevelType && parsedArgs.length > 1) {
69 diagnostics.warn(node, exports.functionWarnings.MULTI_ARGS_IN_VALUE(argsAsString));
70 }
71 }
72 parsedNode.resolvedValue = valueHook
73 ? valueHook(outputValue, varName, true, passedThrough)
74 : outputValue;
75 }
76 else if (varSymbol && varSymbol._kind === 'import') {
77 const resolvedVar = resolver.deepResolve(varSymbol);
78 if (resolvedVar && resolvedVar.symbol) {
79 const resolvedVarSymbol = resolvedVar.symbol;
80 if (resolvedVar._kind === 'css') {
81 if (resolvedVarSymbol._kind === 'var') {
82 const resolvedValue = evalDeclarationValue(resolver, utils_1.stripQuotation(resolvedVarSymbol.text), resolvedVar.meta, resolvedVarSymbol.node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, getArgs);
83 parsedNode.resolvedValue = valueHook
84 ? valueHook(resolvedValue, varName, false, passedThrough)
85 : resolvedValue;
86 }
87 else {
88 const errorKind = resolvedVarSymbol._kind === 'class' &&
89 resolvedVarSymbol[stylable_value_parsers_1.valueMapping.root]
90 ? 'stylesheet'
91 : resolvedVarSymbol._kind;
92 if (diagnostics && node) {
93 diagnostics.warn(node, exports.functionWarnings.CANNOT_USE_AS_VALUE(errorKind, varName), { word: varName });
94 }
95 }
96 }
97 else if (resolvedVar._kind === 'js' &&
98 typeof resolvedVar.symbol === 'string') {
99 parsedNode.resolvedValue = valueHook
100 ? valueHook(resolvedVar.symbol, varName, false, passedThrough)
101 : resolvedVar.symbol;
102 }
103 else if (resolvedVar._kind === 'js' && diagnostics && node) {
104 // ToDo: provide actual exported id (default/named as x)
105 diagnostics.warn(node, exports.functionWarnings.CANNOT_USE_JS_AS_VALUE(varName), {
106 word: varName,
107 });
108 }
109 }
110 else {
111 const namedDecl = varSymbol.import.rule.nodes.find((node) => {
112 return node.type === 'decl' && node.prop === stylable_value_parsers_1.valueMapping.named;
113 });
114 if (namedDecl && diagnostics && node) {
115 // ToDo: provide actual exported id (default/named as x)
116 diagnostics.error(node, exports.functionWarnings.CANNOT_FIND_IMPORTED_VAR(varName), { word: varName });
117 }
118 }
119 }
120 else if (diagnostics && node) {
121 diagnostics.warn(node, exports.functionWarnings.UNKNOWN_VAR(varName), {
122 word: varName,
123 });
124 }
125 }
126 }
127 else if (value === '') {
128 parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
129 }
130 else {
131 if (customValues[value]) {
132 // no op resolved at the bottom
133 }
134 else if (value === 'url') {
135 // postcss-value-parser treats url differently:
136 // https://github.com/TrySound/postcss-value-parser/issues/34
137 const url = parsedNode.nodes[0];
138 if ((url.type === 'word' || url.type === 'string') &&
139 url.value.startsWith('~')) {
140 const sourceDir = path_1.dirname(meta.source);
141 url.value = stylable_assets_1.assureRelativeUrlPrefix(path_1.relative(sourceDir, resolver.resolvePath(url.value.slice(1), sourceDir)).replace(/\\/gm, '/'));
142 }
143 }
144 else if (value === 'format') {
145 // preserve native format function quotation
146 parsedNode.resolvedValue = stringifyFunction(value, parsedNode, true);
147 }
148 else {
149 const formatterRef = meta.mappedSymbols[value];
150 const formatter = resolver.deepResolve(formatterRef);
151 const formatterArgs = stylable_value_parsers_1.getFormatterArgs(parsedNode);
152 if (formatter && formatter._kind === 'js') {
153 try {
154 parsedNode.resolvedValue = formatter.symbol.apply(null, formatterArgs);
155 if (valueHook && typeof parsedNode.resolvedValue === 'string') {
156 parsedNode.resolvedValue = valueHook(parsedNode.resolvedValue, { name: parsedNode.value, args: formatterArgs }, true, passedThrough);
157 }
158 }
159 catch (error) {
160 parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
161 if (diagnostics && node) {
162 diagnostics.warn(node, exports.functionWarnings.FAIL_TO_EXECUTE_FORMATTER(parsedNode.resolvedValue, error.message), { word: node.value });
163 }
164 }
165 }
166 else if (value === 'var') {
167 const varWithPrefix = parsedNode.nodes[0].value;
168 if (stylable_utils_1.isCSSVarProp(varWithPrefix)) {
169 if (cssVarsMapping && cssVarsMapping[varWithPrefix]) {
170 parsedNode.nodes[0].value = cssVarsMapping[varWithPrefix];
171 }
172 }
173 // handle default values
174 if (parsedNode.nodes.length > 2) {
175 parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
176 }
177 }
178 else if (native_reserved_lists_1.isCssNativeFunction(value)) {
179 parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
180 }
181 else if (diagnostics && node) {
182 parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
183 diagnostics.warn(node, exports.functionWarnings.UNKNOWN_FORMATTER(value), {
184 word: value,
185 });
186 }
187 }
188 }
189 break;
190 default: {
191 return postcss_value_parser_1.default.stringify(parsedNode);
192 }
193 }
194 return;
195 }, true);
196 let outputValue = '';
197 let topLevelType = null;
198 let typeError = null;
199 for (const n of parsedValue.nodes) {
200 if (n.type === 'function') {
201 const matchingType = customValues[n.value];
202 if (matchingType) {
203 topLevelType = matchingType.evalVarAst(n, customValues);
204 try {
205 outputValue += matchingType.getValue(args, topLevelType, n, customValues);
206 }
207 catch (e) {
208 typeError = e;
209 // catch broken variable resolutions
210 }
211 }
212 else {
213 outputValue += stylable_value_parsers_1.getStringValue([n]);
214 }
215 }
216 else {
217 outputValue += stylable_value_parsers_1.getStringValue([n]);
218 }
219 }
220 return { outputValue, topLevelType, typeError };
221 // }
222 // TODO: handle calc (parse internals but maintain expression)
223 // TODO: check this thing. native function that accent our function does not work
224 // e.g: calc(getVarName())
225}
226exports.processDeclarationValue = processDeclarationValue;
227function evalDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough = [], cssVarsMapping, args = []) {
228 return processDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough, cssVarsMapping, args).outputValue;
229}
230exports.evalDeclarationValue = evalDeclarationValue;
231function handleCyclicValues(passedThrough, refUniqID, diagnostics, node, value, parsedNode) {
232 const cyclicChain = passedThrough.map((variable) => variable || '');
233 cyclicChain.push(refUniqID);
234 if (diagnostics && node) {
235 diagnostics.warn(node, exports.functionWarnings.CYCLIC_VALUE(cyclicChain), {
236 word: refUniqID,
237 });
238 }
239 return stringifyFunction(value, parsedNode);
240}
241function stringifyFunction(name, parsedNode, perserveQuotes = false) {
242 return `${name}(${stylable_value_parsers_1.getFormatterArgs(parsedNode, false, undefined, perserveQuotes).join(', ')})`;
243}
244function createUniqID(source, varName) {
245 return `${source}: ${varName}`;
246}
247//# sourceMappingURL=functions.js.map
\No newline at end of file