@pikacss/integration 0.0.46 → 0.0.47

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.d.mts CHANGED
@@ -3,7 +3,7 @@ import { SourceMap } from "magic-string";
3
3
  export * from "@pikacss/core";
4
4
 
5
5
  //#region src/eventHook.d.ts
6
- type EventHookListener<EventPayload> = (payload: EventPayload) => void | Promise<void>;
6
+ type EventHookListener<EventPayload> = (payload: EventPayload) => void;
7
7
  interface EventHook<EventPayload> {
8
8
  listeners: Set<EventHookListener<EventPayload>>;
9
9
  trigger: (payload: EventPayload) => void;
@@ -38,6 +38,19 @@ interface IntegrationContextOptions {
38
38
  cssCodegen: string;
39
39
  autoCreateConfig: boolean;
40
40
  }
41
+ type LoadedConfigResult = {
42
+ config: EngineConfig;
43
+ file: null;
44
+ content: null;
45
+ } | {
46
+ config: null;
47
+ file: null;
48
+ content: null;
49
+ } | {
50
+ config: EngineConfig;
51
+ file: string;
52
+ content: string;
53
+ };
41
54
  interface IntegrationContext {
42
55
  cwd: string;
43
56
  currentPackageName: string;
@@ -49,16 +62,7 @@ interface IntegrationContext {
49
62
  resolvedConfig: EngineConfig | Nullish;
50
63
  resolvedConfigPath: string | Nullish;
51
64
  resolvedConfigContent: string | Nullish;
52
- loadConfig: () => Promise<{
53
- config: EngineConfig;
54
- file: null;
55
- } | {
56
- config: null;
57
- file: null;
58
- } | {
59
- config: EngineConfig;
60
- file: string;
61
- }>;
65
+ loadConfig: () => Promise<LoadedConfigResult>;
62
66
  usages: Map<string, UsageRecord[]>;
63
67
  hooks: {
64
68
  styleUpdated: ReturnType<typeof createEventHook<void>>;
@@ -85,4 +89,4 @@ interface IntegrationContext {
85
89
  //#region src/ctx.d.ts
86
90
  declare function createCtx(options: IntegrationContextOptions): IntegrationContext;
87
91
  //#endregion
88
- export { FnUtils, IntegrationContext, IntegrationContextOptions, UsageRecord, createCtx };
92
+ export { FnUtils, IntegrationContext, IntegrationContextOptions, LoadedConfigResult, UsageRecord, createCtx };
package/dist/index.mjs CHANGED
@@ -35,21 +35,37 @@ function createEventHook() {
35
35
 
36
36
  //#endregion
37
37
  //#region src/tsCodegen.ts
38
+ function formatUnionType(parts) {
39
+ return parts.length > 0 ? parts.join(" | ") : "never";
40
+ }
38
41
  function formatUnionStringType(list) {
39
- return list.length > 0 ? list.map((i) => JSON.stringify(i)).join(" | ") : "never";
42
+ return formatUnionType(list.map((i) => JSON.stringify(i)));
43
+ }
44
+ function formatAutocompleteUnion(literals, patterns) {
45
+ return formatUnionType([...Array.from(literals, (value) => JSON.stringify(value)), ...patterns == null ? [] : [...patterns]]);
46
+ }
47
+ function formatAutocompleteValueMap(keys, entries, patternEntries, formatValue) {
48
+ const mergedKeys = new Set(keys);
49
+ for (const key of entries.keys()) mergedKeys.add(key);
50
+ for (const key of patternEntries.keys()) mergedKeys.add(key);
51
+ return mergedKeys.size > 0 ? `{ ${Array.from(mergedKeys, (key) => `${JSON.stringify(key)}: ${formatValue(entries.get(key) || [], patternEntries.get(key) || [])}`).join(", ")} }` : "never";
40
52
  }
41
53
  function generateAutocomplete(ctx) {
42
54
  const autocomplete = ctx.engine.config.autocomplete;
55
+ const patterns = autocomplete.patterns ?? {
56
+ selectors: /* @__PURE__ */ new Set(),
57
+ styleItemStrings: /* @__PURE__ */ new Set(),
58
+ properties: /* @__PURE__ */ new Map(),
59
+ cssProperties: /* @__PURE__ */ new Map()
60
+ };
43
61
  const { layers } = ctx.engine.config;
44
62
  const layerNames = sortLayerNames(layers);
45
63
  return [
46
64
  "export type Autocomplete = DefineAutocomplete<{",
47
- ` Selector: ${formatUnionStringType([...autocomplete.selectors])}`,
48
- ` StyleItemString: ${formatUnionStringType([...autocomplete.styleItemStrings])}`,
49
- ` ExtraProperty: ${formatUnionStringType([...autocomplete.extraProperties])}`,
50
- ` ExtraCssProperty: ${formatUnionStringType([...autocomplete.extraCssProperties])}`,
51
- ` PropertiesValue: { ${Array.from(autocomplete.properties.entries(), ([k, v]) => `${JSON.stringify(k)}: ${v.length > 0 ? v.join(" | ") : "never"}`).join(", ")} }`,
52
- ` CssPropertiesValue: { ${Array.from(autocomplete.cssProperties.entries(), ([k, v]) => `${JSON.stringify(k)}: ${formatUnionStringType(v)}`).join(", ")} }`,
65
+ ` Selector: ${formatAutocompleteUnion(autocomplete.selectors, patterns.selectors)}`,
66
+ ` StyleItemString: ${formatAutocompleteUnion(autocomplete.styleItemStrings, patterns.styleItemStrings)}`,
67
+ ` PropertyValue: ${formatAutocompleteValueMap(autocomplete.extraProperties, autocomplete.properties, patterns.properties, (values, patterns) => formatUnionType([...values, ...patterns]))}`,
68
+ ` CSSPropertyValue: ${formatAutocompleteValueMap(autocomplete.extraCssProperties, autocomplete.cssProperties, patterns.cssProperties, (values, patterns) => formatAutocompleteUnion(values, patterns))}`,
53
69
  ` Layer: ${formatUnionStringType(layerNames)}`,
54
70
  "}>",
55
71
  ""
@@ -148,7 +164,7 @@ async function generateTsCodegenContent(ctx) {
148
164
  " interface PikaAugment {",
149
165
  " Autocomplete: Autocomplete",
150
166
  " Selector: Autocomplete['Selector'] | CSSSelector",
151
- " CSSProperty: Autocomplete['ExtraCssProperty'] | CSSProperty",
167
+ " CSSProperty: ([Autocomplete['CSSPropertyValue']] extends [never] ? never : Extract<keyof Autocomplete['CSSPropertyValue'], string>) | CSSProperty",
152
168
  " Properties: Properties",
153
169
  " StyleDefinition: StyleDefinition",
154
170
  " StyleItem: StyleItem",
@@ -167,6 +183,36 @@ async function generateTsCodegenContent(ctx) {
167
183
 
168
184
  //#endregion
169
185
  //#region src/ctx.ts
186
+ function createConfigScaffoldContent({ currentPackageName, resolvedConfigPath, tsCodegenFilepath }) {
187
+ const relativeTsCodegenFilepath = tsCodegenFilepath == null ? null : `./${relative(dirname(resolvedConfigPath), tsCodegenFilepath)}`;
188
+ return [
189
+ ...relativeTsCodegenFilepath == null ? [] : [`/// <reference path="${relativeTsCodegenFilepath}" />`],
190
+ `import { defineEngineConfig } from '${currentPackageName}'`,
191
+ "",
192
+ "export default defineEngineConfig({",
193
+ " // Add your PikaCSS engine config here",
194
+ "})"
195
+ ].join("\n");
196
+ }
197
+ async function writeGeneratedFile(filepath, content) {
198
+ await mkdir(dirname(filepath), { recursive: true }).catch(() => {});
199
+ await writeFile(filepath, content);
200
+ }
201
+ async function evaluateConfigModule(resolvedConfigPath) {
202
+ log.info(`Using config file: ${resolvedConfigPath}`);
203
+ const { createJiti } = await import("jiti");
204
+ const jiti = createJiti(import.meta.url, { interopDefault: true });
205
+ const content = await readFile(resolvedConfigPath, "utf-8");
206
+ const config = (await jiti.evalModule(content, {
207
+ id: resolvedConfigPath,
208
+ forceTranspile: true
209
+ })).default;
210
+ return {
211
+ config: klona(config),
212
+ file: resolvedConfigPath,
213
+ content
214
+ };
215
+ }
170
216
  function usePaths({ cwd: _cwd, cssCodegen, tsCodegen }) {
171
217
  const cwd = signal(_cwd);
172
218
  return {
@@ -189,6 +235,20 @@ function useConfig({ cwd, tsCodegenFilepath, currentPackageName, autoCreateConfi
189
235
  for await (const entry of stream) return join(_cwd, entry);
190
236
  return null;
191
237
  }
238
+ async function ensureConfigPath(candidatePath) {
239
+ if (candidatePath != null) return candidatePath;
240
+ if (autoCreateConfig === false) {
241
+ log.warn("Config file not found and autoCreateConfig is false");
242
+ return null;
243
+ }
244
+ const resolvedConfigPath = specificConfigPath() ?? join(cwd(), "pika.config.js");
245
+ await writeGeneratedFile(resolvedConfigPath, createConfigScaffoldContent({
246
+ currentPackageName,
247
+ resolvedConfigPath,
248
+ tsCodegenFilepath: tsCodegenFilepath()
249
+ }));
250
+ return resolvedConfigPath;
251
+ }
192
252
  const inlineConfig = typeof configOrPath === "object" ? configOrPath : null;
193
253
  async function _loadConfig() {
194
254
  try {
@@ -201,43 +261,13 @@ function useConfig({ cwd, tsCodegenFilepath, currentPackageName, autoCreateConfi
201
261
  content: null
202
262
  };
203
263
  }
204
- let resolvedConfigPath = await findFirstExistingConfigPath();
205
- const _cwd = cwd();
206
- if (resolvedConfigPath == null) {
207
- if (autoCreateConfig === false) {
208
- log.warn("Config file not found and autoCreateConfig is false");
209
- return {
210
- config: null,
211
- file: null,
212
- content: null
213
- };
214
- }
215
- resolvedConfigPath = join(_cwd, specificConfigPath() ?? "pika.config.js");
216
- await mkdir(dirname(resolvedConfigPath), { recursive: true }).catch(() => {});
217
- const _tsCodegenFilepath = tsCodegenFilepath();
218
- const relativeTsCodegenFilepath = _tsCodegenFilepath == null ? null : `./${relative(dirname(resolvedConfigPath), _tsCodegenFilepath)}`;
219
- await writeFile(resolvedConfigPath, [
220
- ...relativeTsCodegenFilepath == null ? [] : [`/// <reference path="${relativeTsCodegenFilepath}" />`],
221
- `import { defineEngineConfig } from '${currentPackageName}'`,
222
- "",
223
- "export default defineEngineConfig({",
224
- " // Add your PikaCSS engine config here",
225
- "})"
226
- ].join("\n"));
227
- }
228
- log.info(`Using config file: ${resolvedConfigPath}`);
229
- const { createJiti } = await import("jiti");
230
- const jiti = createJiti(import.meta.url, { interopDefault: true });
231
- const content = await readFile(resolvedConfigPath, "utf-8");
232
- const config = (await jiti.evalModule(content, {
233
- id: resolvedConfigPath,
234
- forceTranspile: true
235
- })).default;
236
- return {
237
- config: klona(config),
238
- file: resolvedConfigPath,
239
- content
264
+ const resolvedConfigPath = await ensureConfigPath(await findFirstExistingConfigPath());
265
+ if (resolvedConfigPath == null) return {
266
+ config: null,
267
+ file: null,
268
+ content: null
240
269
  };
270
+ return await evaluateConfigModule(resolvedConfigPath);
241
271
  } catch (error) {
242
272
  log.error(`Failed to load config file: ${error.message}`, error);
243
273
  return {
@@ -304,6 +334,46 @@ function useTransform({ cwd, cssCodegenFilepath, tsCodegenFilepath, scan, fnName
304
334
  };
305
335
  }
306
336
  const fnUtils = createFnUtils(fnName);
337
+ function findTemplateExpressionEnd(code, start) {
338
+ let end = start;
339
+ let depth = 1;
340
+ let inString = false;
341
+ let isEscaped = false;
342
+ while (depth > 0 && end < code.length - 1) {
343
+ end++;
344
+ const char = code[end];
345
+ if (isEscaped) {
346
+ isEscaped = false;
347
+ continue;
348
+ }
349
+ if (char === "\\") {
350
+ isEscaped = true;
351
+ continue;
352
+ }
353
+ if (inString !== false) {
354
+ if (char === inString) inString = false;
355
+ else if (inString === "`" && char === "$" && code[end + 1] === "{") {
356
+ const nestedExpressionEnd = findTemplateExpressionEnd(code, end + 1);
357
+ if (nestedExpressionEnd === -1) return -1;
358
+ end = nestedExpressionEnd;
359
+ }
360
+ continue;
361
+ }
362
+ if (char === "{") depth++;
363
+ else if (char === "}") depth--;
364
+ else if (char === "'" || char === "\"" || char === "`") inString = char;
365
+ else if (char === "/" && code[end + 1] === "/") {
366
+ const lineEnd = code.indexOf("\n", end);
367
+ if (lineEnd === -1) return -1;
368
+ end = lineEnd;
369
+ } else if (char === "/" && code[end + 1] === "*") {
370
+ const commentEnd = code.indexOf("*/", end + 2);
371
+ if (commentEnd === -1) return -1;
372
+ end = commentEnd + 1;
373
+ }
374
+ }
375
+ return depth === 0 ? end : -1;
376
+ }
307
377
  function findFunctionCalls(code) {
308
378
  const RE = fnUtils.RE;
309
379
  const result = [];
@@ -329,8 +399,12 @@ function useTransform({ cwd, cssCodegenFilepath, tsCodegenFilepath, scan, fnName
329
399
  if (inString !== false) {
330
400
  if (char === inString) inString = false;
331
401
  else if (inString === "`" && char === "$" && code[end + 1] === "{") {
332
- end++;
333
- depth++;
402
+ const templateExpressionEnd = findTemplateExpressionEnd(code, end + 1);
403
+ if (templateExpressionEnd === -1) {
404
+ log.warn(`Malformed template literal expression in function call at position ${start}`);
405
+ break;
406
+ }
407
+ end = templateExpressionEnd;
334
408
  }
335
409
  continue;
336
410
  }
@@ -509,18 +583,16 @@ function createCtx(options) {
509
583
  await ctx.setupPromise;
510
584
  const content = await ctx.getCssCodegenContent();
511
585
  if (content == null) return;
512
- await mkdir(dirname(ctx.cssCodegenFilepath), { recursive: true }).catch(() => {});
513
586
  log.debug(`Writing CSS code generation file: ${ctx.cssCodegenFilepath}`);
514
- await writeFile(ctx.cssCodegenFilepath, content);
587
+ await writeGeneratedFile(ctx.cssCodegenFilepath, content);
515
588
  },
516
589
  writeTsCodegenFile: async () => {
517
590
  await ctx.setupPromise;
518
591
  if (ctx.tsCodegenFilepath == null) return;
519
592
  const content = await ctx.getTsCodegenContent();
520
593
  if (content == null) return;
521
- await mkdir(dirname(ctx.tsCodegenFilepath), { recursive: true }).catch(() => {});
522
594
  log.debug(`Writing TypeScript code generation file: ${ctx.tsCodegenFilepath}`);
523
- await writeFile(ctx.tsCodegenFilepath, content);
595
+ await writeGeneratedFile(ctx.tsCodegenFilepath, content);
524
596
  },
525
597
  fullyCssCodegen: async () => {
526
598
  await ctx.setupPromise;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pikacss/integration",
3
3
  "type": "module",
4
- "version": "0.0.46",
4
+ "version": "0.0.47",
5
5
  "author": "DevilTea <ch19980814@gmail.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -44,7 +44,7 @@
44
44
  "micromatch": "^4.0.8",
45
45
  "pathe": "^2.0.3",
46
46
  "perfect-debounce": "^2.1.0",
47
- "@pikacss/core": "0.0.46"
47
+ "@pikacss/core": "0.0.47"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/micromatch": "^4.0.10"