UNPKG

@stylable/core

Version:

CSS for Components

690 lines 33.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveStateParam = exports.createStateWithParamClassName = exports.createBooleanStateClassName = exports.isTemplateState = exports.transformPseudoClassToCustomState = exports.validateStateArgument = exports.validateRuleStateDefinition = exports.systemValidators = exports.validationErrors = exports.parseStateValue = exports.parsePseudoStates = exports.stateDiagnostics = exports.stateWithParamDelimiter = exports.booleanStateDelimiter = exports.stateMiddleDelimiter = void 0; const postcss_value_parser_1 = __importDefault(require("postcss-value-parser")); const cssesc_1 = __importDefault(require("cssesc")); const diagnostics_1 = require("../diagnostics"); const selector_1 = require("./selector"); const value_1 = require("./value"); const string_1 = require("./string"); const functions_1 = require("../functions"); const features_1 = require("../features"); const native_reserved_lists_1 = require("../native-reserved-lists"); const css_value_parser_1 = require("@tokey/css-value-parser"); const css_value_seeker_1 = require("./css-value-seeker"); exports.stateMiddleDelimiter = '-'; exports.booleanStateDelimiter = '--'; exports.stateWithParamDelimiter = exports.booleanStateDelimiter + exports.stateMiddleDelimiter; exports.stateDiagnostics = { MISSING_TYPE_OR_TEMPLATE: (0, diagnostics_1.createDiagnosticReporter)('08000', 'error', (name) => `pseudo-state "${name}" missing type or template`), UNKNOWN_STATE_TYPE: (0, diagnostics_1.createDiagnosticReporter)('08002', 'error', (name, type) => `pseudo-state "${name}" defined with unknown type: "${type}"`), TOO_MANY_STATE_TYPES: (0, diagnostics_1.createDiagnosticReporter)('08003', 'error', (name, types) => `pseudo-state "${name}(${types.join(', ')})" definition must be of a single type`), NO_STATE_TYPE_GIVEN: (0, diagnostics_1.createDiagnosticReporter)('08005', 'warning', (name) => `pseudo-state "${name}" expected a definition of a single type, but received none`), TOO_MANY_ARGS_IN_VALIDATOR: (0, diagnostics_1.createDiagnosticReporter)('08006', 'error', (name, validator, args) => `pseudo-state "${name}" expected "${validator}" validator to receive a single argument, but it received "${args.join(', ')}"`), STATE_STARTS_WITH_HYPHEN: (0, diagnostics_1.createDiagnosticReporter)('08007', 'error', (name) => `state "${name}" declaration cannot begin with a "${exports.stateMiddleDelimiter}" character`), RESERVED_NATIVE_STATE: (0, diagnostics_1.createDiagnosticReporter)('08008', 'warning', (name) => `state "${name}" is reserved for native pseudo-class`), DEFAULT_PARAM_FAILS_VALIDATION: (0, diagnostics_1.createDiagnosticReporter)('08010', 'error', (stateName, defaultValue, errors) => `pseudo-state "${stateName}" default value "${defaultValue}" failed validation:\n${errors.join('\n')}`), NO_STATE_ARGUMENT_GIVEN: (0, diagnostics_1.createDiagnosticReporter)('08004', 'error', (name, type) => `pseudo-state "${name}" expected argument of type "${type}" but got none`), FAILED_STATE_VALIDATION: (0, diagnostics_1.createDiagnosticReporter)('08009', 'error', (name, actualParam, errors) => [ `pseudo-state "${name}" with parameter "${actualParam}" failed validation:`, ...errors, ].join('\n')), TEMPLATE_MISSING_PLACEHOLDER: (0, diagnostics_1.createDiagnosticReporter)('08011', 'warning', (state, template) => `pseudo-state "${state}" template "${template}" is missing a placeholder, use "$0" to set the parameter insertion place`), TEMPLATE_MULTI_PARAMETERS: (0, diagnostics_1.createDiagnosticReporter)('08012', 'error', (state) => `pseudo-state "${state}" template only supports a single parameter`), TEMPLATE_MISSING_PARAMETER: (0, diagnostics_1.createDiagnosticReporter)('08013', 'error', (state) => `pseudo-state "${state}" template expected a parameter definition`), UNSUPPORTED_MULTI_SELECTOR: (0, diagnostics_1.createDiagnosticReporter)('08014', 'error', (state, finalSelector) => `pseudo-state "${state}" resulted in an unsupported multi selector "${finalSelector}"`), UNSUPPORTED_COMPLEX_SELECTOR: (0, diagnostics_1.createDiagnosticReporter)('08015', 'error', (state, finalSelector) => `pseudo-state "${state}" resulted in an unsupported complex selector "${finalSelector}"`), INVALID_SELECTOR: (0, diagnostics_1.createDiagnosticReporter)('08016', 'error', (state, finalSelector) => `pseudo-state "${state}" resulted in an invalid selector "${finalSelector}"`), UNSUPPORTED_INITIAL_SELECTOR: (0, diagnostics_1.createDiagnosticReporter)('08017', 'error', (state, finalSelector) => `pseudo-state "${state}" result cannot start with a type or universal selector "${finalSelector}"`), NO_PARAM_REQUIRED: (0, diagnostics_1.createDiagnosticReporter)('08018', 'error', (name, param) => `pseudo-state "${name}" accepts no parameter, but received "${param}"`), }; // parse function parsePseudoStates(value, decl, diagnostics) { const mappedStates = {}; const ast = (0, postcss_value_parser_1.default)(value); const statesSplitByComma = (0, value_1.groupValues)(ast.nodes); statesSplitByComma.forEach((workingState) => { const [stateDefinition, ...stateDefault] = workingState; const stateName = stateDefinition.value; if (!validateStateName(stateName, diagnostics, decl)) { return; } if (stateDefinition.type === 'function') { resolveStateType(stateDefinition, mappedStates, stateDefault, diagnostics, decl); } else if (stateDefinition.type === 'word') { resolveBooleanState(mappedStates, stateDefinition); } else { // TODO: Invalid state, edge case needs warning } }); return mappedStates; } exports.parsePseudoStates = parsePseudoStates; function validateStateName(name, diagnostics, node) { if (name.startsWith('-')) { diagnostics.report(exports.stateDiagnostics.STATE_STARTS_WITH_HYPHEN(name), { node: node, word: name, }); } else if (native_reserved_lists_1.reservedFunctionalPseudoClasses.includes(name)) { diagnostics.report(exports.stateDiagnostics.RESERVED_NATIVE_STATE(name), { node: node, word: name, }); return false; } return true; } function parseStateValue(value, node, diagnostics) { let stateName = ''; let stateDef = null; /*boolean*/ let amountTaken = 0; const customIdentResult = (0, css_value_seeker_1.findCustomIdent)(value, 0); const [amountToName, nameNode] = customIdentResult[0] ? customIdentResult : (0, css_value_seeker_1.findNextCallNode)(value, 0); if (nameNode && validateStateName(nameNode.value, diagnostics, node)) { amountTaken += amountToName; stateName = nameNode.value; // state with parameter if (nameNode.type === 'call') { // take all of the definition since default value takes the rest amountTaken = value.length; // ToDo: translate resolveStateType to tokey and remove the double parsing const postcssStateValue = (0, postcss_value_parser_1.default)((0, css_value_parser_1.stringifyCSSValue)(value.slice(amountToName - 1))); // get state definition const [stateDefinition, ...stateDefault] = postcssStateValue.nodes; const stateMap = {}; resolveStateType(stateDefinition, stateMap, stateDefault, diagnostics, node // ToDo: change to accept any postcss node ); if (stateMap[stateName]) { stateDef = stateMap[stateName]; } } } if (stateName) { return [amountTaken, stateDef]; } return [0, undefined]; } exports.parseStateValue = parseStateValue; function resolveBooleanState(mappedStates, stateDefinition) { const currentState = mappedStates[stateDefinition.value]; if (!currentState) { mappedStates[stateDefinition.value] = null; // add boolean state } else { // TODO: warn with such name already exists } } function resolveStateType(stateDefinition, mappedStates, stateDefault, diagnostics, decl) { const stateName = stateDefinition.value; if (stateDefinition.nodes.length === 0) { resolveBooleanState(mappedStates, stateDefinition); diagnostics.report(exports.stateDiagnostics.NO_STATE_TYPE_GIVEN(stateName), { node: decl, word: decl.value, }); return; } const { paramType, argsFirstNode, argsFullValue } = collectStateArgsDef(stateDefinition.nodes); if (!paramType) { diagnostics.report(exports.stateDiagnostics.MISSING_TYPE_OR_TEMPLATE(stateName), { node: decl, }); return; } if (paramType?.type === 'string') { defineTemplateState(stateName, paramType, argsFirstNode, argsFullValue, mappedStates, diagnostics, decl); } else { if (argsFullValue.length > 1) { diagnostics.report(exports.stateDiagnostics.TOO_MANY_STATE_TYPES(stateName, argsFirstNode.map((argNode) => argNode ? postcss_value_parser_1.default.stringify(argNode) : '')), { node: decl, word: decl.value, }); } defineParamState(stateName, paramType, stateDefault, mappedStates, diagnostics, stateDefinition, decl); } } function defineTemplateState(stateName, templateDef, argsFirstNode, argsFullValue, mappedStates, diagnostics, decl) { const template = (0, string_1.stripQuotation)(postcss_value_parser_1.default.stringify(templateDef)); if (argsFullValue.length === 1) { // simple template with no params const selectorStr = template.trim().replace(/\\["']/g, '"'); const selectorAst = (0, selector_1.parseSelectorWithCache)(selectorStr, { clone: true }); if (!validateTemplateSelector({ stateName, selectorStr, selectorAst, cssNode: decl, diagnostics, })) { return; } else { mappedStates[stateName] = selectorStr; } } else if (argsFullValue.length === 2) { // single parameter template if (!template.includes('$0')) { diagnostics.report(exports.stateDiagnostics.TEMPLATE_MISSING_PLACEHOLDER(stateName, template), { node: decl, word: template, }); } const paramFullDef = argsFullValue[1]; const paramTypeDef = argsFirstNode[1]; if (!paramTypeDef) { diagnostics.report(exports.stateDiagnostics.TEMPLATE_MISSING_PARAMETER(stateName), { node: decl, }); return; } const param = createStateParamDef(stateName + ' parameter', paramTypeDef, paramFullDef.splice(paramFullDef.indexOf(paramTypeDef) + 1), diagnostics, decl); if (!param) { // UNKNOWN_STATE_TYPE reported in createStateParamDef return; } const templateStateType = { type: 'template', template, params: [param], }; mappedStates[stateName] = templateStateType; } else { // unsupported multiple params diagnostics.report(exports.stateDiagnostics.TEMPLATE_MULTI_PARAMETERS(stateName), { node: decl, }); } } function defineParamState(stateName, paramType, stateDefault, mappedStates, diagnostics, stateDefinition, decl) { if (paramType.value === 'boolean') { // explicit boolean // ToDo: remove support resolveBooleanState(mappedStates, stateDefinition); } else { const stateParamDef = createStateParamDef(stateName, paramType, stateDefault, diagnostics, decl); if (stateParamDef) { mappedStates[stateName] = stateParamDef; } } } function createStateParamDef(stateName, typeDef, stateDefault, diagnostics, decl) { const type = typeDef.value; if (type in exports.systemValidators && (typeDef.type === 'function' || typeDef.type === 'word')) { const stateType = { type, arguments: [], defaultValue: postcss_value_parser_1.default .stringify(stateDefault) .trim(), }; if (typeDef.type === 'function' && typeDef.nodes.length > 0) { resolveArguments(typeDef, stateType, stateName, diagnostics, decl); } return stateType; } else { const srcValue = postcss_value_parser_1.default.stringify(typeDef); diagnostics.report(exports.stateDiagnostics.UNKNOWN_STATE_TYPE(stateName, srcValue), { node: decl, word: srcValue, }); return; } } function collectStateArgsDef(nodes) { const argsFullValue = []; const argsFirstNode = []; let collectedArg = []; let firstActualValue = undefined; for (const node of nodes) { if (node.type === 'div') { argsFullValue.push(collectedArg); argsFirstNode.push(firstActualValue); collectedArg = []; firstActualValue = undefined; } else { collectedArg.push(node); if (!firstActualValue && node.type !== 'space' && node.type !== 'comment') { firstActualValue = node; } } } if (collectedArg.length) { argsFullValue.push(collectedArg); argsFirstNode.push(firstActualValue); } const paramType = argsFirstNode[0]; return { paramType, argsFullValue, argsFirstNode }; } function resolveArguments(paramType, stateType, name, diagnostics, decl) { const separatedByComma = (0, value_1.groupValues)(paramType.nodes); separatedByComma.forEach((group) => { const validator = group[0]; if (validator.type === 'function') { const args = (0, value_1.listOptions)(validator); if (args.length > 1) { diagnostics.report(exports.stateDiagnostics.TOO_MANY_ARGS_IN_VALIDATOR(name, validator.value, args), { node: decl, word: decl.value, }); } else { stateType.arguments.push({ name: validator.value, args, }); } } else if (validator.type === 'string' || validator.type === 'word') { stateType.arguments.push(validator.value); } }); } exports.validationErrors = { string: { STRING_TYPE_VALIDATION_FAILED: (actualParam) => `"${actualParam}" should be of type string`, REGEX_VALIDATION_FAILED: (regex, actualParam) => `expected "${actualParam}" to match regex "${regex}"`, CONTAINS_VALIDATION_FAILED: (shouldContain, actualParam) => `expected "${actualParam}" to contain string "${shouldContain}"`, MIN_LENGTH_VALIDATION_FAILED: (length, actualParam) => `expected "${actualParam}" to be of length longer than or equal to ${length}`, MAX_LENGTH_VALIDATION_FAILED: (length, actualParam) => `expected "${actualParam}" to be of length shorter than or equal to ${length}`, UKNOWN_VALIDATOR: (name) => `encountered unknown string validator "${name}"`, }, number: { NUMBER_TYPE_VALIDATION_FAILED: (actualParam) => `expected "${actualParam}" to be of type number`, MIN_VALIDATION_FAILED: (actualParam, min) => `expected "${actualParam}" to be larger than or equal to ${min}`, MAX_VALIDATION_FAILED: (actualParam, max) => `expected "${actualParam}" to be lesser then or equal to ${max}`, MULTIPLE_OF_VALIDATION_FAILED: (actualParam, multipleOf) => `expected "${actualParam}" to be a multiple of ${multipleOf}`, UKNOWN_VALIDATOR: (name) => `encountered unknown number validator "${name}"`, }, enum: { ENUM_TYPE_VALIDATION_FAILED: (actualParam, options) => `expected "${actualParam}" to be one of the options: "${options.join(', ')}"`, NO_OPTIONS_DEFINED: () => `expected enum to be defined with one option or more`, }, }; exports.systemValidators = { string: { validate(value, validators, resolveParam, validateDefinition, validateValue) { const res = value; const errors = []; if (validateValue && typeof value !== 'string') { errors.push(exports.validationErrors.string.STRING_TYPE_VALIDATION_FAILED(value)); } if (validators.length > 0) { validators.forEach((validatorMeta) => { if (typeof validatorMeta === 'object') { if (this.subValidators && this.subValidators[validatorMeta.name]) { const subValidator = this.subValidators[validatorMeta.name]; const validationRes = subValidator(value, resolveParam(validatorMeta.args[0])); if (validateValue && validationRes.errors) { errors.push(...validationRes.errors); } } else if (validateDefinition) { errors.push(exports.validationErrors.string.UKNOWN_VALIDATOR(validatorMeta.name)); } } }); } return { res, errors: errors.length ? errors : null }; }, subValidators: { regex: (value, regex) => { const r = new RegExp(regex); const valid = r.test(value); return { res: value, errors: valid ? null : [exports.validationErrors.string.REGEX_VALIDATION_FAILED(regex, value)], }; }, contains: (value, checkedValue) => { const valid = !!~value.indexOf(checkedValue); return { res: value, errors: valid ? null : [exports.validationErrors.string.CONTAINS_VALIDATION_FAILED(checkedValue, value)], }; }, minLength: (value, length) => { const valid = value.length >= Number(length); return { res: value, errors: valid ? null : [exports.validationErrors.string.MIN_LENGTH_VALIDATION_FAILED(length, value)], }; }, maxLength: (value, length) => { const valid = value.length <= Number(length); return { res: value, errors: valid ? null : [exports.validationErrors.string.MAX_LENGTH_VALIDATION_FAILED(length, value)], }; }, }, }, number: { validate(value, validators, resolveParam, validateDefinition, validateValue) { const res = value; const errors = []; if (isNaN(value)) { if (validateValue) { errors.push(exports.validationErrors.number.NUMBER_TYPE_VALIDATION_FAILED(value)); } } else if (validators.length > 0) { validators.forEach((validatorMeta) => { if (typeof validatorMeta === 'object') { if (this.subValidators && this.subValidators[validatorMeta.name]) { const subValidator = this.subValidators[validatorMeta.name]; const validationRes = subValidator(value, resolveParam(validatorMeta.args[0])); if (validateValue && validationRes.errors) { errors.push(...validationRes.errors); } } else if (validateDefinition) { errors.push(exports.validationErrors.number.UKNOWN_VALIDATOR(validatorMeta.name)); } } }); } return { res, errors: errors.length ? errors : null }; }, subValidators: { min: (value, minValue) => { const valid = Number(value) >= Number(minValue); return { res: value, errors: valid ? null : [exports.validationErrors.number.MIN_VALIDATION_FAILED(value, minValue)], }; }, max: (value, maxValue) => { const valid = Number(value) <= Number(maxValue); return { res: value, errors: valid ? null : [exports.validationErrors.number.MAX_VALIDATION_FAILED(value, maxValue)], }; }, multipleOf: (value, multipleOf) => { const valid = Number(value) % Number(multipleOf) === 0; return { res: value, errors: valid ? null : [ exports.validationErrors.number.MULTIPLE_OF_VALIDATION_FAILED(value, multipleOf), ], }; }, }, }, enum: { validate(value, options, resolveParam, validateDefinition, validateValue) { const res = value; const errors = []; const stringOptions = []; if (options.length) { const isOneOf = options.some((option) => { if (typeof option === 'string') { stringOptions.push(option); return resolveParam(option) === value; } return true; }); if (validateValue && !isOneOf) { errors.push(exports.validationErrors.enum.ENUM_TYPE_VALIDATION_FAILED(value, stringOptions)); } } else if (validateDefinition) { errors.push(exports.validationErrors.enum.NO_OPTIONS_DEFINED()); } return { res, errors: errors.length ? errors : null }; }, }, }; function validateRuleStateDefinition(selector, selectorNode, meta, resolver, diagnostics) { const selectorAst = (0, selector_1.parseSelectorWithCache)(selector); if (selectorAst.length && selectorAst.length === 1) { const singleSelectorAst = selectorAst[0]; const selectorChunk = singleSelectorAst.nodes; if (selectorChunk.length === 1 && selectorChunk[0].type === 'class') { const className = selectorChunk[0].value; const classMeta = features_1.CSSClass.get(meta, className); const states = classMeta?.[`-st-states`]; if (states && classMeta._kind === 'class') { for (const stateName in states) { // TODO: Sort out types const state = states[stateName]; if (state && typeof state === 'object') { const stateParam = isTemplateState(state) ? state.params[0] : state; const { errors } = validateStateArgument(stateParam, meta, stateParam.defaultValue || '', resolver, diagnostics, selectorNode, true, !!stateParam.defaultValue); if (errors && selectorNode.nodes) { for (const node of selectorNode.nodes) { if (node.type === 'decl' && node.prop === `-st-states`) { diagnostics.report(exports.stateDiagnostics.DEFAULT_PARAM_FAILS_VALIDATION(stateName, stateParam.defaultValue || '', errors), { node: node, word: node.value, }); break; } } } } } } else { // TODO: error state on non-class } } } } exports.validateRuleStateDefinition = validateRuleStateDefinition; function validateStateArgument(stateAst, meta, value, resolver, diagnostics, selectorNode, validateDefinition, validateValue = true) { const resolvedValidations = { res: resolveParam(meta, resolver, diagnostics, selectorNode, value || stateAst.defaultValue), errors: null, }; const { type: paramType } = stateAst; const validator = exports.systemValidators[paramType]; try { if (resolvedValidations.res || validateDefinition) { const { errors } = validator.validate(resolvedValidations.res, stateAst.arguments, resolveParam.bind(null, meta, resolver, diagnostics, selectorNode), !!validateDefinition, validateValue); resolvedValidations.errors = errors; } } catch (error) { // TODO: warn about validation throwing exception } return resolvedValidations; } exports.validateStateArgument = validateStateArgument; // transform function transformPseudoClassToCustomState(stateDef, meta, name, stateNode, namespace, resolver, diagnostics, selectorNode) { if (stateDef === null || typeof stateDef === 'string') { if (stateNode.nodes && selectorNode) { diagnostics.report(exports.stateDiagnostics.NO_PARAM_REQUIRED(name, (0, selector_1.stringifySelector)(stateNode.nodes)), { node: selectorNode, word: (0, selector_1.stringifySelector)(stateNode), }); } if (stateDef === null) { // boolean (0, selector_1.convertToClass)(stateNode).value = createBooleanStateClassName(name, namespace); } else { // static template selector // simply concat global mapped selector - ToDo: maybe change to 'selector' (0, selector_1.convertToInvalid)(stateNode).value = stateDef; } delete stateNode.nodes; } else if (typeof stateDef === 'object') { if (isTemplateState(stateDef)) { convertTemplateState(meta, resolver, diagnostics, selectorNode, stateNode, stateDef, name); } else { resolveStateValue(meta, resolver, diagnostics, selectorNode, stateNode, stateDef, name, namespace); } } } exports.transformPseudoClassToCustomState = transformPseudoClassToCustomState; function isTemplateState(state) { return !!state && typeof state === 'object' && state.type === 'template'; } exports.isTemplateState = isTemplateState; function createBooleanStateClassName(stateName, namespace) { const escapedNamespace = (0, cssesc_1.default)(namespace, { isIdentifier: true }); return `${escapedNamespace}${exports.booleanStateDelimiter}${stateName}`; } exports.createBooleanStateClassName = createBooleanStateClassName; function createStateWithParamClassName(stateName, namespace, param) { const escapedNamespace = (0, cssesc_1.default)(namespace, { isIdentifier: true }); return `${escapedNamespace}${exports.stateWithParamDelimiter}${stateName}${resolveStateParam(param, true)}`; } exports.createStateWithParamClassName = createStateWithParamClassName; function resolveStateParam(param, escape = false) { const result = `${exports.stateMiddleDelimiter}${param.length}${exports.stateMiddleDelimiter}${param.replace(/\s/gm, '_')}`; // adding/removing initial `s` to indicate that it's not the first param of the identifier return escape ? (0, cssesc_1.default)(`s` + result, { isIdentifier: true }).slice(1) : result; } exports.resolveStateParam = resolveStateParam; function convertTemplateState(meta, resolver, diagnostics, selectorNode, stateNode, stateParamDef, name) { const paramStateDef = stateParamDef.params[0]; const resolvedParam = getParamInput(meta, resolver, diagnostics, selectorNode, stateNode, paramStateDef, name); validateParam(meta, resolver, diagnostics, selectorNode, paramStateDef, resolvedParam, name); const strippedParam = (0, string_1.stripQuotation)(resolvedParam); transformMappedStateWithParam({ stateName: name, template: stateParamDef.template, param: strippedParam, node: stateNode, selectorNode: selectorNode, diagnostics, }); } function getParamInput(meta, resolver, diagnostics, selectorNode, stateNode, stateParamDef, name) { const inputValue = stateNode.nodes && stateNode.nodes.length ? (0, selector_1.stringifySelector)(stateNode.nodes) : ``; const resolvedParam = resolveParam(meta, resolver, diagnostics, selectorNode, inputValue ? inputValue : stateParamDef.defaultValue); if (selectorNode && !inputValue && !stateParamDef.defaultValue) { diagnostics.report(exports.stateDiagnostics.NO_STATE_ARGUMENT_GIVEN(name, stateParamDef.type), { node: selectorNode, word: name, }); } return resolvedParam; } function validateParam(meta, resolver, diagnostics, selectorNode, stateParamDef, resolvedParam, name) { const validator = exports.systemValidators[stateParamDef.type]; let stateParamOutput; try { stateParamOutput = validator.validate(resolvedParam, stateParamDef.arguments, resolveParam.bind(null, meta, resolver, diagnostics, selectorNode), false, true); } catch (e) { // TODO: warn about validation throwing exception } if (stateParamOutput !== undefined) { if (stateParamOutput.res !== resolvedParam) { resolvedParam = stateParamOutput.res; } if (selectorNode && stateParamOutput.errors) { diagnostics.report(exports.stateDiagnostics.FAILED_STATE_VALIDATION(name, resolvedParam, stateParamOutput.errors), { node: selectorNode, word: resolvedParam, }); } } } function resolveStateValue(meta, resolver, diagnostics, selectorNode, stateNode, stateParamDef, name, namespace) { const resolvedParam = getParamInput(meta, resolver, diagnostics, selectorNode, stateNode, stateParamDef, name); validateParam(meta, resolver, diagnostics, selectorNode, stateParamDef, resolvedParam, name); const strippedParam = (0, string_1.stripQuotation)(resolvedParam); (0, selector_1.convertToClass)(stateNode).value = createStateWithParamClassName(name, namespace, strippedParam); delete stateNode.nodes; } function transformMappedStateWithParam({ stateName, template, param, node, selectorNode, diagnostics, }) { const selectorStr = template.replace(/\$0/g, param); const selectorAst = (0, selector_1.parseSelectorWithCache)(selectorStr, { clone: true }); if (!validateTemplateSelector({ stateName, selectorStr, selectorAst, cssNode: selectorNode, diagnostics, })) { return; } (0, selector_1.convertToSelector)(node).nodes = selectorAst[0].nodes; } function validateTemplateSelector({ stateName, selectorStr, selectorAst, cssNode, diagnostics, }) { if (selectorAst.length > 1) { if (cssNode) { diagnostics.report(exports.stateDiagnostics.UNSUPPORTED_MULTI_SELECTOR(stateName, selectorStr), { node: cssNode, }); } return false; } else { const firstSelector = selectorAst[0].nodes.find(({ type }) => type !== 'comment'); if (firstSelector?.type === 'type' || firstSelector?.type === 'universal') { if (cssNode) { diagnostics.report(exports.stateDiagnostics.UNSUPPORTED_INITIAL_SELECTOR(stateName, selectorStr), { node: cssNode, }); } return false; } let unexpectedSelector = undefined; for (const node of selectorAst[0].nodes) { if (node.type === 'combinator' || node.type === 'invalid') { unexpectedSelector = node; break; } } if (unexpectedSelector) { if (cssNode) { switch (unexpectedSelector.type) { case 'combinator': diagnostics.report(exports.stateDiagnostics.UNSUPPORTED_COMPLEX_SELECTOR(stateName, selectorStr), { node: cssNode, }); break; case 'invalid': diagnostics.report(exports.stateDiagnostics.INVALID_SELECTOR(stateName, selectorStr), { node: cssNode, }); break; } } return false; } } return true; } function resolveParam(meta, resolver, diagnostics, node, nodeContent) { const defaultStringValue = ''; const param = nodeContent || defaultStringValue; return (0, functions_1.evalDeclarationValue)(resolver, param, meta, node, undefined, undefined, diagnostics); } //# sourceMappingURL=custom-state.js.map