@pikacss/integration 0.0.33 → 0.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,13 +1,12 @@
1
1
  import { statSync } from "node:fs";
2
- import { mkdir, writeFile } from "node:fs/promises";
3
- import { createEngine, defineEnginePlugin, setWarnFn, warn } from "@pikacss/core";
4
- import { createJiti } from "jiti";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { createEngine, defineEnginePlugin, log } from "@pikacss/core";
4
+ import { computed, signal } from "alien-signals";
5
+ import { globbyStream } from "globby";
5
6
  import { klona } from "klona";
6
7
  import { isPackageExists } from "local-pkg";
7
8
  import MagicString from "magic-string";
8
- import micromatch from "micromatch";
9
9
  import { dirname, isAbsolute, join, relative, resolve } from "pathe";
10
- import { debounce } from "perfect-debounce";
11
10
 
12
11
  export * from "@pikacss/core"
13
12
 
@@ -15,6 +14,7 @@ export * from "@pikacss/core"
15
14
  function createEventHook() {
16
15
  const listeners = /* @__PURE__ */ new Set();
17
16
  function trigger(payload) {
17
+ if (listeners.size === 0) return;
18
18
  listeners.forEach((listener) => listener(payload));
19
19
  }
20
20
  function off(listener) {
@@ -103,9 +103,11 @@ function generateVueDeclaration(ctx) {
103
103
  ];
104
104
  }
105
105
  async function generateOverloadContent(ctx) {
106
+ log.debug("Generating TypeScript overload content");
106
107
  const paramsLines = [];
107
108
  const fnsLines = [];
108
109
  const usages = [...ctx.usages.values()].flat();
110
+ log.debug(`Processing ${usages.length} style usages for overload generation`);
109
111
  for (let i = 0; i < usages.length; i++) {
110
112
  const usage = usages[i];
111
113
  try {
@@ -139,6 +141,7 @@ async function generateOverloadContent(ctx) {
139
141
  ];
140
142
  }
141
143
  async function generateTsCodegenContent(ctx) {
144
+ log.debug("Generating TypeScript code generation content");
142
145
  const lines = [
143
146
  `// Auto-generated by ${ctx.currentPackageName}`,
144
147
  `import type { CSSProperty, CSSSelectors, DefineAutocomplete, Properties, StyleDefinition, StyleItem } from \'${ctx.currentPackageName}\'`,
@@ -160,257 +163,389 @@ async function generateTsCodegenContent(ctx) {
160
163
  lines.push(...generateGlobalDeclaration(ctx));
161
164
  lines.push(...generateVueDeclaration(ctx));
162
165
  lines.push(...await generateOverloadContent(ctx));
166
+ log.debug("TypeScript code generation content completed");
163
167
  return lines.join("\n");
164
168
  }
165
169
 
166
170
  //#endregion
167
171
  //#region src/ctx.ts
168
- function findFunctionCalls(code, RE) {
169
- const result = [];
170
- let matched = RE.exec(code);
171
- while (matched != null) {
172
- const fnName = matched[1];
173
- const start = matched.index;
174
- let end = start + fnName.length;
175
- let depth = 1;
176
- let inString = false;
177
- while (depth > 0) {
178
- end++;
179
- if (inString === false && code[end] === "(") depth++;
180
- else if (inString === false && code[end] === ")") depth--;
181
- else if (inString === false && (code[end] === "'" || code[end] === "\"")) inString = code[end];
182
- else if (inString === code[end]) inString = false;
183
- }
184
- const snippet = code.slice(start, end + 1);
185
- result.push({
186
- fnName,
187
- start,
188
- end,
189
- snippet
190
- });
191
- matched = RE.exec(code);
192
- }
193
- return result;
194
- }
195
- const ESCAPE_REPLACE_RE = /[.*+?^${}()|[\]\\/]/g;
196
- function createFnUtils(fnName) {
197
- const available = {
198
- normal: new Set([fnName]),
199
- forceString: new Set([
200
- `${fnName}.str`,
201
- `${fnName}['str']`,
202
- `${fnName}["str"]`,
203
- `${fnName}[\`str\`]`
204
- ]),
205
- forceArray: new Set([
206
- `${fnName}.arr`,
207
- `${fnName}['arr']`,
208
- `${fnName}["arr"]`,
209
- `${fnName}[\`arr\`]`
210
- ]),
211
- forceInline: new Set([
212
- `${fnName}.inl`,
213
- `${fnName}['inl']`,
214
- `${fnName}["inl"]`,
215
- `${fnName}[\`inl\`]`
216
- ]),
217
- normalPreview: new Set([`${fnName}p`]),
218
- forceStringPreview: new Set([
219
- `${fnName}p.str`,
220
- `${fnName}p['str']`,
221
- `${fnName}p["str"]`,
222
- `${fnName}p[\`str\`]`
223
- ]),
224
- forceArrayPreview: new Set([
225
- `${fnName}p.arr`,
226
- `${fnName}p['arr']`,
227
- `${fnName}p["arr"]`,
228
- `${fnName}p[\`arr\`]`
229
- ]),
230
- forceInlinePreview: new Set([
231
- `${fnName}p.inl`,
232
- `${fnName}p['inl']`,
233
- `${fnName}p["inl"]`,
234
- `${fnName}p[\`inl\`]`
235
- ])
236
- };
172
+ function usePaths({ cwd: _cwd, cssCodegen, tsCodegen }) {
173
+ const cwd = signal(_cwd);
237
174
  return {
238
- isNormal: (fnName$1) => available.normal.has(fnName$1) || available.normalPreview.has(fnName$1),
239
- isForceString: (fnName$1) => available.forceString.has(fnName$1) || available.forceStringPreview.has(fnName$1),
240
- isForceArray: (fnName$1) => available.forceArray.has(fnName$1) || available.forceArrayPreview.has(fnName$1),
241
- isForceInline: (fnName$1) => available.forceInline.has(fnName$1) || available.forceInlinePreview.has(fnName$1),
242
- isPreview: (fnName$1) => available.normalPreview.has(fnName$1) || available.forceStringPreview.has(fnName$1) || available.forceArrayPreview.has(fnName$1) || available.forceInlinePreview.has(fnName$1),
243
- RE: new RegExp(`\\b(${Object.values(available).flatMap((s) => [...s].map((f) => `(${f.replace(ESCAPE_REPLACE_RE, "\\$&")})`)).join("|")})\\(`, "g")
175
+ cwd,
176
+ cssCodegenFilepath: computed(() => isAbsolute(cssCodegen) ? resolve(cssCodegen) : join(cwd(), cssCodegen)),
177
+ tsCodegenFilepath: computed(() => tsCodegen === false ? null : isAbsolute(tsCodegen) ? resolve(tsCodegen) : join(cwd(), tsCodegen))
244
178
  };
245
179
  }
246
- async function createCtx(options) {
247
- const { cwd, currentPackageName, target, configOrPath, fnName, transformedFormat, tsCodegen, devCss, autoCreateConfig } = options;
248
- setWarnFn((...args) => {
249
- console.warn(`[${currentPackageName}]`, ...args);
180
+ function useConfig({ cwd, tsCodegenFilepath, currentPackageName, autoCreateConfig, configOrPath, scan }) {
181
+ const RE_VALID_CONFIG_EXT = /\.(?:js|cjs|mjs|ts|cts|mts)$/;
182
+ const specificConfigPath = computed(() => {
183
+ if (typeof configOrPath === "string" && RE_VALID_CONFIG_EXT.test(configOrPath)) return isAbsolute(configOrPath) ? configOrPath : join(cwd(), configOrPath);
184
+ return null;
250
185
  });
251
- const devCssFilepath = isAbsolute(devCss) ? resolve(devCss) : join(cwd, devCss);
252
- const tsCodegenFilepath = tsCodegen === false ? null : isAbsolute(tsCodegen) ? resolve(tsCodegen) : join(cwd, tsCodegen);
186
+ async function findFirstExistingConfigPath() {
187
+ const _cwd = cwd();
188
+ const _specificConfigPath = specificConfigPath();
189
+ if (_specificConfigPath != null && statSync(_specificConfigPath, { throwIfNoEntry: false })?.isFile()) return _specificConfigPath;
190
+ const stream = globbyStream("**/{pika,pikacss}.config.{js,cjs,mjs,ts,cts,mts}", { ignore: scan.exclude });
191
+ for await (const entry of stream) return join(_cwd, entry);
192
+ return null;
193
+ }
253
194
  const inlineConfig = typeof configOrPath === "object" ? configOrPath : null;
254
- const specificConfigPath = typeof configOrPath === "string" ? isAbsolute(configOrPath) ? configOrPath : join(cwd, configOrPath) : null;
255
- const configSources = [...specificConfigPath == null ? [] : [specificConfigPath], ...["pika", "pikacss"].flatMap((name) => [
256
- "js",
257
- "ts",
258
- "cjs",
259
- "cts",
260
- "mjs",
261
- "mts"
262
- ].map((ext) => `${name}.config.${ext}`)).map((name) => join(cwd, name))];
263
- const targetREs = target.map((t) => micromatch.makeRe(t));
264
- const needToTransform = (id) => targetREs.some((re) => re.test(id));
265
- const ctx = {
266
- cwd,
267
- currentPackageName,
268
- fnName,
269
- fnUtils: createFnUtils(fnName),
270
- transformedFormat,
271
- devCssFilepath,
272
- tsCodegenFilepath,
273
- hasVue: isPackageExists("vue", { paths: [cwd] }),
274
- usages: /* @__PURE__ */ new Map(),
275
- hooks: {
276
- styleUpdated: createEventHook(),
277
- tsCodegenUpdated: createEventHook()
278
- },
279
- loadConfig: async () => {
280
- if (inlineConfig != null) return {
281
- config: klona(inlineConfig),
282
- file: null
283
- };
284
- let resolvedConfigPath = configSources.find((path) => {
285
- const stat = statSync(path, { throwIfNoEntry: false });
286
- return stat != null && stat.isFile();
287
- });
288
- if (resolvedConfigPath == null) {
289
- if (autoCreateConfig === false) return {
290
- config: null,
291
- file: null
195
+ async function _loadConfig() {
196
+ try {
197
+ log.debug("Loading engine config");
198
+ if (inlineConfig != null) {
199
+ log.debug("Using inline config");
200
+ return {
201
+ config: klona(inlineConfig),
202
+ file: null,
203
+ content: null
292
204
  };
293
- resolvedConfigPath = configSources[0];
294
- await mkdir(dirname(resolvedConfigPath), { recursive: true }).catch(() => {});
295
- const relativeTsCodegenFilepath = tsCodegenFilepath == null ? null : `./${relative(dirname(resolvedConfigPath), tsCodegenFilepath)}`;
296
- await writeFile(resolvedConfigPath, [
205
+ }
206
+ let resolvedConfigPath$1 = await findFirstExistingConfigPath();
207
+ const _cwd = cwd();
208
+ if (resolvedConfigPath$1 == null) {
209
+ if (autoCreateConfig === false) {
210
+ log.warn("Config file not found and autoCreateConfig is false");
211
+ return {
212
+ config: null,
213
+ file: null,
214
+ content: null
215
+ };
216
+ }
217
+ resolvedConfigPath$1 = join(_cwd, specificConfigPath() ?? "pika.config.js");
218
+ await mkdir(dirname(resolvedConfigPath$1), { recursive: true }).catch(() => {});
219
+ const _tsCodegenFilepath = tsCodegenFilepath();
220
+ const relativeTsCodegenFilepath = _tsCodegenFilepath == null ? null : `./${relative(dirname(resolvedConfigPath$1), _tsCodegenFilepath)}`;
221
+ await writeFile(resolvedConfigPath$1, [
222
+ ...relativeTsCodegenFilepath == null ? [] : [`/// <reference path="${relativeTsCodegenFilepath}" />`],
297
223
  `import { defineEngineConfig } from '${currentPackageName}'`,
298
- ...relativeTsCodegenFilepath == null ? [] : [`/** @type {import('${relativeTsCodegenFilepath}')} */`],
299
224
  "",
300
225
  "export default defineEngineConfig({",
301
226
  " // Add your PikaCSS engine config here",
302
227
  "})"
303
228
  ].join("\n"));
304
229
  }
305
- const config = (await createJiti(cwd, {
306
- fsCache: false,
307
- moduleCache: false
308
- }).import(resolvedConfigPath)).default;
230
+ log.info(`Using config file: ${resolvedConfigPath$1}`);
231
+ const { createJiti } = await import("jiti");
232
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
233
+ const content = await readFile(resolvedConfigPath$1, "utf-8");
234
+ const config = (await jiti.evalModule(content, {
235
+ id: resolvedConfigPath$1,
236
+ forceTranspile: true
237
+ })).default;
309
238
  return {
310
239
  config: klona(config),
311
- file: resolvedConfigPath
240
+ file: resolvedConfigPath$1,
241
+ content
312
242
  };
313
- },
314
- init: debounce(async () => {
315
- ctx.isReady = false;
316
- ctx.usages.clear();
317
- const { config, file } = await ctx.loadConfig().catch((error) => {
318
- warn(`Failed to load config file: ${error.message}`, error);
319
- return {
320
- config: null,
321
- file: null
322
- };
323
- });
324
- ctx.resolvedConfigPath = file;
325
- const devPlugin = defineEnginePlugin({
326
- name: "@pikacss/integration:dev",
327
- preflightUpdated: () => ctx.hooks.styleUpdated.trigger(),
328
- atomicStyleAdded: () => ctx.hooks.styleUpdated.trigger(),
329
- autocompleteConfigUpdated: () => ctx.hooks.tsCodegenUpdated.trigger()
330
- });
331
- try {
332
- const _config = config ?? {};
333
- _config.plugins = _config.plugins ?? [];
334
- _config.plugins.unshift(devPlugin);
335
- ctx.engine = await createEngine(_config);
336
- } catch (error) {
337
- warn(`Failed to create engine: ${error.message}. Maybe the config file is invalid, falling back to default config.`, error);
338
- ctx.engine = await createEngine({ plugins: [devPlugin] });
339
- }
340
- await mkdir(dirname(devCssFilepath), { recursive: true }).catch(() => {});
341
- await writeFile(devCssFilepath, "");
342
- if (tsCodegenFilepath != null) {
343
- await mkdir(dirname(tsCodegenFilepath), { recursive: true }).catch(() => {});
344
- await writeFile(tsCodegenFilepath, await generateTsCodegenContent(ctx));
243
+ } catch (error) {
244
+ log.error(`Failed to load config file: ${error.message}`, error);
245
+ return {
246
+ config: null,
247
+ file: null,
248
+ content: null
249
+ };
250
+ }
251
+ }
252
+ const resolvedConfig = signal(inlineConfig);
253
+ const resolvedConfigPath = signal(null);
254
+ const resolvedConfigContent = signal(null);
255
+ async function loadConfig() {
256
+ const result = await _loadConfig();
257
+ resolvedConfig(result.config);
258
+ resolvedConfigPath(result.file);
259
+ resolvedConfigContent(result.content);
260
+ return result;
261
+ }
262
+ return {
263
+ resolvedConfig,
264
+ resolvedConfigPath,
265
+ resolvedConfigContent,
266
+ loadConfig
267
+ };
268
+ }
269
+ function useTransform({ cwd, cssCodegenFilepath, tsCodegenFilepath, scan, fnName, usages, engine, transformedFormat, triggerStyleUpdated, triggerTsCodegenUpdated }) {
270
+ const ESCAPE_REPLACE_RE = /[.*+?^${}()|[\]\\/]/g;
271
+ function createFnUtils(fnName$1) {
272
+ const available = {
273
+ normal: new Set([fnName$1]),
274
+ forceString: new Set([
275
+ `${fnName$1}.str`,
276
+ `${fnName$1}['str']`,
277
+ `${fnName$1}["str"]`,
278
+ `${fnName$1}[\`str\`]`
279
+ ]),
280
+ forceArray: new Set([
281
+ `${fnName$1}.arr`,
282
+ `${fnName$1}['arr']`,
283
+ `${fnName$1}["arr"]`,
284
+ `${fnName$1}[\`arr\`]`
285
+ ]),
286
+ forceInline: new Set([
287
+ `${fnName$1}.inl`,
288
+ `${fnName$1}['inl']`,
289
+ `${fnName$1}["inl"]`,
290
+ `${fnName$1}[\`inl\`]`
291
+ ]),
292
+ normalPreview: new Set([`${fnName$1}p`]),
293
+ forceStringPreview: new Set([
294
+ `${fnName$1}p.str`,
295
+ `${fnName$1}p['str']`,
296
+ `${fnName$1}p["str"]`,
297
+ `${fnName$1}p[\`str\`]`
298
+ ]),
299
+ forceArrayPreview: new Set([
300
+ `${fnName$1}p.arr`,
301
+ `${fnName$1}p['arr']`,
302
+ `${fnName$1}p["arr"]`,
303
+ `${fnName$1}p[\`arr\`]`
304
+ ]),
305
+ forceInlinePreview: new Set([
306
+ `${fnName$1}p.inl`,
307
+ `${fnName$1}p['inl']`,
308
+ `${fnName$1}p["inl"]`,
309
+ `${fnName$1}p[\`inl\`]`
310
+ ])
311
+ };
312
+ return {
313
+ isNormal: (fnName$2) => available.normal.has(fnName$2) || available.normalPreview.has(fnName$2),
314
+ isForceString: (fnName$2) => available.forceString.has(fnName$2) || available.forceStringPreview.has(fnName$2),
315
+ isForceArray: (fnName$2) => available.forceArray.has(fnName$2) || available.forceArrayPreview.has(fnName$2),
316
+ isForceInline: (fnName$2) => available.forceInline.has(fnName$2) || available.forceInlinePreview.has(fnName$2),
317
+ isPreview: (fnName$2) => available.normalPreview.has(fnName$2) || available.forceStringPreview.has(fnName$2) || available.forceArrayPreview.has(fnName$2) || available.forceInlinePreview.has(fnName$2),
318
+ RE: new RegExp(`\\b(${Object.values(available).flatMap((s) => [...s].map((f) => `(${f.replace(ESCAPE_REPLACE_RE, "\\$&")})`)).join("|")})\\(`, "g")
319
+ };
320
+ }
321
+ const fnUtils = createFnUtils(fnName);
322
+ function findFunctionCalls(code) {
323
+ const RE = fnUtils.RE;
324
+ const result = [];
325
+ let matched = RE.exec(code);
326
+ while (matched != null) {
327
+ const fnName$1 = matched[1];
328
+ const start = matched.index;
329
+ let end = start + fnName$1.length;
330
+ let depth = 1;
331
+ let inString = false;
332
+ while (depth > 0) {
333
+ end++;
334
+ if (inString === false && code[end] === "(") depth++;
335
+ else if (inString === false && code[end] === ")") depth--;
336
+ else if (inString === false && (code[end] === "'" || code[end] === "\"")) inString = code[end];
337
+ else if (inString === code[end]) inString = false;
345
338
  }
346
- ctx.isReady = true;
347
- }, 300),
348
- isReady: false,
349
- configSources,
350
- resolvedConfigPath: null,
351
- engine: null,
352
- transform: async (code, id) => {
353
- try {
354
- if (ctx.isReady === false || !needToTransform(id)) return;
355
- ctx.usages.delete(id);
356
- const functionCalls = findFunctionCalls(code, ctx.fnUtils.RE);
357
- if (functionCalls.length === 0) return;
358
- const usages = [];
359
- const transformed = new MagicString(code);
360
- for (const fnCall of functionCalls) {
361
- const argsStr = `[${fnCall.snippet.slice(fnCall.fnName.length + 1, -1)}]`;
362
- const args = new Function(`return ${argsStr}`)();
363
- const names = await ctx.engine.use(...args);
364
- const usage = {
365
- atomicStyleIds: names,
366
- params: args
367
- };
368
- usages.push(usage);
369
- let transformedContent;
370
- if (ctx.fnUtils.isNormal(fnCall.fnName)) transformedContent = ctx.transformedFormat === "array" ? `[${names.map((n) => `'${n}'`).join(", ")}]` : ctx.transformedFormat === "string" ? `'${names.join(" ")}'` : names.join(" ");
371
- else if (ctx.fnUtils.isForceString(fnCall.fnName)) transformedContent = `'${names.join(" ")}'`;
372
- else if (ctx.fnUtils.isForceArray(fnCall.fnName)) transformedContent = `[${names.map((n) => `'${n}'`).join(", ")}]`;
373
- else if (ctx.fnUtils.isForceInline(fnCall.fnName)) transformedContent = names.join(" ");
374
- else throw new Error(`Unexpected function name: ${fnCall.fnName}`);
375
- transformed.update(fnCall.start, fnCall.end + 1, transformedContent);
376
- }
377
- ctx.usages.set(id, usages);
378
- ctx.hooks.styleUpdated.trigger();
379
- ctx.hooks.tsCodegenUpdated.trigger();
380
- return {
381
- code: transformed.toString(),
382
- map: transformed.generateMap({ hires: true })
339
+ const snippet = code.slice(start, end + 1);
340
+ result.push({
341
+ fnName: fnName$1,
342
+ start,
343
+ end,
344
+ snippet
345
+ });
346
+ matched = RE.exec(code);
347
+ }
348
+ return result;
349
+ }
350
+ async function transform(code, id) {
351
+ const _engine = engine();
352
+ if (_engine == null) return null;
353
+ try {
354
+ log.debug(`Transforming file: ${id}`);
355
+ usages.delete(id);
356
+ const functionCalls = findFunctionCalls(code);
357
+ if (functionCalls.length === 0) return;
358
+ log.debug(`Found ${functionCalls.length} style function calls in ${id}`);
359
+ const usageList = [];
360
+ const transformed = new MagicString(code);
361
+ for (const fnCall of functionCalls) {
362
+ const argsStr = `[${fnCall.snippet.slice(fnCall.fnName.length + 1, -1)}]`;
363
+ const args = new Function(`return ${argsStr}`)();
364
+ const names = await _engine.use(...args);
365
+ const usage = {
366
+ atomicStyleIds: names,
367
+ params: args
383
368
  };
384
- } catch (error) {
385
- warn(`Failed to transform code: ${error.message}`, error);
386
- return;
369
+ usageList.push(usage);
370
+ let transformedContent;
371
+ if (fnUtils.isNormal(fnCall.fnName)) transformedContent = transformedFormat === "array" ? `[${names.map((n) => `'${n}'`).join(", ")}]` : transformedFormat === "string" ? `'${names.join(" ")}'` : names.join(" ");
372
+ else if (fnUtils.isForceString(fnCall.fnName)) transformedContent = `'${names.join(" ")}'`;
373
+ else if (fnUtils.isForceArray(fnCall.fnName)) transformedContent = `[${names.map((n) => `'${n}'`).join(", ")}]`;
374
+ else if (fnUtils.isForceInline(fnCall.fnName)) transformedContent = names.join(" ");
375
+ else throw new Error(`Unexpected function name: ${fnCall.fnName}`);
376
+ transformed.update(fnCall.start, fnCall.end + 1, transformedContent);
387
377
  }
378
+ usages.set(id, usageList);
379
+ triggerStyleUpdated();
380
+ triggerTsCodegenUpdated();
381
+ log.debug(`Transformed ${usageList.length} style usages in ${id}`);
382
+ return {
383
+ code: transformed.toString(),
384
+ map: transformed.generateMap({ hires: true })
385
+ };
386
+ } catch (error) {
387
+ log.error(`Failed to transform code (${join(cwd(), id)}): ${error.message}`, error);
388
+ return;
389
+ }
390
+ }
391
+ return {
392
+ transformFilter: {
393
+ include: scan.include,
394
+ exclude: [
395
+ ...scan.exclude,
396
+ cssCodegenFilepath(),
397
+ ...tsCodegenFilepath() ? [tsCodegenFilepath()] : []
398
+ ]
399
+ },
400
+ transform
401
+ };
402
+ }
403
+ function createCtx(options) {
404
+ const { cwd, cssCodegenFilepath, tsCodegenFilepath } = usePaths(options);
405
+ const { resolvedConfig, resolvedConfigPath, resolvedConfigContent, loadConfig } = useConfig({
406
+ ...options,
407
+ cwd,
408
+ tsCodegenFilepath
409
+ });
410
+ const usages = /* @__PURE__ */ new Map();
411
+ const engine = signal(null);
412
+ const hooks = {
413
+ styleUpdated: createEventHook(),
414
+ tsCodegenUpdated: createEventHook()
415
+ };
416
+ const { transformFilter, transform } = useTransform({
417
+ ...options,
418
+ cwd,
419
+ cssCodegenFilepath,
420
+ tsCodegenFilepath,
421
+ usages,
422
+ engine,
423
+ triggerStyleUpdated: () => hooks.styleUpdated.trigger(),
424
+ triggerTsCodegenUpdated: () => hooks.tsCodegenUpdated.trigger()
425
+ });
426
+ const ctx = {
427
+ currentPackageName: options.currentPackageName,
428
+ fnName: options.fnName,
429
+ transformedFormat: options.transformedFormat,
430
+ get cwd() {
431
+ return cwd();
432
+ },
433
+ set cwd(v) {
434
+ cwd(v);
435
+ },
436
+ get cssCodegenFilepath() {
437
+ return cssCodegenFilepath();
388
438
  },
389
- getCssContent: async (isDev) => {
390
- if (ctx.isReady === false) return null;
439
+ get tsCodegenFilepath() {
440
+ return tsCodegenFilepath();
441
+ },
442
+ get hasVue() {
443
+ return isPackageExists("vue", { paths: [cwd()] });
444
+ },
445
+ get resolvedConfig() {
446
+ return resolvedConfig();
447
+ },
448
+ get resolvedConfigPath() {
449
+ return resolvedConfigPath();
450
+ },
451
+ get resolvedConfigContent() {
452
+ return resolvedConfigContent();
453
+ },
454
+ loadConfig,
455
+ usages,
456
+ hooks,
457
+ get engine() {
458
+ const _engine = engine();
459
+ if (_engine == null) throw new Error("Engine is not initialized yet");
460
+ return _engine;
461
+ },
462
+ transformFilter,
463
+ transform: async (code, id) => {
464
+ await ctx.setupPromise;
465
+ return transform(code, id);
466
+ },
467
+ getCssCodegenContent: async () => {
468
+ await ctx.setupPromise;
469
+ log.debug("Generating CSS code");
391
470
  const atomicStyleIds = [...new Set([...ctx.usages.values()].flatMap((i) => [...new Set(i.flatMap((i$1) => i$1.atomicStyleIds))]))];
471
+ log.debug(`Collecting ${atomicStyleIds.length} atomic style IDs`);
392
472
  return [
393
473
  `/* Auto-generated by ${ctx.currentPackageName} */`,
394
- await ctx.engine.renderPreflights(isDev),
395
- await ctx.engine.renderAtomicStyles(isDev, { atomicStyleIds })
474
+ await ctx.engine.renderPreflights(true),
475
+ await ctx.engine.renderAtomicStyles(true, { atomicStyleIds })
396
476
  ].join("\n").trim();
397
477
  },
398
478
  getTsCodegenContent: async () => {
399
- if (ctx.isReady === false || ctx.tsCodegenFilepath == null) return null;
479
+ await ctx.setupPromise;
480
+ if (ctx.tsCodegenFilepath == null) return null;
400
481
  return await generateTsCodegenContent(ctx);
401
482
  },
402
- writeDevCssFile: debounce(async () => {
403
- const content = await ctx.getCssContent(true);
483
+ writeCssCodegenFile: async () => {
484
+ await ctx.setupPromise;
485
+ const content = await ctx.getCssCodegenContent();
404
486
  if (content == null) return;
405
- await writeFile(ctx.devCssFilepath, content);
406
- }, 300),
407
- writeTsCodegenFile: debounce(async () => {
487
+ await mkdir(dirname(ctx.cssCodegenFilepath), { recursive: true }).catch(() => {});
488
+ log.debug(`Writing CSS code generation file: ${ctx.cssCodegenFilepath}`);
489
+ await writeFile(ctx.cssCodegenFilepath, content);
490
+ },
491
+ writeTsCodegenFile: async () => {
492
+ await ctx.setupPromise;
493
+ if (ctx.tsCodegenFilepath == null) return;
408
494
  const content = await ctx.getTsCodegenContent();
409
- if (ctx.tsCodegenFilepath == null || content == null) return;
495
+ if (content == null) return;
496
+ await mkdir(dirname(ctx.tsCodegenFilepath), { recursive: true }).catch(() => {});
497
+ log.debug(`Writing TypeScript code generation file: ${ctx.tsCodegenFilepath}`);
410
498
  await writeFile(ctx.tsCodegenFilepath, content);
411
- }, 300)
499
+ },
500
+ fullyCssCodegen: async () => {
501
+ await ctx.setupPromise;
502
+ log.debug("Starting full CSS code generation scan");
503
+ const stream = globbyStream(options.scan.include, { ignore: options.scan.exclude });
504
+ let fileCount = 0;
505
+ const _cwd = cwd();
506
+ for await (const entry of stream) {
507
+ const code = await readFile(join(_cwd, entry), "utf-8");
508
+ await ctx.transform(code, entry);
509
+ fileCount++;
510
+ }
511
+ log.debug(`Scanned ${fileCount} files for style collection`);
512
+ await ctx.writeCssCodegenFile();
513
+ },
514
+ setupPromise: null,
515
+ setup: () => {
516
+ ctx.setupPromise = setup().catch((error) => {
517
+ log.error(`Failed to setup integration context: ${error.message}`, error);
518
+ }).then(() => {
519
+ ctx.setupPromise = null;
520
+ });
521
+ return ctx.setupPromise;
522
+ }
412
523
  };
413
- await ctx.init();
524
+ async function setup() {
525
+ log.debug("Setting up integration context");
526
+ usages.clear();
527
+ hooks.styleUpdated.listeners.clear();
528
+ hooks.tsCodegenUpdated.listeners.clear();
529
+ engine(null);
530
+ await loadConfig();
531
+ const devPlugin = defineEnginePlugin({
532
+ name: "@pikacss/integration:dev",
533
+ preflightUpdated: () => hooks.styleUpdated.trigger(),
534
+ atomicStyleAdded: () => hooks.styleUpdated.trigger(),
535
+ autocompleteConfigUpdated: () => hooks.tsCodegenUpdated.trigger()
536
+ });
537
+ try {
538
+ const config = resolvedConfig() ?? {};
539
+ config.plugins = config.plugins ?? [];
540
+ config.plugins.unshift(devPlugin);
541
+ log.debug("Creating engine with loaded/default config");
542
+ engine(await createEngine(config));
543
+ } catch (error) {
544
+ log.error(`Failed to create engine: ${error.message}. Falling back to default config.`, error);
545
+ engine(await createEngine({ plugins: [devPlugin] }));
546
+ }
547
+ log.debug("Integration context setup successfully");
548
+ }
414
549
  return ctx;
415
550
  }
416
551