@stylable/core
Advanced tools
Comparing version 3.11.14 to 3.12.0
@@ -23,4 +23,5 @@ export { safeParse } from './parser'; | ||
export * from './module-resolver'; | ||
export * from './timed-cache'; | ||
import * as pseudoStates from './pseudo-states'; | ||
export { pseudoStates }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -49,4 +49,5 @@ "use strict"; | ||
__exportStar(require("./module-resolver"), exports); | ||
__exportStar(require("./timed-cache"), exports); | ||
const pseudoStates = __importStar(require("./pseudo-states")); | ||
exports.pseudoStates = pseudoStates; | ||
//# sourceMappingURL=index.js.map |
@@ -38,3 +38,3 @@ import * as postcss from 'postcss'; | ||
keyframes: Record<string, string>; | ||
rule: postcss.Rule; | ||
rule: postcss.Rule | postcss.AtRule; | ||
fromRelative: string; | ||
@@ -41,0 +41,0 @@ context: string; |
@@ -30,2 +30,6 @@ import * as postcss from 'postcss'; | ||
NO_IMPORT_IN_ST_SCOPE(): string; | ||
NO_ST_IMPORT_IN_NESTED_SCOPE(): string; | ||
ST_IMPORT_STAR(): string; | ||
ST_IMPORT_EMPTY_FROM(): string; | ||
INVALID_ST_IMPORT_FORMAT(errors: string[]): string; | ||
NO_KEYFRAMES_IN_ST_SCOPE(): string; | ||
@@ -42,2 +46,3 @@ MISSING_SCOPING_PARAM(): string; | ||
protected meta: StylableMeta; | ||
protected dirContext: string; | ||
constructor(diagnostics?: Diagnostics, resolveNamespace?: typeof processNamespace); | ||
@@ -52,2 +57,3 @@ process(root: postcss.Root): StylableMeta; | ||
protected checkRedeclareKeyframes(symbolName: string, node: postcss.Node): import("./stylable-meta").KeyframesSymbol; | ||
protected checkForScopedNodeAfter(rule: postcss.Rule, nodes: SelectorAstNode[], index: number): boolean; | ||
protected addElementSymbolOnce(name: string, rule: postcss.Rule): void; | ||
@@ -63,3 +69,5 @@ protected addClassSymbolOnce(name: string, rule: postcss.Rule): void; | ||
protected extendTypedRule(node: postcss.Node, selector: string, key: keyof StylableDirectives, value: any): void; | ||
protected handleStImport(atRule: postcss.AtRule): Imported; | ||
protected handleImport(rule: postcss.Rule): Imported; | ||
private handleScope; | ||
} | ||
@@ -66,0 +74,0 @@ export declare function validateScopingSelector(atRule: postcss.AtRule, { selector: scopingSelector }: SRule, diagnostics: Diagnostics): void; |
@@ -33,2 +33,3 @@ "use strict"; | ||
const postcss_value_parser_1 = __importDefault(require("postcss-value-parser")); | ||
const toky_1 = require("toky"); | ||
const diagnostics_1 = require("./diagnostics"); | ||
@@ -116,2 +117,14 @@ const selector_utils_1 = require("./selector-utils"); | ||
}, | ||
NO_ST_IMPORT_IN_NESTED_SCOPE() { | ||
return `cannot use "@st-import" inside of nested scope`; | ||
}, | ||
ST_IMPORT_STAR() { | ||
return '@st-import * is not supported'; | ||
}, | ||
ST_IMPORT_EMPTY_FROM() { | ||
return '@st-import must specify a valid "from" string value'; | ||
}, | ||
INVALID_ST_IMPORT_FORMAT(errors) { | ||
return `Invalid @st-import format:\n - ${errors.join('\n - ')}`; | ||
}, | ||
NO_KEYFRAMES_IN_ST_SCOPE() { | ||
@@ -143,2 +156,3 @@ return `cannot use "@keyframes" inside of "@st-scope"`; | ||
this.meta = new stylable_meta_1.StylableMeta(root, this.diagnostics); | ||
this.dirContext = path_1.default.dirname(this.meta.source); | ||
this.handleAtRules(root); | ||
@@ -166,19 +180,4 @@ const stubs = this.insertCustomSelectorsStubs(); | ||
}); | ||
this.meta.scopes.forEach((atRule) => { | ||
const scopingRule = postcss.rule({ selector: atRule.params }); | ||
this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, this.diagnostics); | ||
if (scopingRule.selector) { | ||
atRule.walkRules((rule) => { | ||
const scopedRule = rule.clone({ | ||
selector: stylable_utils_1.scopeSelector(scopingRule.selector, rule.selector, false) | ||
.selector, | ||
}); | ||
scopedRule.stScopeSelector = atRule.params; | ||
rule.replaceWith(scopedRule); | ||
}); | ||
} | ||
atRule.replaceWith(atRule.nodes || []); | ||
}); | ||
stubs.forEach((s) => s && s.remove()); | ||
this.meta.scopes.forEach((scope) => this.handleScope(scope)); | ||
return this.meta; | ||
@@ -203,2 +202,3 @@ } | ||
root.walkAtRules((atRule) => { | ||
var _a; | ||
switch (atRule.name) { | ||
@@ -253,2 +253,13 @@ case 'namespace': { | ||
break; | ||
case 'st-import': | ||
if (((_a = atRule.parent) === null || _a === void 0 ? void 0 : _a.type) !== 'root') { | ||
this.diagnostics.warn(atRule, exports.processorWarnings.NO_ST_IMPORT_IN_NESTED_SCOPE()); | ||
atRule.remove(); | ||
} | ||
else { | ||
const _import = this.handleStImport(atRule); | ||
this.meta.imports.push(_import); | ||
this.addImportSymbols(_import); | ||
} | ||
break; | ||
case 'st-global-custom-property': { | ||
@@ -306,5 +317,7 @@ const cssVarsByComma = atRule.params.split(','); | ||
const checker = selector_utils_1.createSimpleSelectorChecker(); | ||
const validRoot = selector_utils_1.isRootValid(rule.selectorAst, 'root'); | ||
let locallyScoped = false; | ||
selector_utils_1.traverseNode(rule.selectorAst, (node, _index, _nodes) => { | ||
selector_utils_1.traverseNode(rule.selectorAst, (node, index, nodes) => { | ||
if (node.type === 'selector') { | ||
locallyScoped = false; | ||
} | ||
if (!checker(node)) { | ||
@@ -322,5 +335,5 @@ rule.isSimpleSelector = false; | ||
} | ||
const _import = this.handleImport(rule); | ||
this.meta.imports.push(_import); | ||
this.addImportSymbols(_import); | ||
const imported = this.handleImport(rule); | ||
this.meta.imports.push(imported); | ||
this.addImportSymbols(imported); | ||
return false; | ||
@@ -354,5 +367,10 @@ } | ||
else if (locallyScoped === false && !inStScope) { | ||
this.diagnostics.warn(rule, exports.processorWarnings.UNSCOPED_CLASS(name), { | ||
word: name, | ||
}); | ||
if (this.checkForScopedNodeAfter(rule, nodes, index) === false) { | ||
this.diagnostics.warn(rule, exports.processorWarnings.UNSCOPED_CLASS(name), { | ||
word: name, | ||
}); | ||
} | ||
else { | ||
locallyScoped = true; | ||
} | ||
} | ||
@@ -364,5 +382,10 @@ } | ||
if (locallyScoped === false && !inStScope) { | ||
this.diagnostics.warn(rule, exports.processorWarnings.UNSCOPED_ELEMENT(name), { | ||
word: name, | ||
}); | ||
if (this.checkForScopedNodeAfter(rule, nodes, index) === false) { | ||
this.diagnostics.warn(rule, exports.processorWarnings.UNSCOPED_ELEMENT(name), { | ||
word: name, | ||
}); | ||
} | ||
else { | ||
locallyScoped = true; | ||
} | ||
} | ||
@@ -382,3 +405,3 @@ } | ||
} | ||
if (!validRoot) { | ||
if (!selector_utils_1.isRootValid(rule.selectorAst, 'root')) { | ||
this.diagnostics.warn(rule, exports.processorWarnings.ROOT_AFTER_SPACING()); | ||
@@ -404,2 +427,22 @@ } | ||
} | ||
checkForScopedNodeAfter(rule, nodes, index) { | ||
for (let i = index + 1; i < nodes.length; i++) { | ||
const element = nodes[i]; | ||
if (!element) { | ||
break; | ||
} | ||
if (element.type === 'spacing' || element.type === 'operator') { | ||
break; | ||
} | ||
if (element.type === 'class') { | ||
this.addClassSymbolOnce(element.name, rule); | ||
if (this.meta.classes[element.name]) { | ||
if (!this.meta.classes[element.name].alias) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
addElementSymbolOnce(name, rule) { | ||
@@ -456,3 +499,3 @@ if (selector_utils_1.isCompRoot(name) && !this.meta.elements[name]) { | ||
import: importDef, | ||
context: path_1.default.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -467,3 +510,3 @@ } | ||
import: importDef, | ||
context: path_1.default.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -662,2 +705,41 @@ }); | ||
} | ||
handleStImport(atRule) { | ||
var _a, _b; | ||
const importObj = { | ||
defaultExport: '', | ||
from: '', | ||
fromRelative: '', | ||
named: {}, | ||
rule: atRule, | ||
context: this.dirContext, | ||
keyframes: {}, | ||
}; | ||
const imports = toky_1.tokenizeImports(`import ${atRule.params}`, '[', ']', true)[0]; | ||
if (imports && imports.star) { | ||
this.diagnostics.error(atRule, exports.processorWarnings.ST_IMPORT_STAR()); | ||
} | ||
else { | ||
importObj.defaultExport = imports.defaultName || ''; | ||
setImportObjectFrom(imports.from || '', this.dirContext, importObj); | ||
if ((_a = imports.tagged) === null || _a === void 0 ? void 0 : _a.keyframes) { | ||
// importObj.keyframes = imports.tagged?.keyframes; | ||
for (const [impName, impAsName] of Object.entries(imports.tagged.keyframes)) { | ||
importObj.keyframes[impAsName] = impName; | ||
} | ||
} | ||
if (imports.named) { | ||
for (const [impName, impAsName] of Object.entries(imports.named)) { | ||
importObj.named[impAsName] = impName; | ||
} | ||
} | ||
if (imports.errors.length) { | ||
this.diagnostics.error(atRule, exports.processorWarnings.INVALID_ST_IMPORT_FORMAT(imports.errors)); | ||
} | ||
else if (!((_b = imports.from) === null || _b === void 0 ? void 0 : _b.trim())) { | ||
this.diagnostics.error(atRule, exports.processorWarnings.ST_IMPORT_EMPTY_FROM()); | ||
} | ||
} | ||
atRule.remove(); | ||
return importObj; | ||
} | ||
handleImport(rule) { | ||
@@ -672,3 +754,3 @@ let fromExists = false; | ||
rule, | ||
context: path_1.default.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -685,15 +767,3 @@ rule.walkDecls((decl) => { | ||
} | ||
if (!path_1.default.isAbsolute(importPath) && !importPath.startsWith('.')) { | ||
// 3rd party request | ||
importObj.fromRelative = importPath; | ||
importObj.from = importPath; | ||
} | ||
else { | ||
importObj.fromRelative = importPath; | ||
const dirPath = path_1.default.dirname(this.meta.source); | ||
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); | ||
} | ||
setImportObjectFrom(importPath, this.dirContext, importObj); | ||
fromExists = true; | ||
@@ -726,4 +796,32 @@ break; | ||
} | ||
handleScope(atRule) { | ||
const scopingRule = postcss.rule({ selector: atRule.params }); | ||
this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, this.diagnostics); | ||
if (scopingRule.selector) { | ||
atRule.walkRules((rule) => { | ||
const scopedRule = rule.clone({ | ||
selector: stylable_utils_1.scopeSelector(scopingRule.selector, rule.selector, false).selector, | ||
}); | ||
scopedRule.stScopeSelector = atRule.params; | ||
rule.replaceWith(scopedRule); | ||
}); | ||
} | ||
atRule.replaceWith(atRule.nodes || []); | ||
} | ||
} | ||
exports.StylableProcessor = StylableProcessor; | ||
function setImportObjectFrom(importPath, dirPath, importObj) { | ||
if (!path_1.default.isAbsolute(importPath) && !importPath.startsWith('.')) { | ||
importObj.fromRelative = importPath; | ||
importObj.from = importPath; | ||
} | ||
else { | ||
importObj.fromRelative = 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 validateScopingSelector(atRule, { selector: scopingSelector }, diagnostics) { | ||
@@ -730,0 +828,0 @@ if (!scopingSelector) { |
@@ -10,2 +10,8 @@ import { FileProcessor } from './cached-process-file'; | ||
}; | ||
export declare type JsModule = { | ||
default?: unknown; | ||
[key: string]: unknown; | ||
}; | ||
export declare type CachedModule = StylableMeta | JsModule | null; | ||
export declare type StylableResolverCache = Map<string, StylableMeta | JsModule | null>; | ||
export interface CSSResolve<T extends StylableSymbol = StylableSymbol> { | ||
@@ -25,4 +31,6 @@ _kind: 'css'; | ||
protected requireModule: (modulePath: string) => any; | ||
constructor(fileProcessor: FileProcessor<StylableMeta>, requireModule: (modulePath: string) => any); | ||
resolveImported(imported: Imported, name: string): CSSResolve<StylableSymbol> | JSResolve | null; | ||
protected cache?: StylableResolverCache | undefined; | ||
constructor(fileProcessor: FileProcessor<StylableMeta>, requireModule: (modulePath: string) => any, cache?: StylableResolverCache | undefined); | ||
private getModule; | ||
resolveImported(imported: Imported, name: string, subtype?: 'mappedSymbols' | 'mappedKeyframes'): CSSResolve | JSResolve | null; | ||
resolveImport(importSymbol: ImportSymbol): CSSResolve<StylableSymbol> | JSResolve | null; | ||
@@ -29,0 +37,0 @@ resolve(maybeImport: StylableSymbol | undefined): CSSResolve | JSResolve | null; |
@@ -19,35 +19,58 @@ "use strict"; | ||
exports.isInPath = isInPath; | ||
// this is a safe cache key delimiter for all OS; | ||
const safePathDelimiter = ';:'; | ||
class StylableResolver { | ||
constructor(fileProcessor, requireModule) { | ||
constructor(fileProcessor, requireModule, cache) { | ||
this.fileProcessor = fileProcessor; | ||
this.requireModule = requireModule; | ||
this.cache = cache; | ||
} | ||
resolveImported(imported, name) { | ||
const { context, from } = imported; | ||
let symbol; | ||
getModule({ context, from }) { | ||
var _a, _b; | ||
const key = `${context}${safePathDelimiter}${from}`; | ||
if ((_a = this.cache) === null || _a === void 0 ? void 0 : _a.has(key)) { | ||
return this.cache.get(key); | ||
} | ||
let res; | ||
if (from.match(/\.css$/)) { | ||
let meta; | ||
try { | ||
meta = this.fileProcessor.process(from, false, context); | ||
symbol = !name | ||
? meta.mappedSymbols[meta.root] | ||
: meta.mappedSymbols[name] || meta.mappedKeyframes[name]; | ||
res = this.fileProcessor.process(from, false, context); | ||
} | ||
catch (e) { | ||
return null; | ||
res = null; | ||
} | ||
return { _kind: 'css', symbol, meta }; | ||
} | ||
else { | ||
let _module; | ||
try { | ||
_module = this.requireModule(this.fileProcessor.resolvePath(from, context)); | ||
res = this.requireModule(this.fileProcessor.resolvePath(from, context)); | ||
} | ||
catch { | ||
return null; | ||
res = null; | ||
} | ||
symbol = !name ? _module.default || _module : _module[name]; | ||
return { _kind: 'js', symbol, meta: null }; | ||
} | ||
(_b = this.cache) === null || _b === void 0 ? void 0 : _b.set(key, res); | ||
return res; | ||
} | ||
resolveImported(imported, name, subtype = 'mappedSymbols') { | ||
const res = this.getModule(imported); | ||
if (res === null) { | ||
return null; | ||
} | ||
if (imported.from.match(/\.css$/)) { | ||
const meta = res; | ||
return { | ||
_kind: 'css', | ||
symbol: !name ? meta.mappedSymbols[meta.root] : meta[subtype][name], | ||
meta, | ||
}; | ||
} | ||
else { | ||
const jsModule = res; | ||
return { | ||
_kind: 'js', | ||
symbol: !name ? jsModule.default || jsModule : jsModule[name], | ||
meta: null, | ||
}; | ||
} | ||
} | ||
resolveImport(importSymbol) { | ||
@@ -90,3 +113,3 @@ const name = importSymbol.type === 'named' ? importSymbol.name : ''; | ||
while ((_a = current.symbol) === null || _a === void 0 ? void 0 : _a.import) { | ||
const res = this.resolveImported(current.symbol.import, current.symbol.name); | ||
const res = this.resolveImported(current.symbol.import, current.symbol.name, 'mappedKeyframes'); | ||
if ((res === null || res === void 0 ? void 0 : res._kind) === 'css' && ((_b = res.symbol) === null || _b === void 0 ? void 0 : _b._kind) === 'keyframes') { | ||
@@ -93,0 +116,0 @@ const { meta, symbol } = res; |
@@ -6,3 +6,3 @@ import * as postcss from 'postcss'; | ||
import { ClassSymbol, ElementSymbol, StylableMeta, StylableSymbol } from './stylable-processor'; | ||
import { CSSResolve, StylableResolver } from './stylable-resolver'; | ||
import { CSSResolve, StylableResolverCache, StylableResolver } from './stylable-resolver'; | ||
export interface ResolvedElement { | ||
@@ -53,2 +53,3 @@ name: string; | ||
mode?: EnvMode; | ||
resolverCache?: StylableResolverCache; | ||
} | ||
@@ -55,0 +56,0 @@ export interface AdditionalSelector { |
@@ -71,3 +71,3 @@ "use strict"; | ||
this.postProcessor = options.postProcessor; | ||
this.resolver = new stylable_resolver_1.StylableResolver(options.fileProcessor, options.requireModule); | ||
this.resolver = new stylable_resolver_1.StylableResolver(options.fileProcessor, options.requireModule, options.resolverCache); | ||
this.mode = options.mode || 'production'; | ||
@@ -74,0 +74,0 @@ } |
@@ -68,3 +68,3 @@ import * as postcss from 'postcss'; | ||
}; | ||
'-st-named'(value: string, node: postcss.Declaration, diagnostics: Diagnostics): { | ||
'-st-named'(value: string, node: postcss.Declaration | postcss.AtRule, diagnostics: Diagnostics): { | ||
namedMap: Record<string, string>; | ||
@@ -71,0 +71,0 @@ keyframesMap: Record<string, string>; |
import { FileProcessor, MinimalFS } from './cached-process-file'; | ||
import { Diagnostics } from './diagnostics'; | ||
import { CssParser } from './parser'; | ||
import { processNamespace, StylableMeta } from './stylable-processor'; | ||
import { StylableResolver } from './stylable-resolver'; | ||
import { processNamespace, StylableMeta, StylableProcessor } from './stylable-processor'; | ||
import { StylableResolverCache, StylableResolver } from './stylable-resolver'; | ||
import { StylableResults, StylableTransformer, TransformerOptions, TransformHooks } from './stylable-transformer'; | ||
@@ -25,6 +25,9 @@ import { TimedCacheOptions } from './timed-cache'; | ||
resolveNamespace?: typeof processNamespace; | ||
/** @deprecated use resolverCache instead */ | ||
timedCacheOptions?: Omit<TimedCacheOptions, 'createKey'>; | ||
resolveModule?: ModuleResolver; | ||
cssParser?: CssParser; | ||
resolverCache?: StylableResolverCache; | ||
} | ||
export declare type CreateProcessorOptions = Pick<StylableConfig, 'resolveNamespace'>; | ||
export declare class Stylable { | ||
@@ -45,2 +48,3 @@ projectRoot: string; | ||
protected cssParser: CssParser; | ||
protected resolverCache?: StylableResolverCache | undefined; | ||
static create(config: StylableConfig): Stylable; | ||
@@ -50,3 +54,6 @@ fileProcessor: FileProcessor<StylableMeta>; | ||
resolvePath: (ctx: string | undefined, path: string) => string; | ||
constructor(projectRoot: string, fileSystem: MinimalFS, requireModule: (path: string) => any, delimiter?: string, onProcess?: ((meta: StylableMeta, path: string) => StylableMeta) | undefined, diagnostics?: Diagnostics, hooks?: TransformHooks, resolveOptions?: any, optimizer?: IStylableOptimizer | undefined, mode?: 'production' | 'development', resolveNamespace?: typeof processNamespace | undefined, timedCacheOptions?: Omit<TimedCacheOptions, 'createKey'>, resolveModule?: ModuleResolver | undefined, cssParser?: CssParser); | ||
constructor(projectRoot: string, fileSystem: MinimalFS, requireModule: (path: string) => any, delimiter?: string, onProcess?: ((meta: StylableMeta, path: string) => StylableMeta) | undefined, diagnostics?: Diagnostics, hooks?: TransformHooks, resolveOptions?: any, optimizer?: IStylableOptimizer | undefined, mode?: 'production' | 'development', resolveNamespace?: typeof processNamespace | undefined, timedCacheOptions?: Omit<TimedCacheOptions, 'createKey'>, resolveModule?: ModuleResolver | undefined, cssParser?: CssParser, resolverCache?: StylableResolverCache | undefined); | ||
initCache(): void; | ||
createResolver({ requireModule, resolverCache, }: Pick<StylableConfig, 'requireModule' | 'resolverCache'>): StylableResolver; | ||
createProcessor({ resolveNamespace }?: CreateProcessorOptions): StylableProcessor; | ||
createTransformer(options?: Partial<TransformerOptions>): StylableTransformer; | ||
@@ -53,0 +60,0 @@ transform(meta: StylableMeta): StylableResults; |
@@ -14,3 +14,3 @@ "use strict"; | ||
useTimer: true, | ||
}, resolveModule, cssParser = parser_1.safeParse) { | ||
}, resolveModule, cssParser = parser_1.safeParse, resolverCache) { | ||
this.projectRoot = projectRoot; | ||
@@ -30,2 +30,3 @@ this.fileSystem = fileSystem; | ||
this.cssParser = cssParser; | ||
this.resolverCache = resolverCache; | ||
const { fileProcessor, resolvePath } = create_infra_structure_1.createInfrastructure(projectRoot, fileSystem, onProcess, resolveOptions, this.resolveNamespace, timedCacheOptions, resolveModule, cssParser); | ||
@@ -42,4 +43,13 @@ this.resolvePath = resolvePath; | ||
throw new Error('Javascript files are not supported without requireModule options'); | ||
}, config.delimiter, config.onProcess, config.diagnostics, config.hooks, config.resolveOptions, config.optimizer, config.mode, config.resolveNamespace, config.timedCacheOptions, config.resolveModule, config.cssParser); | ||
}, config.delimiter, config.onProcess, config.diagnostics, config.hooks, config.resolveOptions, config.optimizer, config.mode, config.resolveNamespace, config.timedCacheOptions, config.resolveModule, config.cssParser, config.resolverCache); | ||
} | ||
initCache() { | ||
this.resolverCache = new Map(); | ||
} | ||
createResolver({ requireModule, resolverCache, }) { | ||
return new stylable_resolver_1.StylableResolver(this.fileProcessor, requireModule || this.requireModule, resolverCache || this.resolverCache); | ||
} | ||
createProcessor({ resolveNamespace } = {}) { | ||
return new stylable_processor_1.StylableProcessor(new diagnostics_1.Diagnostics(), resolveNamespace || this.resolveNamespace); | ||
} | ||
createTransformer(options = {}) { | ||
@@ -53,2 +63,3 @@ return new stylable_transformer_1.StylableTransformer({ | ||
replaceValueHook: this.hooks.replaceValueHook, | ||
resolverCache: this.resolverCache, | ||
mode: this.mode, | ||
@@ -58,8 +69,5 @@ ...options, | ||
} | ||
transform(meta, resourcePath, options = {}) { | ||
transform(meta, resourcePath, options = {}, processorOptions = {}) { | ||
if (typeof meta === 'string') { | ||
// TODO: refactor to use fileProcessor | ||
// meta = this.fileProcessor.processContent(meta, resourcePath + ''); | ||
const root = this.cssParser(meta, { from: resourcePath }); | ||
meta = new stylable_processor_1.StylableProcessor(undefined, this.resolveNamespace).process(root); | ||
meta = this.createProcessor(processorOptions).process(this.cssParser(meta, { from: resourcePath })); | ||
} | ||
@@ -66,0 +74,0 @@ const transformer = this.createTransformer(options); |
{ | ||
"name": "@stylable/core", | ||
"version": "3.11.14", | ||
"version": "3.12.0", | ||
"description": "CSS for Components", | ||
@@ -23,3 +23,3 @@ "main": "./cjs/index.js", | ||
"murmurhash": "^1.0.0", | ||
"postcss": "^8.2.4", | ||
"postcss": "^8.2.6", | ||
"postcss-js": "^3.0.3", | ||
@@ -29,3 +29,4 @@ "postcss-nested": "^5.0.3", | ||
"postcss-selector-matches": "^4.0.0", | ||
"postcss-value-parser": "^4.1.0" | ||
"postcss-value-parser": "^4.1.0", | ||
"toky": "^0.1.0" | ||
}, | ||
@@ -32,0 +33,0 @@ "files": [ |
@@ -23,4 +23,5 @@ export { safeParse } from './parser'; | ||
export * from './module-resolver'; | ||
export * from './timed-cache'; | ||
import * as pseudoStates from './pseudo-states'; | ||
export { pseudoStates }; |
@@ -162,3 +162,3 @@ // MDN reference: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes | ||
steps: true, | ||
styleset: true, | ||
styleset: true, | ||
stylistic: true, | ||
@@ -165,0 +165,0 @@ swash: true, |
@@ -70,3 +70,3 @@ import * as postcss from 'postcss'; | ||
keyframes: Record<string, string>; | ||
rule: postcss.Rule; | ||
rule: postcss.Rule | postcss.AtRule; | ||
fromRelative: string; | ||
@@ -73,0 +73,0 @@ context: string; |
@@ -5,2 +5,3 @@ import hash from 'murmurhash'; | ||
import postcssValueParser from 'postcss-value-parser'; | ||
import { tokenizeImports } from 'toky'; | ||
import { Diagnostics } from './diagnostics'; | ||
@@ -120,2 +121,14 @@ import { | ||
}, | ||
NO_ST_IMPORT_IN_NESTED_SCOPE() { | ||
return `cannot use "@st-import" inside of nested scope`; | ||
}, | ||
ST_IMPORT_STAR() { | ||
return '@st-import * is not supported'; | ||
}, | ||
ST_IMPORT_EMPTY_FROM() { | ||
return '@st-import must specify a valid "from" string value'; | ||
}, | ||
INVALID_ST_IMPORT_FORMAT(errors: string[]) { | ||
return `Invalid @st-import format:\n - ${errors.join('\n - ')}`; | ||
}, | ||
NO_KEYFRAMES_IN_ST_SCOPE() { | ||
@@ -143,2 +156,3 @@ return `cannot use "@keyframes" inside of "@st-scope"`; | ||
protected meta!: StylableMeta; | ||
protected dirContext!: string; | ||
constructor( | ||
@@ -151,2 +165,4 @@ protected diagnostics = new Diagnostics(), | ||
this.dirContext = path.dirname(this.meta.source); | ||
this.handleAtRules(root); | ||
@@ -183,22 +199,6 @@ | ||
this.meta.scopes.forEach((atRule) => { | ||
const scopingRule = postcss.rule({ selector: atRule.params }) as SRule; | ||
this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, this.diagnostics); | ||
stubs.forEach((s) => s && s.remove()); | ||
if (scopingRule.selector) { | ||
atRule.walkRules((rule) => { | ||
const scopedRule = rule.clone({ | ||
selector: scopeSelector(scopingRule.selector, rule.selector, false) | ||
.selector, | ||
}); | ||
(scopedRule as SRule).stScopeSelector = atRule.params; | ||
rule.replaceWith(scopedRule); | ||
}); | ||
} | ||
this.meta.scopes.forEach((scope) => this.handleScope(scope)); | ||
atRule.replaceWith(atRule.nodes || []); | ||
}); | ||
stubs.forEach((s) => s && s.remove()); | ||
return this.meta; | ||
@@ -271,2 +271,16 @@ } | ||
break; | ||
case 'st-import': | ||
if (atRule.parent?.type !== 'root') { | ||
this.diagnostics.warn( | ||
atRule, | ||
processorWarnings.NO_ST_IMPORT_IN_NESTED_SCOPE() | ||
); | ||
atRule.remove(); | ||
} else { | ||
const _import = this.handleStImport(atRule); | ||
this.meta.imports.push(_import); | ||
this.addImportSymbols(_import); | ||
} | ||
break; | ||
case 'st-global-custom-property': { | ||
@@ -343,6 +357,9 @@ const cssVarsByComma = atRule.params.split(','); | ||
const checker = createSimpleSelectorChecker(); | ||
const validRoot = isRootValid(rule.selectorAst, 'root'); | ||
let locallyScoped = false; | ||
traverseNode(rule.selectorAst, (node, _index, _nodes) => { | ||
traverseNode(rule.selectorAst, (node, index, nodes) => { | ||
if (node.type === 'selector') { | ||
locallyScoped = false; | ||
} | ||
if (!checker(node)) { | ||
@@ -361,5 +378,5 @@ rule.isSimpleSelector = false; | ||
const _import = this.handleImport(rule); | ||
this.meta.imports.push(_import); | ||
this.addImportSymbols(_import); | ||
const imported = this.handleImport(rule); | ||
this.meta.imports.push(imported); | ||
this.addImportSymbols(imported); | ||
return false; | ||
@@ -403,5 +420,9 @@ } else { | ||
} else if (locallyScoped === false && !inStScope) { | ||
this.diagnostics.warn(rule, processorWarnings.UNSCOPED_CLASS(name), { | ||
word: name, | ||
}); | ||
if (this.checkForScopedNodeAfter(rule, nodes, index) === false) { | ||
this.diagnostics.warn(rule, processorWarnings.UNSCOPED_CLASS(name), { | ||
word: name, | ||
}); | ||
} else { | ||
locallyScoped = true; | ||
} | ||
} | ||
@@ -413,5 +434,9 @@ } | ||
if (locallyScoped === false && !inStScope) { | ||
this.diagnostics.warn(rule, processorWarnings.UNSCOPED_ELEMENT(name), { | ||
word: name, | ||
}); | ||
if (this.checkForScopedNodeAfter(rule, nodes, index) === false) { | ||
this.diagnostics.warn(rule, processorWarnings.UNSCOPED_ELEMENT(name), { | ||
word: name, | ||
}); | ||
} else { | ||
locallyScoped = true; | ||
} | ||
} | ||
@@ -431,3 +456,3 @@ } else if (type === 'nested-pseudo-class' && name === 'global') { | ||
if (!validRoot) { | ||
if (!isRootValid(rule.selectorAst, 'root')) { | ||
this.diagnostics.warn(rule, processorWarnings.ROOT_AFTER_SPACING()); | ||
@@ -456,2 +481,24 @@ } | ||
protected checkForScopedNodeAfter(rule: postcss.Rule, nodes: SelectorAstNode[], index: number) { | ||
for (let i = index + 1; i < nodes.length; i++) { | ||
const element = nodes[i]; | ||
if (!element) { | ||
break; | ||
} | ||
if (element.type === 'spacing' || element.type === 'operator') { | ||
break; | ||
} | ||
if (element.type === 'class') { | ||
this.addClassSymbolOnce(element.name, rule); | ||
if (this.meta.classes[element.name]) { | ||
if (!this.meta.classes[element.name].alias) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
protected addElementSymbolOnce(name: string, rule: postcss.Rule) { | ||
@@ -513,3 +560,3 @@ if (isCompRoot(name) && !this.meta.elements[name]) { | ||
import: importDef, | ||
context: path.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -524,3 +571,3 @@ } | ||
import: importDef, | ||
context: path.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -753,3 +800,47 @@ }); | ||
} | ||
protected handleStImport(atRule: postcss.AtRule) { | ||
const importObj: Imported = { | ||
defaultExport: '', | ||
from: '', | ||
fromRelative: '', | ||
named: {}, | ||
rule: atRule, | ||
context: this.dirContext, | ||
keyframes: {}, | ||
}; | ||
const imports = tokenizeImports(`import ${atRule.params}`, '[', ']', true)[0]; | ||
if (imports && imports.star) { | ||
this.diagnostics.error(atRule, processorWarnings.ST_IMPORT_STAR()); | ||
} else { | ||
importObj.defaultExport = imports.defaultName || ''; | ||
setImportObjectFrom(imports.from || '', this.dirContext, importObj); | ||
if (imports.tagged?.keyframes) { | ||
// importObj.keyframes = imports.tagged?.keyframes; | ||
for (const [impName, impAsName] of Object.entries(imports.tagged.keyframes)) { | ||
importObj.keyframes[impAsName] = impName; | ||
} | ||
} | ||
if (imports.named) { | ||
for (const [impName, impAsName] of Object.entries(imports.named)) { | ||
importObj.named[impAsName] = impName; | ||
} | ||
} | ||
if (imports.errors.length) { | ||
this.diagnostics.error( | ||
atRule, | ||
processorWarnings.INVALID_ST_IMPORT_FORMAT(imports.errors) | ||
); | ||
} else if (!imports.from?.trim()) { | ||
this.diagnostics.error(atRule, processorWarnings.ST_IMPORT_EMPTY_FROM()); | ||
} | ||
} | ||
atRule.remove(); | ||
return importObj; | ||
} | ||
protected handleImport(rule: postcss.Rule) { | ||
@@ -764,3 +855,3 @@ let fromExists = false; | ||
rule, | ||
context: path.dirname(this.meta.source), | ||
context: this.dirContext, | ||
}; | ||
@@ -780,14 +871,3 @@ | ||
if (!path.isAbsolute(importPath) && !importPath.startsWith('.')) { | ||
// 3rd party request | ||
importObj.fromRelative = importPath; | ||
importObj.from = importPath; | ||
} else { | ||
importObj.fromRelative = importPath; | ||
const dirPath = path.dirname(this.meta.source); | ||
importObj.from = | ||
path.posix && path.posix.isAbsolute(dirPath) // browser has no posix methods | ||
? path.posix.resolve(dirPath, importPath) | ||
: path.resolve(dirPath, importPath); | ||
} | ||
setImportObjectFrom(importPath, this.dirContext, importObj); | ||
fromExists = true; | ||
@@ -836,4 +916,34 @@ break; | ||
} | ||
private handleScope(atRule: postcss.AtRule) { | ||
const scopingRule = postcss.rule({ selector: atRule.params }) as SRule; | ||
this.handleRule(scopingRule, true); | ||
validateScopingSelector(atRule, scopingRule, this.diagnostics); | ||
if (scopingRule.selector) { | ||
atRule.walkRules((rule) => { | ||
const scopedRule = rule.clone({ | ||
selector: scopeSelector(scopingRule.selector, rule.selector, false).selector, | ||
}); | ||
(scopedRule as SRule).stScopeSelector = atRule.params; | ||
rule.replaceWith(scopedRule); | ||
}); | ||
} | ||
atRule.replaceWith(atRule.nodes || []); | ||
} | ||
} | ||
function setImportObjectFrom(importPath: string, dirPath: string, importObj: Imported) { | ||
if (!path.isAbsolute(importPath) && !importPath.startsWith('.')) { | ||
importObj.fromRelative = importPath; | ||
importObj.from = importPath; | ||
} else { | ||
importObj.fromRelative = importPath; | ||
importObj.from = | ||
path.posix && path.posix.isAbsolute(dirPath) // browser has no posix methods | ||
? path.posix.resolve(dirPath, importPath) | ||
: path.resolve(dirPath, importPath); | ||
} | ||
} | ||
export function validateScopingSelector( | ||
@@ -840,0 +950,0 @@ atRule: postcss.AtRule, |
@@ -17,2 +17,9 @@ import { FileProcessor } from './cached-process-file'; | ||
export type JsModule = { | ||
default?: unknown; | ||
[key: string]: unknown; | ||
}; | ||
export type CachedModule = StylableMeta | JsModule | null; | ||
export type StylableResolverCache = Map<string, StylableMeta | JsModule | null>; | ||
export interface CSSResolve<T extends StylableSymbol = StylableSymbol> { | ||
@@ -39,33 +46,59 @@ _kind: 'css'; | ||
// this is a safe cache key delimiter for all OS; | ||
const safePathDelimiter = ';:'; | ||
export class StylableResolver { | ||
constructor( | ||
protected fileProcessor: FileProcessor<StylableMeta>, | ||
protected requireModule: (modulePath: string) => any | ||
protected requireModule: (modulePath: string) => any, | ||
protected cache?: StylableResolverCache | ||
) {} | ||
public resolveImported(imported: Imported, name: string) { | ||
const { context, from } = imported; | ||
let symbol: StylableSymbol; | ||
private getModule({ context, from }: Imported): CachedModule { | ||
const key = `${context}${safePathDelimiter}${from}`; | ||
if (this.cache?.has(key)) { | ||
return this.cache.get(key)!; | ||
} | ||
let res; | ||
if (from.match(/\.css$/)) { | ||
let meta; | ||
try { | ||
meta = this.fileProcessor.process(from, false, context); | ||
symbol = !name | ||
? meta.mappedSymbols[meta.root] | ||
: meta.mappedSymbols[name] || meta.mappedKeyframes[name]; | ||
res = this.fileProcessor.process(from, false, context); | ||
} catch (e) { | ||
return null; | ||
res = null; | ||
} | ||
return { _kind: 'css', symbol, meta } as CSSResolve; | ||
} else { | ||
let _module; | ||
try { | ||
_module = this.requireModule(this.fileProcessor.resolvePath(from, context)); | ||
res = this.requireModule(this.fileProcessor.resolvePath(from, context)); | ||
} catch { | ||
return null; | ||
res = null; | ||
} | ||
symbol = !name ? _module.default || _module : _module[name]; | ||
} | ||
this.cache?.set(key, res); | ||
return res; | ||
} | ||
return { _kind: 'js', symbol, meta: null } as JSResolve; | ||
public resolveImported( | ||
imported: Imported, | ||
name: string, | ||
subtype: 'mappedSymbols' | 'mappedKeyframes' = 'mappedSymbols' | ||
): CSSResolve | JSResolve | null { | ||
const res = this.getModule(imported); | ||
if (res === null) { | ||
return null; | ||
} | ||
if (imported.from.match(/\.css$/)) { | ||
const meta = res as StylableMeta; | ||
return { | ||
_kind: 'css', | ||
symbol: !name ? meta.mappedSymbols[meta.root] : meta[subtype][name], | ||
meta, | ||
}; | ||
} else { | ||
const jsModule = res as JsModule; | ||
return { | ||
_kind: 'js', | ||
symbol: !name ? jsModule.default || jsModule : jsModule[name], | ||
meta: null, | ||
}; | ||
} | ||
} | ||
@@ -108,3 +141,7 @@ public resolveImport(importSymbol: ImportSymbol) { | ||
while (current.symbol?.import) { | ||
const res = this.resolveImported(current.symbol.import, current.symbol.name); | ||
const res = this.resolveImported( | ||
current.symbol.import, | ||
current.symbol.name, | ||
'mappedKeyframes' | ||
); | ||
if (res?._kind === 'css' && res.symbol?._kind === 'keyframes') { | ||
@@ -111,0 +148,0 @@ const { meta, symbol } = res; |
@@ -43,3 +43,3 @@ import { basename } from 'path'; | ||
} from './stylable-processor'; | ||
import { CSSResolve, JSResolve, StylableResolver } from './stylable-resolver'; | ||
import { CSSResolve, JSResolve, StylableResolverCache, StylableResolver } from './stylable-resolver'; | ||
import { findRule, generateScopedCSSVar, getDeclStylable, isCSSVarProp } from './stylable-utils'; | ||
@@ -110,2 +110,3 @@ import { valueMapping } from './stylable-value-parsers'; | ||
mode?: EnvMode; | ||
resolverCache?: StylableResolverCache; | ||
} | ||
@@ -158,3 +159,7 @@ | ||
this.postProcessor = options.postProcessor; | ||
this.resolver = new StylableResolver(options.fileProcessor, options.requireModule); | ||
this.resolver = new StylableResolver( | ||
options.fileProcessor, | ||
options.requireModule, | ||
options.resolverCache | ||
); | ||
this.mode = options.mode || 'production'; | ||
@@ -161,0 +166,0 @@ } |
@@ -73,3 +73,2 @@ import * as postcss from 'postcss'; | ||
export const mixinDeclRegExp = new RegExp(`(${valueMapping.mixin})|(${valueMapping.partialMixin})`); | ||
@@ -134,3 +133,7 @@ | ||
}, | ||
'-st-named'(value: string, node: postcss.Declaration, diagnostics: Diagnostics) { | ||
'-st-named'( | ||
value: string, | ||
node: postcss.Declaration | postcss.AtRule, | ||
diagnostics: Diagnostics | ||
) { | ||
const namedMap: Record<string, string> = {}; | ||
@@ -200,3 +203,3 @@ const keyframesMap: Record<string, string> = {}; | ||
key: keyof typeof buckets = 'namedMap', | ||
node: postcss.Declaration, | ||
node: postcss.Declaration | postcss.AtRule, | ||
diagnostics: Diagnostics | ||
@@ -203,0 +206,0 @@ ) { |
@@ -6,3 +6,3 @@ import { FileProcessor, MinimalFS } from './cached-process-file'; | ||
import { processNamespace, StylableMeta, StylableProcessor } from './stylable-processor'; | ||
import { StylableResolver } from './stylable-resolver'; | ||
import { StylableResolverCache, StylableResolver } from './stylable-resolver'; | ||
import { | ||
@@ -33,7 +33,11 @@ StylableResults, | ||
resolveNamespace?: typeof processNamespace; | ||
/** @deprecated use resolverCache instead */ | ||
timedCacheOptions?: Omit<TimedCacheOptions, 'createKey'>; | ||
resolveModule?: ModuleResolver; | ||
cssParser?: CssParser; | ||
resolverCache?: StylableResolverCache; | ||
} | ||
export type CreateProcessorOptions = Pick<StylableConfig, 'resolveNamespace'>; | ||
export class Stylable { | ||
@@ -60,3 +64,4 @@ public static create(config: StylableConfig) { | ||
config.resolveModule, | ||
config.cssParser | ||
config.cssParser, | ||
config.resolverCache | ||
); | ||
@@ -84,3 +89,4 @@ } | ||
protected resolveModule?: ModuleResolver, | ||
protected cssParser: CssParser = safeParse | ||
protected cssParser: CssParser = safeParse, | ||
protected resolverCache?: StylableResolverCache | ||
) { | ||
@@ -101,2 +107,18 @@ const { fileProcessor, resolvePath } = createInfrastructure( | ||
} | ||
public initCache() { | ||
this.resolverCache = new Map(); | ||
} | ||
public createResolver({ | ||
requireModule, | ||
resolverCache, | ||
}: Pick<StylableConfig, 'requireModule' | 'resolverCache'>) { | ||
return new StylableResolver( | ||
this.fileProcessor, | ||
requireModule || this.requireModule, | ||
resolverCache || this.resolverCache | ||
); | ||
} | ||
public createProcessor({ resolveNamespace }: CreateProcessorOptions = {}) { | ||
return new StylableProcessor(new Diagnostics(), resolveNamespace || this.resolveNamespace); | ||
} | ||
public createTransformer(options: Partial<TransformerOptions> = {}) { | ||
@@ -110,2 +132,3 @@ return new StylableTransformer({ | ||
replaceValueHook: this.hooks.replaceValueHook, | ||
resolverCache: this.resolverCache, | ||
mode: this.mode, | ||
@@ -120,14 +143,12 @@ ...options, | ||
resourcePath?: string, | ||
options: Partial<TransformerOptions> = {} | ||
options: Partial<TransformerOptions> = {}, | ||
processorOptions: CreateProcessorOptions = {} | ||
): StylableResults { | ||
if (typeof meta === 'string') { | ||
// TODO: refactor to use fileProcessor | ||
// meta = this.fileProcessor.processContent(meta, resourcePath + ''); | ||
const root = this.cssParser(meta, { from: resourcePath }); | ||
meta = new StylableProcessor(undefined, this.resolveNamespace).process(root); | ||
meta = this.createProcessor(processorOptions).process( | ||
this.cssParser(meta, { from: resourcePath }) | ||
); | ||
} | ||
const transformer = this.createTransformer(options); | ||
this.fileProcessor.add(meta.source, meta); | ||
return transformer.transform(meta); | ||
@@ -134,0 +155,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
731705
12606
16
+ Addedtoky@^0.1.0
+ Addedtoky@0.1.0(transitive)
Updatedpostcss@^8.2.6