@stylable/core
Version:
CSS for Components
200 lines • 9.85 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.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