@stylable/core
Version:
CSS for Components
460 lines • 18.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryCollectImportsDeep = exports.parsePseudoImportNamed = exports.parsePseudoImport = exports.parseStImport = exports.parseModuleImportStatement = exports.ensureModuleImport = exports.createAtImportProps = exports.ensureImportsMessages = exports.parseImportMessages = void 0;
const path_1 = __importDefault(require("path"));
const imports_parser_1 = require("@tokey/imports-parser");
const diagnostics_1 = require("../diagnostics");
const postcss_1 = require("postcss");
const string_1 = require("../helpers/string");
const selector_1 = require("./selector");
const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
exports.parseImportMessages = {
ST_IMPORT_STAR: (0, diagnostics_1.createDiagnosticReporter)('05001', 'error', () => '@st-import * is not supported'),
INVALID_ST_IMPORT_FORMAT: (0, diagnostics_1.createDiagnosticReporter)('05002', 'error', (errors) => `Invalid @st-import format:\n - ${errors.join('\n - ')}`),
ST_IMPORT_EMPTY_FROM: (0, diagnostics_1.createDiagnosticReporter)('05003', 'error', () => '@st-import must specify a valid "from" string value'),
EMPTY_IMPORT_FROM: (0, diagnostics_1.createDiagnosticReporter)('05004', 'error', () => '"-st-from" cannot be empty'),
MULTIPLE_FROM_IN_IMPORT: (0, diagnostics_1.createDiagnosticReporter)('05005', 'warning', () => `cannot define multiple "-st-from" declarations in a single import`),
DEFAULT_IMPORT_IS_LOWER_CASE: (0, diagnostics_1.createDiagnosticReporter)('05006', 'warning', () => 'Default import of a Stylable stylesheet must start with an upper-case letter'),
ILLEGAL_PROP_IN_IMPORT: (0, diagnostics_1.createDiagnosticReporter)('05007', 'warning', (propName) => `"${propName}" css attribute cannot be used inside :import block`),
FROM_PROP_MISSING_IN_IMPORT: (0, diagnostics_1.createDiagnosticReporter)('05008', 'error', () => `"-st-from" is missing in :import block`),
INVALID_NAMED_IMPORT_AS: (0, diagnostics_1.createDiagnosticReporter)('05009', 'error', (name) => `Invalid named import "as" with name "${name}"`),
INVALID_NESTED_KEYFRAMES: (0, diagnostics_1.createDiagnosticReporter)('05010', 'error', (name) => `Invalid nested keyframes import "${name}"`),
INVALID_NESTED_TYPED_IMPORT: (0, diagnostics_1.createDiagnosticReporter)('05019', 'warning', (type, name) => `Invalid nested ${type} import "${name}"`),
};
exports.ensureImportsMessages = {
ATTEMPT_OVERRIDE_SYMBOL: (0, diagnostics_1.createDiagnosticReporter)('16001', 'error', (kind, origin, override) => `Attempt to override existing ${kind} import symbol. ${origin} -> ${override}`),
PATCH_CONTAINS_NEW_IMPORT_IN_NEW_IMPORT_NONE_MODE: (0, diagnostics_1.createDiagnosticReporter)('16002', 'error', () => `Attempt to insert new a import in newImport "none" mode`),
};
function createAtImportProps(importObj) {
const named = Object.entries(importObj.named || {});
const keyframes = Object.entries(importObj.keyframes || {});
let params = '';
if (importObj.defaultExport) {
params += importObj.defaultExport;
}
if (importObj.defaultExport && (named.length || keyframes.length)) {
params += ', ';
}
if (named.length || keyframes.length) {
params += '[';
const namedParts = getNamedImportParts(named);
const keyFramesParts = getNamedImportParts(keyframes);
params += namedParts.join(', ');
if (keyFramesParts.length) {
if (namedParts.length) {
params += ', ';
}
params += `keyframes(${keyFramesParts.join(', ')})`;
}
params += ']';
}
params += ` from ${JSON.stringify(importObj.request || '')}`;
return { name: 'st-import', params };
}
exports.createAtImportProps = createAtImportProps;
function ensureModuleImport(ast, importPatches, options, diagnostics = new diagnostics_1.Diagnostics()) {
const patches = createImportPatches(ast, importPatches, options, diagnostics);
if (!diagnostics.reports.length) {
for (const patch of patches) {
patch();
}
}
return { diagnostics };
}
exports.ensureModuleImport = ensureModuleImport;
function createImportPatches(ast, importPatches, { newImport }, diagnostics) {
const patches = [];
const handled = new Set();
for (const node of ast.nodes) {
if (node.type === 'atrule' && node.name === 'st-import') {
const imported = parseStImport(node, '*', diagnostics);
processImports(imported, importPatches, handled, diagnostics);
patches.push(() => node.assign(createAtImportProps(imported)));
}
else if (node.type === 'rule' && node.selector === ':import') {
const imported = parsePseudoImport(node, '*', diagnostics);
processImports(imported, importPatches, handled, diagnostics);
patches.push(() => {
const named = generateNamedValue(imported);
const { defaultDecls, namedDecls } = patchDecls(node, named, imported);
if (imported.defaultExport) {
ensureSingleDecl(defaultDecls, node, '-st-default', imported.defaultExport);
}
if (named.length) {
ensureSingleDecl(namedDecls, node, '-st-named', named.join(', '));
}
});
}
}
if (newImport === 'none') {
if (handled.size !== importPatches.length) {
diagnostics.report(exports.ensureImportsMessages.PATCH_CONTAINS_NEW_IMPORT_IN_NEW_IMPORT_NONE_MODE(), { node: ast });
}
return patches;
}
if (handled.size === importPatches.length) {
return patches;
}
for (const item of importPatches) {
if (handled.has(item)) {
continue;
}
if (!hasDefinitions(item)) {
continue;
}
if (newImport === 'st-import') {
patches.push(() => {
ast.prepend((0, postcss_1.atRule)(createAtImportProps({
defaultExport: item.defaultExport || '',
keyframes: item.keyframes || {},
named: item.named || {},
request: item.request,
})));
});
}
else {
patches.push(() => {
ast.prepend((0, postcss_1.rule)(createPseudoImportProps(item)));
});
}
}
return patches;
}
function setImportObjectFrom(importPath, dirPath, importObj) {
if (!path_1.default.isAbsolute(importPath) && !importPath.startsWith('.')) {
importObj.request = importPath;
importObj.from = importPath;
}
else {
importObj.request = importPath;
importObj.from =
path_1.default.posix && path_1.default.posix.isAbsolute(dirPath) // browser has no posix methods
? path_1.default.posix.resolve(dirPath, importPath)
: path_1.default.resolve(dirPath, importPath);
}
}
function parseModuleImportStatement(node, context, diagnostics) {
if (node.type === 'atrule') {
return parseStImport(node, context, diagnostics);
}
else {
return parsePseudoImport(node, context, diagnostics);
}
}
exports.parseModuleImportStatement = parseModuleImportStatement;
function parseStImport(atRule, context, diagnostics) {
var _a;
const keyframes = {};
const importObj = {
defaultExport: '',
from: '',
request: '',
named: {},
rule: atRule,
context,
keyframes,
typed: {
keyframes,
},
};
const imports = (0, imports_parser_1.parseImports)(`import ${atRule.params}`, '[', ']', true)[0];
if (imports && imports.star) {
diagnostics.report(exports.parseImportMessages.ST_IMPORT_STAR(), { node: atRule });
}
else {
setImportObjectFrom(imports.from || '', context, importObj);
importObj.defaultExport = imports.defaultName || '';
if (importObj.defaultExport &&
!(0, selector_1.isCompRoot)(importObj.defaultExport) &&
importObj.from.endsWith(`.css`)) {
diagnostics.report(exports.parseImportMessages.DEFAULT_IMPORT_IS_LOWER_CASE(), {
node: atRule,
word: importObj.defaultExport,
});
}
if (imports.tagged) {
for (const [kind, namedTyped] of Object.entries(imports.tagged)) {
if (!namedTyped) {
continue;
}
for (const [impName, impAsName] of namedTyped) {
(_a = importObj.typed)[kind] ?? (_a[kind] = {});
importObj.typed[kind][impAsName] = impName;
}
}
}
if (imports.named) {
for (const [impName, impAsName] of imports.named) {
importObj.named[impAsName] = impName;
}
}
if (imports.errors.length) {
diagnostics.report(exports.parseImportMessages.INVALID_ST_IMPORT_FORMAT(imports.errors), {
node: atRule,
});
}
else if (!imports.from?.trim()) {
diagnostics.report(exports.parseImportMessages.ST_IMPORT_EMPTY_FROM(), { node: atRule });
}
}
return importObj;
}
exports.parseStImport = parseStImport;
function parsePseudoImport(rule, context, diagnostics) {
let fromExists = false;
const keyframes = {};
const importObj = {
defaultExport: '',
from: '',
request: '',
named: {},
keyframes,
typed: {
keyframes,
},
rule,
context,
};
rule.walkDecls((decl) => {
switch (decl.prop) {
case `-st-from`: {
const importPath = (0, string_1.stripQuotation)(decl.value);
if (!importPath.trim()) {
diagnostics.report(exports.parseImportMessages.EMPTY_IMPORT_FROM(), { node: decl });
}
if (fromExists) {
diagnostics.report(exports.parseImportMessages.MULTIPLE_FROM_IN_IMPORT(), {
node: rule,
});
}
setImportObjectFrom(importPath, context, importObj);
fromExists = true;
break;
}
case `-st-default`:
importObj.defaultExport = decl.value;
if (!(0, selector_1.isCompRoot)(importObj.defaultExport) && importObj.from.endsWith(`.css`)) {
diagnostics.report(exports.parseImportMessages.DEFAULT_IMPORT_IS_LOWER_CASE(), {
node: decl,
word: importObj.defaultExport,
});
}
break;
case `-st-named`:
{
const { typedMap, namedMap } = parsePseudoImportNamed(decl.value, decl, diagnostics);
importObj.named = namedMap;
importObj.keyframes = typedMap.keyframes || {};
importObj.typed = typedMap;
}
break;
default:
diagnostics.report(exports.parseImportMessages.ILLEGAL_PROP_IN_IMPORT(decl.prop), {
node: decl,
word: decl.prop,
});
break;
}
});
if (!importObj.from) {
diagnostics.report(exports.parseImportMessages.FROM_PROP_MISSING_IN_IMPORT(), {
node: rule,
});
}
return importObj;
}
exports.parsePseudoImport = parsePseudoImport;
function parsePseudoImportNamed(value, node, diagnostics) {
const namedMap = {};
const typedMap = {};
if (value) {
handleNamedTokens((0, postcss_value_parser_1.default)(value), namedMap, typedMap, node, diagnostics);
}
return { namedMap, typedMap };
}
exports.parsePseudoImportNamed = parsePseudoImportNamed;
function createPseudoImportProps(item) {
const nodes = [];
const named = generateNamedValue(item);
if (item.request) {
nodes.push((0, postcss_1.decl)({ prop: '-st-from', value: JSON.stringify(item.request) }));
}
if (item.defaultExport) {
nodes.push((0, postcss_1.decl)({
prop: '-st-default',
value: item.defaultExport,
}));
}
if (named.length) {
nodes.push((0, postcss_1.decl)({
prop: '-st-named',
value: named.join(', '),
}));
}
return {
selector: ':import',
nodes,
};
}
function patchDecls(node, named, pseudoImport) {
const namedDecls = [];
const defaultDecls = [];
for (const decl of node.nodes) {
if (decl.type !== 'decl') {
continue;
}
if (decl.prop === '-st-named') {
decl.assign({ value: named.join(', ') });
namedDecls.push(decl);
}
else if (decl.prop === '-st-default') {
decl.assign({ value: pseudoImport.defaultExport });
defaultDecls.push(decl);
}
}
return { defaultDecls, namedDecls };
}
function ensureSingleDecl(decls, node, prop, value) {
if (!decls.length) {
node.append((0, postcss_1.decl)({ prop, value }));
}
else if (decls.length > 1) {
// remove duplicates keep last one
for (let i = 0; i < decls.length - 1; i++) {
decls[i].remove();
}
}
}
function getNamedImportParts(named) {
const parts = [];
for (const [as, name] of named) {
if (as === name) {
parts.push(name);
}
else {
parts.push(`${name} as ${as}`);
}
}
return parts;
}
function generateNamedValue({ named = {}, keyframes = {}, }) {
const namedParts = getNamedImportParts(Object.entries(named));
const keyframesParts = getNamedImportParts(Object.entries(keyframes));
if (keyframesParts.length) {
namedParts.push(`keyframes(${keyframesParts.join(', ')})`);
}
return namedParts;
}
function hasDefinitions({ named = {}, keyframes = {}, defaultExport, }) {
return defaultExport || Object.keys(named).length || Object.keys(keyframes).length;
}
function processImports(imported, importPatches, handled, diagnostics) {
const ops = ['named', 'keyframes'];
for (const patch of importPatches) {
if (handled.has(patch)) {
continue;
}
if (imported.request === patch.request) {
for (const op of ops) {
const patchBucket = patch[op];
if (!patchBucket) {
continue;
}
for (const [asName, symbol] of Object.entries(patchBucket)) {
const currentSymbol = imported[op][asName];
if (currentSymbol === symbol) {
continue;
}
else if (currentSymbol) {
diagnostics.report(exports.ensureImportsMessages.ATTEMPT_OVERRIDE_SYMBOL(op, currentSymbol === asName
? currentSymbol
: `${currentSymbol} as ${asName}`, symbol === asName ? symbol : `${symbol} as ${asName}`), {
node: imported.rule,
});
}
else {
imported[op][asName] = symbol;
}
}
}
if (patch.defaultExport) {
if (!imported.defaultExport) {
imported.defaultExport = patch.defaultExport;
}
else if (imported.defaultExport !== patch.defaultExport) {
diagnostics.report(exports.ensureImportsMessages.ATTEMPT_OVERRIDE_SYMBOL('default', imported.defaultExport, patch.defaultExport), {
node: imported.rule,
});
}
}
handled.add(patch);
}
}
}
function handleNamedTokens(tokens, mainBucket, typedBuckets, node, diagnostics) {
var _a;
const { nodes } = tokens;
for (let i = 0; i < nodes.length; i++) {
const token = nodes[i];
if (token.type === 'word') {
const space = nodes[i + 1];
const as = nodes[i + 2];
const spaceAfter = nodes[i + 3];
const asName = nodes[i + 4];
if (isImportAs(space, as)) {
if (spaceAfter?.type === 'space' && asName?.type === 'word') {
mainBucket[asName.value] = token.value;
i += 4; //ignore next 4 tokens
}
else {
i += !asName ? 3 : 2;
diagnostics.report(exports.parseImportMessages.INVALID_NAMED_IMPORT_AS(token.value), {
node,
});
continue;
}
}
else {
mainBucket[token.value] = token.value;
}
}
else if (token.type === 'function') {
if (!typedBuckets) {
diagnostics.report(exports.parseImportMessages.INVALID_NESTED_TYPED_IMPORT(token.value, postcss_value_parser_1.default.stringify(token)), { node });
}
else {
typedBuckets[_a = token.value] ?? (typedBuckets[_a] = {});
handleNamedTokens(token, typedBuckets[token.value], null, node, diagnostics);
}
}
}
}
function isImportAs(space, as) {
return space?.type === 'space' && as?.type === 'word' && as?.value === 'as';
}
function tryCollectImportsDeep(resolver, meta, imports = new Set(), onImport = undefined, depth = 1, origin = meta.source) {
for (const { context, request } of meta.getImportStatements()) {
try {
const resolved = resolver.resolvePath(context, request);
if (resolved === origin) {
continue;
}
onImport?.({ context, request, resolved, depth });
if (!imports.has(resolved)) {
imports.add(resolved);
if (resolved.endsWith('.st.css')) {
tryCollectImportsDeep(resolver, resolver.analyze(resolved), imports, onImport, depth + 1, origin);
}
}
}
catch {
/** */
}
}
return imports;
}
exports.tryCollectImportsDeep = tryCollectImportsDeep;
//# sourceMappingURL=import.js.map