UNPKG

@stylable/core

Version:

CSS for Components

200 lines 9.85 kB
"use strict"; 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.functionDiagnostics = exports.StylableEvaluator = void 0; const path_1 = require("path"); const postcss_value_parser_1 = __importDefault(require("postcss-value-parser")); const diagnostics_1 = require("./diagnostics"); const native_reserved_lists_1 = require("./native-reserved-lists"); const stylable_assets_1 = require("./stylable-assets"); const stylable_resolver_1 = require("./stylable-resolver"); const value_1 = require("./helpers/value"); const escape_1 = require("./helpers/escape"); const features_1 = require("./features"); const custom_values_1 = require("./custom-values"); class StylableEvaluator { constructor(options) { this.valueHook = options.valueHook; this.stVarOverride = options.stVarOverride; this.getResolvedSymbols = options.getResolvedSymbols; } evaluateValue(context, data) { return processDeclarationValue(context.resolver, this.getResolvedSymbols, data.value, data.meta, data.node, data.stVarOverride || this.stVarOverride, this.valueHook, context.diagnostics, context.passedThrough, data.args, data.rootArgument, data.initialNode); } } exports.StylableEvaluator = StylableEvaluator; // old API exports.functionDiagnostics = { FAIL_TO_EXECUTE_FORMATTER: (0, diagnostics_1.createDiagnosticReporter)('15001', 'error', (resolvedValue, message) => `failed to execute formatter "${resolvedValue}" with error: "${message}"`), UNKNOWN_FORMATTER: (0, diagnostics_1.createDiagnosticReporter)('15002', 'error', (name) => `cannot find native function or custom formatter called ${name}`), }; function resolveArgumentsValue(options, transformer, meta, diagnostics, node, variableOverride, path) { const resolvedArgs = {}; for (const k in options) { resolvedArgs[k] = evalDeclarationValue(transformer.resolver, (0, escape_1.unescapeCSS)(options[k]), meta, node, variableOverride, transformer.replaceValueHook, diagnostics, path, undefined); } return resolvedArgs; } exports.resolveArgumentsValue = resolveArgumentsValue; function processDeclarationValue(resolver, getResolvedSymbols, value, meta, node, variableOverride, valueHook, diagnostics = new diagnostics_1.Diagnostics(), passedThrough = [], args = [], rootArgument, initialNode) { const evaluator = new StylableEvaluator({ stVarOverride: variableOverride, valueHook, getResolvedSymbols, }); const resolvedSymbols = getResolvedSymbols(meta); const parsedValue = (0, postcss_value_parser_1.default)(value); parsedValue.walk((parsedNode) => { const { type, value } = parsedNode; if (type === `function`) { if (value === 'value') { features_1.STVar.hooks.transformValue({ context: { meta, diagnostics, resolver, evaluator, getResolvedSymbols, passedThrough, }, data: { value, node, meta, stVarOverride: variableOverride, args, rootArgument, initialNode, }, node: parsedNode, }); } else if (value === '') { parsedNode.resolvedValue = (0, value_1.stringifyFunction)(value, parsedNode); } else if (resolvedSymbols.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 = (0, path_1.dirname)(meta.source); url.value = (0, stylable_assets_1.assureRelativeUrlPrefix)((0, path_1.relative)(sourceDir, resolver.resolvePath(sourceDir, url.value.slice(1))).replace(/\\/gm, '/')); } } else if (value === 'format') { // preserve native format function arg quotation parsedNode.resolvedValue = (0, value_1.stringifyFunction)(value, parsedNode, true); } else if (resolvedSymbols.js[value]) { const formatter = resolvedSymbols.js[value]; const formatterArgs = (0, value_1.getFormatterArgs)(parsedNode); try { // ToDo: check if function instead of calling on a non function parsedNode.resolvedValue = formatter.symbol(...formatterArgs); if (evaluator.valueHook && typeof parsedNode.resolvedValue === 'string') { parsedNode.resolvedValue = evaluator.valueHook(parsedNode.resolvedValue, { name: parsedNode.value, args: formatterArgs }, true, passedThrough); } } catch (error) { parsedNode.resolvedValue = (0, value_1.stringifyFunction)(value, parsedNode); if (diagnostics && node) { diagnostics.report(exports.functionDiagnostics.FAIL_TO_EXECUTE_FORMATTER(parsedNode.resolvedValue, error?.message), { node, word: node.value, }); } } } else if (value === 'var') { features_1.CSSCustomProperty.hooks.transformValue({ context: { meta, diagnostics, resolver, evaluator, getResolvedSymbols, passedThrough, }, data: { value, node, meta, stVarOverride: variableOverride, args, rootArgument, initialNode, }, node: parsedNode, }); } else if (native_reserved_lists_1.nativeFunctionsDic[value]) { const { preserveQuotes } = native_reserved_lists_1.nativeFunctionsDic[value]; parsedNode.resolvedValue = (0, value_1.stringifyFunction)(value, parsedNode, preserveQuotes); } else if (node) { parsedNode.resolvedValue = (0, value_1.stringifyFunction)(value, parsedNode); diagnostics.report(exports.functionDiagnostics.UNKNOWN_FORMATTER(value), { node, word: value, }); } } }, true); let outputValue = ''; let topLevelType = null; let runtimeValue = null; let typeError = undefined; for (const n of parsedValue.nodes) { if (n.type === 'function') { const matchingType = resolvedSymbols.customValues[n.value]; if (matchingType) { try { topLevelType = matchingType.evalVarAst(n, resolvedSymbols.customValues, true); runtimeValue = (0, custom_values_1.unbox)(topLevelType, true, resolvedSymbols.customValues, n); try { outputValue += matchingType.getValue(args, topLevelType, n, resolvedSymbols.customValues); } catch (error) { if (error instanceof custom_values_1.CustomValueError) { outputValue += error.fallbackValue; } else { throw error; } } } catch (e) { typeError = e; const invalidNode = initialNode || node; if (invalidNode) { diagnostics.report(features_1.STVar.diagnostics.COULD_NOT_RESOLVE_VALUE([...(rootArgument ? [rootArgument] : []), ...args].join(', ')), { node: invalidNode, word: value, }); } else { // TODO: catch broken variable resolutions without a node } } } else { outputValue += (0, value_1.getStringValue)([n]); } } else { outputValue += (0, value_1.getStringValue)([n]); } } return { outputValue, topLevelType, typeError, runtimeValue }; } exports.processDeclarationValue = processDeclarationValue; function evalDeclarationValue(resolver, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough = [], args = [], getResolvedSymbols = (0, stylable_resolver_1.createSymbolResolverWithCache)(resolver, diagnostics || new diagnostics_1.Diagnostics())) { return processDeclarationValue(resolver, getResolvedSymbols, value, meta, node, variableOverride, valueHook, diagnostics, passedThrough, args).outputValue; } exports.evalDeclarationValue = evalDeclarationValue; //# sourceMappingURL=functions.js.map