diff --git a/packages/core/src/features/st-mixin.ts b/packages/core/src/features/st-mixin.ts index 00dbc8208..e7d1ac357 100644 --- a/packages/core/src/features/st-mixin.ts +++ b/packages/core/src/features/st-mixin.ts @@ -183,7 +183,7 @@ export class StylablePublicApi { name, kind: 'js-func', args: [], - func: resolvedSymbols.js[name].symbol, + func: resolvedSymbols.js[name].symbol as (...args: any[]) => any, }; for (const arg of Object.values(data.options)) { mixRef.args.push(arg.value); @@ -374,10 +374,10 @@ function appendMixin(context: FeatureTransformContext, config: ApplyMixinContext handleCSSMixin(context, config, resolveChain); return; } else if (resolvedType === `js`) { - const resolvedMixin = resolvedSymbols.js[symbolName]; - if (typeof resolvedMixin.symbol === 'function') { + const jsValue = resolvedSymbols.js[symbolName].symbol; + if (typeof jsValue === 'function') { try { - handleJSMixin(context, config, resolvedMixin.symbol); + handleJSMixin(context, config, jsValue as (...args: any[]) => any); } catch (e) { context.diagnostics.report(diagnostics.FAILED_TO_APPLY_MIXIN(String(e)), { node: config.rule, diff --git a/packages/core/src/features/st-var.ts b/packages/core/src/features/st-var.ts index dc75f5d7f..ae870ff84 100644 --- a/packages/core/src/features/st-var.ts +++ b/packages/core/src/features/st-var.ts @@ -400,21 +400,16 @@ function evaluateValueCall( const type = resolvedSymbols.mainNamespace[varName]; if (type === `js`) { const deepResolve = resolvedSymbols.js[varName]; - const importedType = typeof deepResolve.symbol; - if (importedType === 'string') { + const jsValue = deepResolve.symbol; + if (typeof jsValue === 'string') { parsedNode.resolvedValue = context.evaluator.valueHook - ? context.evaluator.valueHook( - deepResolve.symbol, - varName, - false, - passedThrough - ) - : deepResolve.symbol; + ? context.evaluator.valueHook(jsValue, varName, false, passedThrough) + : jsValue; } else if (node) { // unsupported Javascript value // ToDo: provide actual exported id (default/named as x) context.diagnostics.report( - diagnostics.CANNOT_USE_JS_AS_VALUE(importedType, varName), + diagnostics.CANNOT_USE_JS_AS_VALUE(typeof jsValue, varName), { node, word: varName, @@ -480,7 +475,7 @@ export function resolveReferencedVarNames( break; case 'import': { const resolved = context.resolver.deepResolve(symbol); - if (resolved?._kind === 'css' && resolved.symbol._kind === 'var') { + if (resolved?._kind === 'css' && resolved.symbol?._kind === 'var') { varsToCheck.push({ meta: resolved.meta, name: resolved.symbol.name }); } break; diff --git a/packages/core/src/functions.ts b/packages/core/src/functions.ts index 9bf44bc38..13a4ccda2 100644 --- a/packages/core/src/functions.ts +++ b/packages/core/src/functions.ts @@ -186,7 +186,10 @@ export function processDeclarationValue( const formatter = resolvedSymbols.js[value]; const formatterArgs = getFormatterArgs(parsedNode); try { - parsedNode.resolvedValue = formatter.symbol.apply(null, formatterArgs); + // ToDo: check if function instead of calling on a non function + parsedNode.resolvedValue = (formatter.symbol as (...args: any[]) => any)( + ...formatterArgs + ); if (evaluator.valueHook && typeof parsedNode.resolvedValue === 'string') { parsedNode.resolvedValue = evaluator.valueHook( parsedNode.resolvedValue, diff --git a/packages/core/src/index-internal.ts b/packages/core/src/index-internal.ts index b8361725e..c76956052 100644 --- a/packages/core/src/index-internal.ts +++ b/packages/core/src/index-internal.ts @@ -47,7 +47,12 @@ export { EmitDiagnosticsContext, reportDiagnostic, } from './report-diagnostic'; -export { StylableResolver, StylableResolverCache } from './stylable-resolver'; +export { + StylableResolver, + StylableResolverCache, + isValidCSSResolve, + CSSResolveMaybe, +} from './stylable-resolver'; export { CacheItem, FileProcessor, cachedProcessFile, processFn } from './cached-process-file'; export { createStylableFileProcessor } from './create-stylable-processor'; export { packageNamespaceFactory } from './resolve-namespace-factories'; diff --git a/packages/core/src/stylable-resolver.ts b/packages/core/src/stylable-resolver.ts index c84da2c9e..40605c813 100644 --- a/packages/core/src/stylable-resolver.ts +++ b/packages/core/src/stylable-resolver.ts @@ -63,16 +63,26 @@ export type CachedModuleEntity = export type StylableResolverCache = Map; +export interface CSSResolveMaybe< + T extends StylableSymbol | STStructure.PartSymbol = StylableSymbol +> { + _kind: 'css'; + symbol: T | undefined; + meta: StylableMeta; +} export interface CSSResolve { _kind: 'css'; symbol: T; meta: StylableMeta; } +export function isValidCSSResolve(resolved: CSSResolveMaybe): resolved is CSSResolve { + return resolved.symbol !== undefined; +} export type CSSResolvePath = Array>; export interface JSResolve { _kind: 'js'; - symbol: any; + symbol: unknown; meta: null; } @@ -91,7 +101,7 @@ export interface MetaResolvedSymbols { } export type ReportError = ( - res: CSSResolve | JSResolve | null, + res: CSSResolveMaybe | JSResolve | null, extend: ImportSymbol | ClassSymbol | ElementSymbol, extendPath: Array>, meta: StylableMeta, @@ -192,7 +202,7 @@ export class StylableResolver { imported: Imported, name: string, subtype: 'mappedSymbols' | 'mappedKeyframes' | STSymbol.Namespaces = 'mappedSymbols' - ): CSSResolve | JSResolve | null { + ): CSSResolveMaybe | JSResolve | null { const res = this.getModule(imported); if (res.value === null) { return null; @@ -226,7 +236,7 @@ export class StylableResolver { const name = importSymbol.type === 'named' ? importSymbol.name : ''; return this.resolveImported(importSymbol.import, name); } - public resolve(maybeImport: StylableSymbol | undefined): CSSResolve | JSResolve | null { + public resolve(maybeImport: StylableSymbol | undefined): CSSResolveMaybe | JSResolve | null { if (!maybeImport || maybeImport._kind !== 'import') { if ( maybeImport && @@ -261,7 +271,7 @@ export class StylableResolver { public deepResolve( maybeImport: StylableSymbol | undefined, path: StylableSymbol[] = [] - ): CSSResolve | JSResolve | null { + ): CSSResolveMaybe | JSResolve | null { let resolved = this.resolve(maybeImport); while ( resolved && @@ -334,7 +344,7 @@ export class StylableResolver { }; // resolve main namespace for (const [name, symbol] of Object.entries(meta.getAllSymbols())) { - let deepResolved: CSSResolve | JSResolve | null; + let deepResolved: CSSResolveMaybe | JSResolve | null; if (symbol._kind === `import` || (symbol._kind === `cssVar` && symbol.alias)) { deepResolved = this.deepResolve(symbol); if (!deepResolved || !deepResolved.symbol) { @@ -366,13 +376,19 @@ export class StylableResolver { } else { deepResolved = { _kind: `css`, meta, symbol }; } - switch (deepResolved.symbol._kind) { + // deepResolved symbol is resolved by this point + switch (deepResolved.symbol!._kind) { case `class`: resolvedSymbols.class[name] = this.resolveExtends( meta, - deepResolved.symbol, + deepResolved.symbol!, false, - validateClassResolveExtends(meta, name, diagnostics, deepResolved) + validateClassResolveExtends( + meta, + name, + diagnostics, + deepResolved as CSSResolve + ) ); break; case `element`: @@ -385,7 +401,7 @@ export class StylableResolver { resolvedSymbols.cssVar[name] = deepResolved as CSSResolve; break; } - resolvedSymbols.mainNamespace[name] = deepResolved.symbol._kind; + resolvedSymbols.mainNamespace[name] = deepResolved.symbol!._kind; } // resolve keyframes for (const [name, symbol] of Object.entries(CSSKeyframes.getAll(meta))) { @@ -497,7 +513,7 @@ function validateClassResolveExtends( meta: StylableMeta, name: string, diagnostics: Diagnostics, - deepResolved: CSSResolve | JSResolve | null + deepResolved: CSSResolve ): ReportError | undefined { return (res, extend) => { const decl = findRule(meta.sourceAst, '.' + name); @@ -520,7 +536,7 @@ function validateClassResolveExtends( }); } } else { - if (deepResolved?.symbol.alias) { + if (deepResolved.symbol.alias) { meta.sourceAst.walkRules(new RegExp('\\.' + name), (rule) => { diagnostics.report(CSSClass.diagnostics.UNKNOWN_IMPORT_ALIAS(name), { node: rule, diff --git a/packages/language-service/src/lib/completion-providers.ts b/packages/language-service/src/lib/completion-providers.ts index fc18c8c0c..94a7dbfee 100644 --- a/packages/language-service/src/lib/completion-providers.ts +++ b/packages/language-service/src/lib/completion-providers.ts @@ -565,6 +565,7 @@ export const ExtendCompletionPlugin: LangServicePlugin = { return ( res && res._kind === 'css' && + res.symbol && (res.symbol._kind === 'class' || res.symbol._kind === 'element') ); }) diff --git a/packages/language-service/src/lib/provider.ts b/packages/language-service/src/lib/provider.ts index f9ae236d8..96225a42e 100644 --- a/packages/language-service/src/lib/provider.ts +++ b/packages/language-service/src/lib/provider.ts @@ -10,7 +10,6 @@ import { ImportSymbol, Stylable, StylableMeta, - JSResolve, Diagnostics, } from '@stylable/core'; import { @@ -18,6 +17,8 @@ import { StylableProcessor, STCustomSelector, MappedStates, + type StylableResolver, + isValidCSSResolve, } from '@stylable/core/dist/index-internal'; import type { Location, @@ -202,7 +203,7 @@ export class Provider { break; } case 'import': { - let resolved: CSSResolve | JSResolve | null = null; + let resolved: ReturnType = null; try { resolved = this.stylable.resolver.resolve(symbol); } catch { @@ -321,29 +322,24 @@ export class Provider { state: string ): CSSResolve | null { const importedSymbol = origMeta.getClass(elementName)![`-st-extends`]; - let res: CSSResolve | JSResolve | null = null; + let res: ReturnType = null; if (importedSymbol && importedSymbol._kind === 'import') { res = this.stylable.resolver.resolveImport(importedSymbol); } const localSymbol = origMeta.getSymbol(elementName)!; - if ( - res && - res._kind === 'css' && - Object.keys((res.symbol as ClassSymbol)[`-st-states`]!).includes(state) - ) { - return res; - } else if ( - res && - res._kind === 'css' && - (localSymbol._kind === 'class' || localSymbol._kind === 'element') && - localSymbol[`-st-extends`] - ) { - return this.findMyState(res.meta, res.symbol.name, state); - } else { - return null; + if (res && res._kind === 'css' && isValidCSSResolve(res)) { + if (Object.keys((res.symbol as ClassSymbol)[`-st-states`]!).includes(state)) { + return res; + } else if ( + (localSymbol._kind === 'class' || localSymbol._kind === 'element') && + localSymbol[`-st-extends`] + ) { + return this.findMyState(res.meta, res.symbol.name, state); + } } + return null; } public getSignatureHelp( diff --git a/packages/webpack-extensions/src/types.ts b/packages/webpack-extensions/src/types.ts index 2742092e5..b9167ca7d 100644 --- a/packages/webpack-extensions/src/types.ts +++ b/packages/webpack-extensions/src/types.ts @@ -1,4 +1,5 @@ -import type { CSSResolve, Imported, JSResolve, StylableMeta } from '@stylable/core'; +import type { Imported, JSResolve, StylableMeta } from '@stylable/core'; +import type { CSSResolveMaybe } from '@stylable/core/dist/index-internal'; export interface Metadata { entry: string; @@ -24,5 +25,5 @@ export type MetadataList = Array<{ export type ResolvedImport = { stImport: Imported; - resolved: CSSResolve | JSResolve | null; + resolved: CSSResolveMaybe | JSResolve | null; };