UNPKG

@stylable/core

Version:

CSS for Components

460 lines 18.8 kB
"use strict"; 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