@stylable/core
Version:
CSS for Components
241 lines • 14.7 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.evalDeclarationValue = exports.processDeclarationValue = exports.resolveArgumentsValue = exports.functionWarnings = void 0;
const path_1 = require("path");
const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
const custom_values_1 = require("./custom-values");
const native_reserved_lists_1 = require("./native-reserved-lists");
const stylable_assets_1 = require("./stylable-assets");
const stylable_utils_1 = require("./stylable-utils");
const stylable_value_parsers_1 = require("./stylable-value-parsers");
const utils_1 = require("./utils");
exports.functionWarnings = {
FAIL_TO_EXECUTE_FORMATTER: (resolvedValue, message) => `failed to execute formatter "${resolvedValue}" with error: "${message}"`,
CYCLIC_VALUE: (cyclicChain) => `Cyclic value definition detected: "${cyclicChain
.map((s, i) => (i === cyclicChain.length - 1 ? '↻ ' : i === 0 ? '→ ' : '↪ ') + s)
.join('\n')}"`,
CANNOT_USE_AS_VALUE: (type, varName) => `${type} "${varName}" cannot be used as a variable`,
CANNOT_USE_JS_AS_VALUE: (varName) => `JavaScript import "${varName}" cannot be used as a variable`,
CANNOT_FIND_IMPORTED_VAR: (varName) => `cannot use unknown imported "${varName}"`,
MULTI_ARGS_IN_VALUE: (args) => `value function accepts only a single argument: "value(${args})"`,
COULD_NOT_RESOLVE_VALUE: (args) => `cannot resolve value function using the arguments provided: "${args}"`,
UNKNOWN_FORMATTER: (name) => `cannot find native function or custom formatter called ${name}`,
UNKNOWN_VAR: (name) => `unknown var "${name}"`,
};
function resolveArgumentsValue(options, transformer, meta, diagnostics, node, variableOverride, path, cssVarsMapping) {
const resolvedArgs = {};
for (const k in options) {
resolvedArgs[k] = evalDeclarationValue(transformer.resolver, options[k], meta, node, variableOverride, transformer.replaceValueHook, diagnostics, path, cssVarsMapping, undefined);
}
return resolvedArgs;
}
exports.resolveArgumentsValue = resolveArgumentsValue;
function processDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough = [], cssVarsMapping, args = []) {
diagnostics = node ? diagnostics : undefined;
const customValues = custom_values_1.resolveCustomValues(meta, resolver);
const parsedValue = postcss_value_parser_1.default(value);
parsedValue.walk((parsedNode) => {
const { type, value } = parsedNode;
switch (type) {
case 'function':
if (value === 'value') {
const parsedArgs = stylable_value_parsers_1.strategies.args(parsedNode).map((x) => x.value);
if (parsedArgs.length >= 1) {
const varName = parsedArgs[0];
const getArgs = parsedArgs
.slice(1)
.map((arg) => evalDeclarationValue(resolver, arg, meta, node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, undefined));
if (variableOverride && variableOverride[varName]) {
return (parsedNode.resolvedValue = variableOverride[varName]);
}
const refUniqID = createUniqID(meta.source, varName);
if (passedThrough.includes(refUniqID)) {
// TODO: move diagnostic to original value usage instead of the end of the cyclic chain
return handleCyclicValues(passedThrough, refUniqID, diagnostics, node, value, parsedNode);
}
const varSymbol = meta.mappedSymbols[varName];
if (varSymbol && varSymbol._kind === 'var') {
const resolved = processDeclarationValue(resolver, utils_1.stripQuotation(varSymbol.text), meta, varSymbol.node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, getArgs);
const { outputValue, topLevelType, typeError } = resolved;
if (diagnostics && node) {
const argsAsString = parsedArgs.join(', ');
if (typeError) {
diagnostics.warn(node, exports.functionWarnings.COULD_NOT_RESOLVE_VALUE(argsAsString));
}
else if (!topLevelType && parsedArgs.length > 1) {
diagnostics.warn(node, exports.functionWarnings.MULTI_ARGS_IN_VALUE(argsAsString));
}
}
parsedNode.resolvedValue = valueHook
? valueHook(outputValue, varName, true, passedThrough)
: outputValue;
}
else if (varSymbol && varSymbol._kind === 'import') {
const resolvedVar = resolver.deepResolve(varSymbol);
if (resolvedVar && resolvedVar.symbol) {
const resolvedVarSymbol = resolvedVar.symbol;
if (resolvedVar._kind === 'css') {
if (resolvedVarSymbol._kind === 'var') {
const resolvedValue = evalDeclarationValue(resolver, utils_1.stripQuotation(resolvedVarSymbol.text), resolvedVar.meta, resolvedVarSymbol.node, variableOverride, valueHook, diagnostics, passedThrough.concat(createUniqID(meta.source, varName)), cssVarsMapping, getArgs);
parsedNode.resolvedValue = valueHook
? valueHook(resolvedValue, varName, false, passedThrough)
: resolvedValue;
}
else {
const errorKind = resolvedVarSymbol._kind === 'class' &&
resolvedVarSymbol[stylable_value_parsers_1.valueMapping.root]
? 'stylesheet'
: resolvedVarSymbol._kind;
if (diagnostics && node) {
diagnostics.warn(node, exports.functionWarnings.CANNOT_USE_AS_VALUE(errorKind, varName), { word: varName });
}
}
}
else if (resolvedVar._kind === 'js' && diagnostics && node) {
// ToDo: provide actual exported id (default/named as x)
diagnostics.warn(node, exports.functionWarnings.CANNOT_USE_JS_AS_VALUE(varName), {
word: varName,
});
}
}
else {
const namedDecl = varSymbol.import.rule.nodes.find((node) => {
return node.type === 'decl' && node.prop === stylable_value_parsers_1.valueMapping.named;
});
if (namedDecl && diagnostics && node) {
// ToDo: provide actual exported id (default/named as x)
diagnostics.error(node, exports.functionWarnings.CANNOT_FIND_IMPORTED_VAR(varName), { word: varName });
}
}
}
else if (diagnostics && node) {
diagnostics.warn(node, exports.functionWarnings.UNKNOWN_VAR(varName), {
word: varName,
});
}
}
}
else if (value === '') {
parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
}
else {
if (customValues[value]) {
// no op resolved at the bottom
}
else if (value === 'url') {
// postcss-value-parser treats url differently:
// https://github.com/TrySound/postcss-value-parser/issues/34
const url = parsedNode.nodes[0];
if ((url.type === 'word' || url.type === 'string') &&
url.value.startsWith('~')) {
const sourceDir = path_1.dirname(meta.source);
url.value = stylable_assets_1.assureRelativeUrlPrefix(path_1.relative(sourceDir, resolver.resolvePath(url.value.slice(1), sourceDir)).replace(/\\/gm, '/'));
}
}
else if (value === 'format') {
// preserve native format function quotation
parsedNode.resolvedValue = stringifyFunction(value, parsedNode, true);
}
else {
const formatterRef = meta.mappedSymbols[value];
const formatter = resolver.deepResolve(formatterRef);
const formatterArgs = stylable_value_parsers_1.getFormatterArgs(parsedNode);
if (formatter && formatter._kind === 'js') {
try {
parsedNode.resolvedValue = formatter.symbol.apply(null, formatterArgs);
if (valueHook && typeof parsedNode.resolvedValue === 'string') {
parsedNode.resolvedValue = valueHook(parsedNode.resolvedValue, { name: parsedNode.value, args: formatterArgs }, true, passedThrough);
}
}
catch (error) {
parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
if (diagnostics && node) {
diagnostics.warn(node, exports.functionWarnings.FAIL_TO_EXECUTE_FORMATTER(parsedNode.resolvedValue, error.message), { word: node.value });
}
}
}
else if (value === 'var') {
const varWithPrefix = parsedNode.nodes[0].value;
if (stylable_utils_1.isCSSVarProp(varWithPrefix)) {
if (cssVarsMapping && cssVarsMapping[varWithPrefix]) {
parsedNode.nodes[0].value = cssVarsMapping[varWithPrefix];
}
}
// handle default values
if (parsedNode.nodes.length > 2) {
parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
}
}
else if (native_reserved_lists_1.isCssNativeFunction(value)) {
parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
}
else if (diagnostics && node) {
parsedNode.resolvedValue = stringifyFunction(value, parsedNode);
diagnostics.warn(node, exports.functionWarnings.UNKNOWN_FORMATTER(value), {
word: value,
});
}
}
}
break;
default: {
return postcss_value_parser_1.default.stringify(parsedNode);
}
}
return;
}, true);
let outputValue = '';
let topLevelType = null;
let typeError = null;
for (const n of parsedValue.nodes) {
if (n.type === 'function') {
const matchingType = customValues[n.value];
if (matchingType) {
topLevelType = matchingType.evalVarAst(n, customValues);
try {
outputValue += matchingType.getValue(args, topLevelType, n, customValues);
}
catch (e) {
typeError = e;
// catch broken variable resolutions
}
}
else {
outputValue += stylable_value_parsers_1.getStringValue([n]);
}
}
else {
outputValue += stylable_value_parsers_1.getStringValue([n]);
}
}
return { outputValue, topLevelType, typeError };
// }
// TODO: handle calc (parse internals but maintain expression)
// TODO: check this thing. native function that accent our function dose not work
// e.g: calc(getVarName())
}
exports.processDeclarationValue = processDeclarationValue;
function evalDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough = [], cssVarsMapping, args = []) {
return processDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough, cssVarsMapping, args).outputValue;
}
exports.evalDeclarationValue = evalDeclarationValue;
function handleCyclicValues(passedThrough, refUniqID, diagnostics, node, value, parsedNode) {
const cyclicChain = passedThrough.map((variable) => variable || '');
cyclicChain.push(refUniqID);
if (diagnostics && node) {
diagnostics.warn(node, exports.functionWarnings.CYCLIC_VALUE(cyclicChain), {
word: refUniqID,
});
}
return stringifyFunction(value, parsedNode);
}
function stringifyFunction(name, parsedNode, perserveQuotes = false) {
return `${name}(${stylable_value_parsers_1.getFormatterArgs(parsedNode, false, undefined, perserveQuotes).join(', ')})`;
}
function createUniqID(source, varName) {
return `${source}: ${varName}`;
}
//# sourceMappingURL=functions.js.map
;