1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.resolveStateParam = exports.createAttributeState = exports.createStateWithParamClassName = exports.createBooleanStateClassName = exports.setStateToNode = exports.transformPseudoStateSelector = exports.validateStateArgument = exports.validateStateDefinition = exports.processPseudoStates = exports.stateErrors = exports.stateWithParamDelimiter = exports.booleanStateDelimiter = exports.stateMiddleDelimiter = void 0;
|
7 | const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
|
8 | const is_vendor_prefixed_1 = __importDefault(require("is-vendor-prefixed"));
|
9 | const functions_1 = require("./functions");
|
10 | const native_reserved_lists_1 = require("./native-reserved-lists");
|
11 | const state_validators_1 = require("./state-validators");
|
12 | const stylable_utils_1 = require("./stylable-utils");
|
13 | const stylable_value_parsers_1 = require("./stylable-value-parsers");
|
14 | const stylable_value_parsers_2 = require("./stylable-value-parsers");
|
15 | const utils_1 = require("./utils");
|
16 | const { hasOwnProperty } = Object.prototype;
|
17 | exports.stateMiddleDelimiter = '-';
|
18 | exports.booleanStateDelimiter = '--';
|
19 | exports.stateWithParamDelimiter = exports.booleanStateDelimiter + exports.stateMiddleDelimiter;
|
20 | exports.stateErrors = {
|
21 | UNKNOWN_STATE_USAGE: (name) => `unknown pseudo-state "${name}"`,
|
22 | UNKNOWN_STATE_TYPE: (name, type) => `pseudo-state "${name}" defined with unknown type: "${type}"`,
|
23 | TOO_MANY_STATE_TYPES: (name, types) => `pseudo-state "${name}(${types.join(', ')})" definition must be of a single type`,
|
24 | NO_STATE_TYPE_GIVEN: (name) => `pseudo-state "${name}" expected a definition of a single type, but received none`,
|
25 | TOO_MANY_ARGS_IN_VALIDATOR: (name, validator, args) => `pseudo-state "${name}" expected "${validator}" validator to receive a single argument, but it received "${args.join(', ')}"`,
|
26 | STATE_STARTS_WITH_HYPHEN: (name) => `state "${name}" declaration cannot begin with a "${exports.stateMiddleDelimiter}" chararcter`,
|
27 | };
|
28 |
|
29 | function processPseudoStates(value, decl, diagnostics) {
|
30 | const mappedStates = {};
|
31 | const ast = postcss_value_parser_1.default(value);
|
32 | const statesSplitByComma = stylable_value_parsers_1.groupValues(ast.nodes);
|
33 | statesSplitByComma.forEach((workingState) => {
|
34 | const [stateDefinition, ...stateDefault] = workingState;
|
35 | if (stateDefinition.value.startsWith('-')) {
|
36 | diagnostics.error(decl, exports.stateErrors.STATE_STARTS_WITH_HYPHEN(stateDefinition.value), {
|
37 | word: stateDefinition.value,
|
38 | });
|
39 | }
|
40 | if (stateDefinition.type === 'function') {
|
41 | resolveStateType(stateDefinition, mappedStates, stateDefault, diagnostics, decl);
|
42 | }
|
43 | else if (stateDefinition.type === 'word') {
|
44 | resolveBooleanState(mappedStates, stateDefinition);
|
45 | }
|
46 | else {
|
47 |
|
48 | }
|
49 | });
|
50 | return mappedStates;
|
51 | }
|
52 | exports.processPseudoStates = processPseudoStates;
|
53 | function resolveStateType(stateDefinition, mappedStates, stateDefault, diagnostics, decl) {
|
54 | if (stateDefinition.type === 'function' && stateDefinition.nodes.length === 0) {
|
55 | resolveBooleanState(mappedStates, stateDefinition);
|
56 | diagnostics.warn(decl, exports.stateErrors.NO_STATE_TYPE_GIVEN(stateDefinition.value), {
|
57 | word: decl.value,
|
58 | });
|
59 | return;
|
60 | }
|
61 | if (stateDefinition.nodes.length > 1) {
|
62 | diagnostics.warn(decl, exports.stateErrors.TOO_MANY_STATE_TYPES(stateDefinition.value, stylable_value_parsers_1.listOptions(stateDefinition)), { word: decl.value });
|
63 | }
|
64 | const paramType = stateDefinition.nodes[0];
|
65 | const stateType = {
|
66 | type: stateDefinition.nodes[0].value,
|
67 | arguments: [],
|
68 | defaultValue: postcss_value_parser_1.default
|
69 | .stringify(stateDefault)
|
70 | .trim(),
|
71 | };
|
72 | if (isCustomMapping(stateDefinition)) {
|
73 | mappedStates[stateDefinition.value] = stateType.type.trim().replace(/\\["']/g, '"');
|
74 | }
|
75 | else if (typeof stateType === 'object' && stateType.type === 'boolean') {
|
76 | resolveBooleanState(mappedStates, stateDefinition);
|
77 | return;
|
78 | }
|
79 | else if (paramType.type === 'function' && stateType.type in state_validators_1.systemValidators) {
|
80 | if (paramType.nodes.length > 0) {
|
81 | resolveArguments(paramType, stateType, stateDefinition.value, diagnostics, decl);
|
82 | }
|
83 | mappedStates[stateDefinition.value] = stateType;
|
84 | }
|
85 | else if (stateType.type in state_validators_1.systemValidators) {
|
86 | mappedStates[stateDefinition.value] = stateType;
|
87 | }
|
88 | else {
|
89 | diagnostics.warn(decl, exports.stateErrors.UNKNOWN_STATE_TYPE(stateDefinition.value, paramType.value), { word: paramType.value });
|
90 | }
|
91 | }
|
92 | function resolveArguments(paramType, stateType, name, diagnostics, decl) {
|
93 | const separatedByComma = stylable_value_parsers_1.groupValues(paramType.nodes);
|
94 | separatedByComma.forEach((group) => {
|
95 | const validator = group[0];
|
96 | if (validator.type === 'function') {
|
97 | const args = stylable_value_parsers_1.listOptions(validator);
|
98 | if (args.length > 1) {
|
99 | diagnostics.warn(decl, exports.stateErrors.TOO_MANY_ARGS_IN_VALIDATOR(name, validator.value, args), { word: decl.value });
|
100 | }
|
101 | else {
|
102 | stateType.arguments.push({
|
103 | name: validator.value,
|
104 | args,
|
105 | });
|
106 | }
|
107 | }
|
108 | else if (validator.type === 'string' || validator.type === 'word') {
|
109 | stateType.arguments.push(validator.value);
|
110 | }
|
111 | });
|
112 | }
|
113 | function isCustomMapping(stateDefinition) {
|
114 | return stateDefinition.nodes.length === 1 && stateDefinition.nodes[0].type === 'string';
|
115 | }
|
116 | function resolveBooleanState(mappedStates, stateDefinition) {
|
117 | const currentState = mappedStates[stateDefinition.type];
|
118 | if (!currentState) {
|
119 | mappedStates[stateDefinition.value] = null;
|
120 | }
|
121 | else {
|
122 |
|
123 | }
|
124 | }
|
125 |
|
126 | function validateStateDefinition(decl, meta, resolver, diagnostics) {
|
127 | if (decl.parent && decl.parent.type !== 'root') {
|
128 | const container = decl.parent;
|
129 | if (container.type !== 'atrule') {
|
130 | const sRule = container;
|
131 | if (sRule.selectorAst.nodes && sRule.selectorAst.nodes.length === 1) {
|
132 | const singleSelectorAst = sRule.selectorAst.nodes[0];
|
133 | const selectorChunk = singleSelectorAst.nodes;
|
134 | if (selectorChunk.length === 1 && selectorChunk[0].type === 'class') {
|
135 | const className = selectorChunk[0].name;
|
136 | const classMeta = meta.classes[className];
|
137 | const states = classMeta[stylable_value_parsers_2.valueMapping.states];
|
138 | if (classMeta && classMeta._kind === 'class' && states) {
|
139 | for (const stateName in states) {
|
140 |
|
141 | const state = states[stateName];
|
142 | if (state && typeof state === 'object') {
|
143 | const res = validateStateArgument(state, meta, state.defaultValue || '', resolver, diagnostics, sRule, true, !!state.defaultValue);
|
144 | if (res.errors) {
|
145 | res.errors.unshift(`pseudo-state "${stateName}" default value "${state.defaultValue}" failed validation:`);
|
146 | diagnostics.warn(decl, res.errors.join('\n'), {
|
147 | word: decl.value,
|
148 | });
|
149 | }
|
150 | }
|
151 | }
|
152 | }
|
153 | else {
|
154 |
|
155 | }
|
156 | }
|
157 | }
|
158 | }
|
159 | }
|
160 | }
|
161 | exports.validateStateDefinition = validateStateDefinition;
|
162 | function validateStateArgument(stateAst, meta, value, resolver, diagnostics, rule, validateDefinition, validateValue = true) {
|
163 | const resolvedValidations = {
|
164 | res: resolveParam(meta, resolver, diagnostics, rule, value || stateAst.defaultValue),
|
165 | errors: null,
|
166 | };
|
167 | const { type: paramType } = stateAst;
|
168 | const validator = state_validators_1.systemValidators[paramType];
|
169 | try {
|
170 | if (resolvedValidations.res || validateDefinition) {
|
171 | const { errors } = validator.validate(resolvedValidations.res, stateAst.arguments, resolveParam.bind(null, meta, resolver, diagnostics, rule), !!validateDefinition, validateValue);
|
172 | resolvedValidations.errors = errors;
|
173 | }
|
174 | }
|
175 | catch (error) {
|
176 |
|
177 | }
|
178 | return resolvedValidations;
|
179 | }
|
180 | exports.validateStateArgument = validateStateArgument;
|
181 | function transformPseudoStateSelector(meta, node, name, symbol, origin, originSymbol, resolver, diagnostics, rule) {
|
182 | let current = meta;
|
183 | let currentSymbol = symbol;
|
184 | if (originSymbol && symbol !== originSymbol) {
|
185 | current = origin;
|
186 | currentSymbol = originSymbol;
|
187 | }
|
188 | let found = false;
|
189 | while (current && currentSymbol) {
|
190 | if (currentSymbol._kind === 'class' || currentSymbol._kind === 'element') {
|
191 | const states = currentSymbol[stylable_value_parsers_2.valueMapping.states];
|
192 | const extend = currentSymbol[stylable_value_parsers_2.valueMapping.extends];
|
193 | const alias = currentSymbol.alias;
|
194 | if (states && hasOwnProperty.call(states, name)) {
|
195 | found = true;
|
196 | setStateToNode(states, meta, name, node, current.namespace, resolver, diagnostics, rule);
|
197 | break;
|
198 | }
|
199 | else if (extend) {
|
200 | if (current.mappedSymbols[extend.name] &&
|
201 | current.mappedSymbols[extend.name]._kind !== 'import') {
|
202 | const nextCurrentSymbol = current.mappedSymbols[extend.name];
|
203 | if (currentSymbol === nextCurrentSymbol) {
|
204 | break;
|
205 | }
|
206 | currentSymbol = nextCurrentSymbol;
|
207 | }
|
208 | else {
|
209 | const next = resolver.resolve(extend);
|
210 | if (next && next.meta) {
|
211 | currentSymbol = next.symbol;
|
212 | current = next.meta;
|
213 | }
|
214 | else {
|
215 | break;
|
216 | }
|
217 | }
|
218 | }
|
219 | else if (alias) {
|
220 | const next = resolver.resolve(alias);
|
221 | if (next && next.meta) {
|
222 | currentSymbol = next.symbol;
|
223 | current = next.meta;
|
224 | }
|
225 | else {
|
226 | break;
|
227 | }
|
228 | }
|
229 | else {
|
230 | break;
|
231 | }
|
232 | }
|
233 | else {
|
234 | break;
|
235 | }
|
236 | }
|
237 | if (!found && rule) {
|
238 | if (!native_reserved_lists_1.nativePseudoClasses.includes(name) && !is_vendor_prefixed_1.default(name)) {
|
239 | diagnostics.warn(rule, exports.stateErrors.UNKNOWN_STATE_USAGE(name), { word: name });
|
240 | }
|
241 | }
|
242 | return meta;
|
243 | }
|
244 | exports.transformPseudoStateSelector = transformPseudoStateSelector;
|
245 | function setStateToNode(states, meta, name, node, namespace, resolver, diagnostics, rule) {
|
246 | const stateDef = states[name];
|
247 | if (stateDef === null) {
|
248 | node.type = 'class';
|
249 | node.name = createBooleanStateClassName(name, namespace);
|
250 | }
|
251 | else if (typeof stateDef === 'string') {
|
252 | node.type = 'invalid';
|
253 | node.value = stateDef;
|
254 | }
|
255 | else if (typeof stateDef === 'object') {
|
256 | resolveStateValue(meta, resolver, diagnostics, rule, node, stateDef, name, namespace);
|
257 | }
|
258 | }
|
259 | exports.setStateToNode = setStateToNode;
|
260 | function resolveStateValue(meta, resolver, diagnostics, rule, node, stateDef, name, namespace) {
|
261 | let actualParam = resolveParam(meta, resolver, diagnostics, rule, node.content || stateDef.defaultValue);
|
262 | const validator = state_validators_1.systemValidators[stateDef.type];
|
263 | let stateParamOutput;
|
264 | try {
|
265 | stateParamOutput = validator.validate(actualParam, stateDef.arguments, resolveParam.bind(null, meta, resolver, diagnostics, rule), false, true);
|
266 | }
|
267 | catch (e) {
|
268 |
|
269 | }
|
270 | if (stateParamOutput !== undefined) {
|
271 | if (stateParamOutput.res !== actualParam) {
|
272 | actualParam = stateParamOutput.res;
|
273 | }
|
274 | if (rule && stateParamOutput.errors) {
|
275 | stateParamOutput.errors.unshift(`pseudo-state "${name}" with parameter "${actualParam}" failed validation:`);
|
276 | diagnostics.warn(rule, stateParamOutput.errors.join('\n'), { word: actualParam });
|
277 | }
|
278 | }
|
279 | const strippedParam = utils_1.stripQuotation(actualParam);
|
280 | if (stylable_utils_1.isValidClassName(strippedParam)) {
|
281 | node.type = 'class';
|
282 | node.name = createStateWithParamClassName(name, namespace, strippedParam);
|
283 | }
|
284 | else {
|
285 | node.type = 'attribute';
|
286 | node.content = createAttributeState(name, namespace, strippedParam);
|
287 | }
|
288 | }
|
289 | function resolveParam(meta, resolver, diagnostics, rule, nodeContent) {
|
290 | const defaultStringValue = '';
|
291 | const param = nodeContent || defaultStringValue;
|
292 | return functions_1.evalDeclarationValue(resolver, param, meta, rule, undefined, undefined, diagnostics);
|
293 | }
|
294 | function createBooleanStateClassName(stateName, namespace) {
|
295 | return `${namespace}${exports.booleanStateDelimiter}${stateName}`;
|
296 | }
|
297 | exports.createBooleanStateClassName = createBooleanStateClassName;
|
298 | function createStateWithParamClassName(stateName, namespace, param) {
|
299 | return `${namespace}${exports.stateWithParamDelimiter}${stateName}${resolveStateParam(param)}`;
|
300 | }
|
301 | exports.createStateWithParamClassName = createStateWithParamClassName;
|
302 | function createAttributeState(stateName, namespace, param) {
|
303 | return `class~="${createStateWithParamClassName(stateName, namespace, param)}"`;
|
304 | }
|
305 | exports.createAttributeState = createAttributeState;
|
306 | function resolveStateParam(param) {
|
307 | if (stylable_utils_1.isValidClassName(param)) {
|
308 | return `${exports.stateMiddleDelimiter}${param.length}${exports.stateMiddleDelimiter}${param}`;
|
309 | }
|
310 | else {
|
311 | return `${exports.stateMiddleDelimiter}${param.length}${exports.stateMiddleDelimiter}${utils_1.stripQuotation(JSON.stringify(param).replace(/\s/gm, '_'))}`;
|
312 | }
|
313 | }
|
314 | exports.resolveStateParam = resolveStateParam;
|
315 |
|
\ | No newline at end of file |