diff --git a/src/codegen.ts b/src/codegen.ts index b71322f..5c5cccf 100644 --- a/src/codegen.ts +++ b/src/codegen.ts @@ -4,12 +4,15 @@ import type { Artifact, } from '@pandacss/types'; import { makePaths } from './utils'; -import type { ComponentTokens } from './types'; +import type { PluginContext } from './types'; export const codegen = ( args: CodegenPrepareHookArgs, - tokens: ComponentTokens, + context: Partial, ): MaybeAsyncReturn => { + const tokens = context.tokens ?? {}; + if (!tokens) return; + const cssFn = args.artifacts.find((a) => a.id === 'css-fn'); if (!cssFn) return args.artifacts; @@ -31,7 +34,7 @@ export const codegen = ( } if (typeof current !== "string") { - return "alias-not-found"; + return "panda-plugin-ct-alias-not-found"; } return current; diff --git a/src/create-project.ts b/src/create-project.ts new file mode 100644 index 0000000..befb61f --- /dev/null +++ b/src/create-project.ts @@ -0,0 +1,20 @@ +import { Project, ts } from 'ts-morph'; + +export const createProject = () => { + return new Project({ + compilerOptions: { + jsx: ts.JsxEmit.React, + jsxFactory: 'React.createElement', + jsxFragmentFactory: 'React.Fragment', + module: ts.ModuleKind.ESNext, + target: ts.ScriptTarget.ESNext, + noUnusedParameters: false, + noEmit: true, + useVirtualFileSystem: true, + allowJs: true, + }, + skipAddingFilesFromTsConfig: true, + skipFileDependencyResolution: true, + skipLoadingLibFiles: true, + }); +}; diff --git a/src/index.ts b/src/index.ts index d7d52b1..838f449 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,20 +1,26 @@ import type { PandaPlugin } from '@pandacss/types'; import { parser } from './parser'; import { codegen } from './codegen'; -import type { ComponentTokens } from './types'; +import { createProject } from './create-project'; +import type { ComponentTokens, PluginContext } from './types'; /** * */ const pluginComponentTokens = (tokens: ComponentTokens): PandaPlugin => { + const context: Partial = {}; return { - name: 'component-tokens', + name: 'panda-plugin-ct', hooks: { + 'config:resolved': () => { + context.project = createProject(); + context.tokens = tokens; + }, 'parser:before': (args) => { - return parser(args, tokens); + return parser(args, context); }, 'codegen:prepare': (args) => { - return codegen(args, tokens); + return codegen(args, context); }, }, }; diff --git a/src/parser.ts b/src/parser.ts index 4f2f31c..7365537 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,29 +1,22 @@ import type { ParserResultBeforeHookArgs } from '@pandacss/types'; -import { Project } from 'ts-morph'; -import type { ComponentTokens } from './types'; +import type { ComponentTokens, PluginContext } from './types'; export const parser = ( args: ParserResultBeforeHookArgs, - tokens: ComponentTokens, + context: Partial, ): string | void => { - const { content } = args; - const project = new Project(); - const source = project.createSourceFile('__temp-ct-parser.ts', content, { - overwrite: true, - }); + const tokens = context.tokens ?? {}; + const project = context.project; - let hasCt = false; + if (!tokens || !project) return; - for (const node of source.getImportDeclarations()) { - for (const named of node.getNamedImports()) { - if (named.getName() === 'ct') { - hasCt = true; - } - } - if (hasCt) break; - } + // TODO: handle `import { ct as xyz }` aliasing + const content = args.content; + if (!content.includes('ct(')) return; - if (!hasCt) return; + const source = project.createSourceFile('__temp-ct-parser.ts', content, { + overwrite: true, + }); const text = source.getText(); const calls = text.match(/ct\(['"][\w.]+['"]\)/g) ?? []; @@ -38,8 +31,9 @@ export const parser = ( current = current[part] as ComponentTokens; } + // TODO: allow passing through style objects if (typeof current !== 'string') { - return 'alias-not-found'; + return 'panda-plugin-ct-alias-not-found'; } return current as unknown as string; diff --git a/src/types.ts b/src/types.ts index 26cc37b..f620cfa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1 +1,8 @@ +import { type Project } from 'ts-morph'; + export type ComponentTokens = { [k: string]: string | ComponentTokens }; + +export type PluginContext = { + project: Project; + tokens: ComponentTokens; +};