UNPKG

@stylable/core

Version:

CSS for Components

263 lines 10.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAll = exports.get = exports.getKeyframesStatements = exports.hooks = exports.diagnostics = exports.reservedKeyFrames = void 0; const feature_1 = require("./feature"); const STSymbol = __importStar(require("./st-symbol")); const STImport = __importStar(require("./st-import")); const plugable_record_1 = require("../helpers/plugable-record"); const rule_1 = require("../helpers/rule"); const namespace_1 = require("../helpers/namespace"); const global_1 = require("../helpers/global"); const postcss_value_parser_1 = __importDefault(require("postcss-value-parser")); const diagnostics_1 = require("../diagnostics"); exports.reservedKeyFrames = [ 'none', 'inherited', 'initial', 'unset', /* single-timing-function */ 'linear', 'ease', 'ease-in', 'ease-in-out', 'ease-out', 'step-start', 'step-end', 'start', 'end', /* single-animation-iteration-count */ 'infinite', /* single-animation-direction */ 'normal', 'reverse', 'alternate', 'alternate-reverse', /* single-animation-fill-mode */ 'forwards', 'backwards', 'both', /* single-animation-play-state */ 'running', 'paused', ]; exports.diagnostics = { ILLEGAL_KEYFRAMES_NESTING: (0, diagnostics_1.createDiagnosticReporter)('02001', 'error', () => `illegal nested "@keyframes"`), MISSING_KEYFRAMES_NAME: (0, diagnostics_1.createDiagnosticReporter)('02002', 'error', () => '"@keyframes" missing parameter'), MISSING_KEYFRAMES_NAME_INSIDE_GLOBAL: (0, diagnostics_1.createDiagnosticReporter)('02003', 'error', () => `"@keyframes" missing parameter inside "${global_1.GLOBAL_FUNC}()"`), KEYFRAME_NAME_RESERVED: (0, diagnostics_1.createDiagnosticReporter)('02004', 'error', (name) => `keyframes "${name}" is reserved`), UNKNOWN_IMPORTED_KEYFRAMES: (0, diagnostics_1.createDiagnosticReporter)('02005', 'error', (name, path) => `cannot resolve imported keyframes "${name}" from stylesheet "${path}"`), }; const dataKey = plugable_record_1.plugableRecord.key('keyframes'); // HOOKS STImport.ImportTypeHook.set(`keyframes`, (context, localName, importName, importDef) => { addKeyframes({ context, name: localName, importName, ast: importDef.rule, importDef, }); }); exports.hooks = (0, feature_1.createFeature)({ metaInit({ meta }) { plugable_record_1.plugableRecord.set(meta.data, dataKey, { statements: [], paths: {}, imports: [] }); }, analyzeAtRule({ context, atRule }) { let { params: name } = atRule; // check nesting validity if (!(0, rule_1.isInConditionalGroup)(atRule, true)) { context.diagnostics.report(exports.diagnostics.ILLEGAL_KEYFRAMES_NESTING(), { node: atRule }); return; } // save keyframes declarations const { statements: keyframesAsts } = plugable_record_1.plugableRecord.getUnsafe(context.meta.data, dataKey); keyframesAsts.push(atRule); // validate name if (!name) { context.diagnostics.report(exports.diagnostics.MISSING_KEYFRAMES_NAME(), { node: atRule }); return; } // const isStylable = context.meta.type === 'stylable'; let global; const globalName = isStylable ? (0, global_1.globalValue)(name) : undefined; if (globalName !== undefined) { name = globalName; global = true; } if (name === '') { context.diagnostics.report(exports.diagnostics.MISSING_KEYFRAMES_NAME_INSIDE_GLOBAL(), { node: atRule, }); return; } if (exports.reservedKeyFrames.includes(name)) { context.diagnostics.report(exports.diagnostics.KEYFRAME_NAME_RESERVED(name), { node: atRule, word: name, }); } addKeyframes({ context, name, importName: name, ast: atRule, global: isStylable ? global : true, }); }, transformResolve({ context }) { const symbols = STSymbol.getAllByType(context.meta, `keyframes`); const resolved = { record: {}, locals: new Set(), }; const resolvedSymbols = context.getResolvedSymbols(context.meta); for (const [name, symbol] of Object.entries(symbols)) { const res = resolvedSymbols.keyframes[name]; if (res) { resolved.record[name] = res; if (res.meta === context.meta) { resolved.locals.add(name); } } else if (symbol.import) { context.diagnostics.report(exports.diagnostics.UNKNOWN_IMPORTED_KEYFRAMES(symbol.name, symbol.import.request), { node: symbol.import.rule, word: symbol.name, }); } } return resolved; }, transformAtRuleNode({ context, atRule, resolved }) { const globalName = context.meta.type === 'stylable' ? (0, global_1.globalValue)(atRule.params) : undefined; const name = globalName ?? atRule.params; if (!name) { return; } const resolve = resolved.record[name]; /* js keyframes mixins won't have resolved keyframes */ atRule.params = resolve ? getTransformedName(resolve) : globalName ?? (0, namespace_1.namespace)(name, context.meta.namespace); }, transformDeclaration({ decl, resolved }) { const parsed = (0, postcss_value_parser_1.default)(decl.value); // ToDo: improve by correctly parse & identify `animation-name` // ToDo: handle symbols from js mixin parsed.nodes.forEach((node) => { const resolve = resolved.record[node.value]; const scoped = resolve && getTransformedName(resolve); if (scoped) { node.value = scoped; } }); decl.value = parsed.toString(); }, transformJSExports({ exports, resolved }) { for (const name of resolved.locals) { exports.keyframes[name] = getTransformedName(resolved.record[name]); } }, }); // API function getKeyframesStatements({ data }) { const { statements } = plugable_record_1.plugableRecord.getUnsafe(data, dataKey); return statements; } exports.getKeyframesStatements = getKeyframesStatements; function get(meta, name) { return STSymbol.get(meta, name, `keyframes`); } exports.get = get; function getAll(meta) { return STSymbol.getAllByType(meta, `keyframes`); } exports.getAll = getAll; function addKeyframes({ context, name, importName, ast, global, importDef, }) { /** * keyframes are safe to redeclare in case they are unique within their context (applied * in different times/cases), for example 2 keyframes statements can override each other * if 1 is applied on the root (always) and the other in @media (on some condition). * * > in case keyframes are imported, then no local keyframes * > are allowed to override them (will report a warning). */ const isFirstInPath = addKeyframesDeclaration(context.meta, name, ast, !!importDef); // first must not be `safeRedeclare` const safeRedeclare = isFirstInPath && !!STSymbol.get(context.meta, name, `keyframes`); // fields are confusing in this symbol: // name: the import name if imported OR the local name // alias: the local name STSymbol.addSymbol({ context, node: ast, localName: name, symbol: { _kind: 'keyframes', alias: name, name: importName, global, import: importDef, }, safeRedeclare, }); } function addKeyframesDeclaration(meta, name, origin, isImported) { let path = ``; let current = origin.parent; while (current) { if (current.type === `rule`) { path += ` -> ` + current.selector; } else if (current.type === `atrule`) { path += ` -> ` + current.name + ` ` + current.params; } current = current.parent; } const { paths, imports } = plugable_record_1.plugableRecord.getUnsafe(meta.data, dataKey); if (!paths[path]) { paths[path] = []; } const isFirstInPath = !paths[path].includes(name); const isImportedBefore = imports.includes(name); paths[path].push(name); if (isImported) { imports.push(name); } return isFirstInPath && !isImportedBefore; } function getTransformedName({ symbol, meta }) { return symbol.global ? symbol.alias : (0, namespace_1.namespace)(symbol.alias, meta.namespace); } //# sourceMappingURL=css-keyframes.js.map