@stylable/core
Version:
CSS for Components
263 lines • 10.2 kB
JavaScript
;
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