@pandacss/parser 0.0.0-dev-20230321103030 → 0.0.0-dev-20230323194924

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.ts CHANGED
@@ -6,6 +6,7 @@ type ParserNodeOptions = {
6
6
  name: string;
7
7
  type: 'pattern' | 'recipe';
8
8
  props?: string[];
9
+ baseName: string;
9
10
  };
10
11
  type ParserOptions = {
11
12
  importMap: Record<'css' | 'recipe' | 'pattern' | 'jsx', string>;
@@ -15,6 +16,7 @@ type ParserOptions = {
15
16
  isStyleProp: (prop: string) => boolean;
16
17
  };
17
18
  };
19
+ type ParserMode = 'box-extractor' | 'internal';
18
20
 
19
21
  type ProjectOptions = Partial<ProjectOptions$1> & {
20
22
  readFile: (filePath: string) => string;
@@ -25,10 +27,10 @@ declare const createProject: ({ getFiles, readFile, parserOptions, ...projectOpt
25
27
  getSourceFile: (filePath: string) => ts_morph.SourceFile | undefined;
26
28
  removeSourceFile: (filePath: string) => void;
27
29
  createSourceFile: (filePath: string) => ts_morph.SourceFile;
28
- parseSourceFile: (filePath: string) => _pandacss_types.ParserResult | undefined;
30
+ parseSourceFile: (filePath: string, properties: string[], mode?: ParserMode) => _pandacss_types.ParserResult | undefined;
29
31
  reloadSourceFile: (filePath: string) => ts_morph.FileSystemRefreshResult | undefined;
30
32
  reloadSourceFiles: () => void;
31
33
  };
32
34
  type Project = ReturnType<typeof createProject>;
33
35
 
34
- export { Project, ProjectOptions, createProject };
36
+ export { ParserMode, Project, ProjectOptions, createProject };
package/dist/index.js CHANGED
@@ -26,11 +26,13 @@ module.exports = __toCommonJS(src_exports);
26
26
 
27
27
  // src/project.ts
28
28
  var import_lil_fp = require("lil-fp");
29
- var import_ts_morph4 = require("ts-morph");
29
+ var import_ts_morph5 = require("ts-morph");
30
30
 
31
31
  // src/parser.ts
32
+ var import_core = require("@box-extractor/core");
32
33
  var import_logger = require("@pandacss/logger");
33
34
  var import_shared2 = require("@pandacss/shared");
35
+ var import_ts_morph4 = require("ts-morph");
34
36
  var import_ts_pattern3 = require("ts-pattern");
35
37
 
36
38
  // src/call-expression.ts
@@ -261,11 +263,10 @@ function createImportMatcher(mod, values) {
261
263
  };
262
264
  }
263
265
  function createParser(options) {
264
- return function parse(sourceFile) {
266
+ return function parse(sourceFile, confProperties, mode = "internal") {
265
267
  if (!sourceFile)
266
268
  return;
267
269
  const filePath = sourceFile.getFilePath();
268
- const collector = createParserResult();
269
270
  const { jsx, importMap } = options;
270
271
  const importRegex = [
271
272
  createImportMatcher(importMap.css, ["css", "cva"]),
@@ -280,20 +281,158 @@ function createParser(options) {
280
281
  return importRegex.some(({ regex, mod }) => regex.test(value.id) && value.mod.includes(mod));
281
282
  }
282
283
  });
283
- if (imports.value.length) {
284
- import_logger.logger.debug("ast:import", `Found import { ${imports} } in ${filePath}`);
284
+ const collector = createParserResult();
285
+ if (!imports.value.length) {
286
+ import_logger.logger.debug("ast:import", `No import found in ${filePath}`);
287
+ return collector;
285
288
  }
289
+ import_logger.logger.debug("ast:import", `Found import { ${imports} } in ${filePath}`);
290
+ const [css] = importRegex;
286
291
  const isValidPattern = imports.createMatch(importMap.pattern);
287
292
  const isValidRecipe = imports.createMatch(importMap.recipe);
288
293
  const isValidStyleFn = (name) => name === jsx?.factory;
294
+ const jsxFactoryAlias = jsx ? imports.getAlias(jsx.factory) : "panda";
295
+ const jsxPatternNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "pattern" && node.name).join("|")})$`);
296
+ const jsxRecipeNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "recipe" && node.name).join("|")})$`);
297
+ if (mode === "box-extractor") {
298
+ const recipes = /* @__PURE__ */ new Map();
299
+ imports.value.forEach((importDeclaration) => {
300
+ const { name, alias } = importDeclaration;
301
+ const isRecipe = isValidRecipe(name);
302
+ if (isRecipe) {
303
+ recipes.set(alias, true);
304
+ }
305
+ });
306
+ const functions = /* @__PURE__ */ new Map();
307
+ const components = /* @__PURE__ */ new Map();
308
+ const propertiesMap = new Map(confProperties.map((prop) => [prop, true]));
309
+ const cvaAlias = imports.getAlias("cva");
310
+ const cssAlias = imports.getAlias("css");
311
+ if (options.jsx) {
312
+ options.jsx.nodes.forEach((node) => {
313
+ const properties = node.props ? new Map(propertiesMap) : propertiesMap;
314
+ const alias = imports.getAlias(node.name);
315
+ node.props?.forEach((prop) => properties.set(prop, true));
316
+ functions.set(alias, properties);
317
+ components.set(alias, properties);
318
+ });
319
+ }
320
+ const matchTag = (0, import_shared2.memo)((tagName) => {
321
+ return components.has(tagName) || isUpperCase(tagName) || tagName.startsWith(jsxFactoryAlias);
322
+ });
323
+ const matchTagProp = (0, import_shared2.memo)((tagName, propName) => {
324
+ if (propertiesMap.size === 0)
325
+ return true;
326
+ return Boolean(components.get(tagName)?.get(propName)) || propertiesMap.has(propName);
327
+ });
328
+ const matchFn = (0, import_shared2.memo)((fnName) => {
329
+ if (recipes.has(fnName))
330
+ return true;
331
+ if (fnName === cvaAlias || fnName === cssAlias || fnName.startsWith(jsxFactoryAlias))
332
+ return true;
333
+ return Boolean(functions.get(fnName));
334
+ });
335
+ const matchFnProp = (0, import_shared2.memo)((fnName, propName) => {
336
+ if (propertiesMap.size === 0)
337
+ return true;
338
+ if (recipes.has(fnName))
339
+ return true;
340
+ if (fnName === cvaAlias)
341
+ return true;
342
+ if (fnName.startsWith(jsxFactoryAlias))
343
+ return true;
344
+ if (fnName === cssAlias)
345
+ return Boolean(propertiesMap.get(propName) || propName === "selectors");
346
+ return Boolean(functions.get(fnName)?.get(propName));
347
+ });
348
+ const measure2 = import_logger.logger.time.debug(`Tokens extracted from ${filePath}`);
349
+ const extractResultByName = (0, import_core.extract)({
350
+ ast: sourceFile,
351
+ components: {
352
+ matchTag: (prop) => matchTag(prop.tagName),
353
+ matchProp: (prop) => matchTagProp(prop.tagName, prop.propName)
354
+ },
355
+ functions: {
356
+ matchFn: (prop) => matchFn(prop.fnName),
357
+ matchProp: (prop) => matchFnProp(prop.fnName, prop.propName),
358
+ matchArg: (prop) => {
359
+ if (prop.fnName === jsxFactoryAlias && prop.index === 1 && import_ts_morph4.Node.isIdentifier(prop.argNode))
360
+ return false;
361
+ return true;
362
+ }
363
+ },
364
+ flags: { skipTraverseFiles: true }
365
+ });
366
+ measure2();
367
+ extractResultByName.forEach((result, alias) => {
368
+ const name = imports.getName(alias);
369
+ import_logger.logger.debug(`ast:${name}`, { filePath, result, alias });
370
+ if (result.kind === "function") {
371
+ (0, import_ts_pattern3.match)(name).when(css.match, (name2) => {
372
+ result.queryList.forEach((query) => {
373
+ collector.set(name2, {
374
+ name: name2,
375
+ box: query.box.value[0],
376
+ data: (0, import_core.unbox)(query.box.value[0])
377
+ });
378
+ });
379
+ }).when(isValidPattern, (name2) => {
380
+ result.queryList.forEach((query) => {
381
+ collector.setPattern(name2, {
382
+ name: name2,
383
+ box: query.box.value[0],
384
+ data: (0, import_core.unbox)(query.box.value[0])
385
+ });
386
+ });
387
+ }).when(isValidRecipe, (name2) => {
388
+ result.queryList.forEach((query) => {
389
+ collector.setRecipe(name2, {
390
+ name: name2,
391
+ box: query.box.value[0],
392
+ data: (0, import_core.unbox)(query.box.value[0])
393
+ });
394
+ });
395
+ }).when(isValidStyleFn, () => {
396
+ result.queryList.forEach((query) => {
397
+ collector.setCva({ name, box: query.box, data: (0, import_core.unbox)(query.box) });
398
+ });
399
+ }).otherwise(() => {
400
+ });
401
+ } else if (result.kind === "component") {
402
+ result.queryList.forEach((query) => {
403
+ let type;
404
+ const data = (0, import_core.unbox)(query.box);
405
+ import_logger.logger.debug(`ast:jsx:${name}`, { filePath, result: data });
406
+ if (jsx && name.startsWith(jsxFactoryAlias)) {
407
+ type = "jsx-factory";
408
+ } else if (jsxPatternNodes.test(name)) {
409
+ type = "pattern";
410
+ } else if (jsxRecipeNodes.test(name)) {
411
+ type = "recipe";
412
+ } else {
413
+ type = "jsx";
414
+ }
415
+ collector.jsx.add({
416
+ // from "panda.*" -> "panda.button"
417
+ name,
418
+ box: query.box,
419
+ type,
420
+ data
421
+ });
422
+ });
423
+ }
424
+ });
425
+ return collector;
426
+ }
427
+ const measure = import_logger.logger.time.debug(`Tokens extracted & collected from ${filePath}`);
289
428
  visitCallExpressions(sourceFile, {
290
429
  match: (0, import_shared2.memo)((name) => imports.match(name)),
291
430
  fn({ name: _name, data }) {
292
431
  const name = imports.getName(_name);
293
- const [css] = importRegex;
432
+ const [css2] = importRegex;
294
433
  const result = { name, data };
295
434
  import_logger.logger.debug(`ast:${name}`, { filePath, result });
296
- (0, import_ts_pattern3.match)(name).when(css.match, (name2) => {
435
+ (0, import_ts_pattern3.match)(name).when(css2.match, (name2) => {
297
436
  collector.set(name2, result);
298
437
  }).when(isValidPattern, (name2) => {
299
438
  collector.setPattern(name2, result);
@@ -305,9 +444,6 @@ function createParser(options) {
305
444
  });
306
445
  }
307
446
  });
308
- const jsxFactoryAlias = jsx ? imports.getAlias(jsx.factory) : "panda";
309
- const jsxPatternNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "pattern" && node.name).join("|")})$`);
310
- const jsxRecipeNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "recipe" && node.name).join("|")})$`);
311
447
  visitJsxElement(sourceFile, {
312
448
  match: {
313
449
  tag: (0, import_shared2.memo)((name) => {
@@ -333,13 +469,14 @@ function createParser(options) {
333
469
  collector.jsx.add({ type, name, data });
334
470
  }
335
471
  });
472
+ measure();
336
473
  return collector;
337
474
  };
338
475
  }
339
476
  var isUpperCase = (value) => value[0] === value[0].toUpperCase();
340
477
 
341
478
  // src/project.ts
342
- var createTsProject = (options) => new import_ts_morph4.Project({
479
+ var createTsProject = (options) => new import_ts_morph5.Project({
343
480
  skipAddingFilesFromTsConfig: true,
344
481
  skipFileDependencyResolution: true,
345
482
  skipLoadingLibFiles: true,
@@ -365,10 +502,10 @@ var createProject = ({ getFiles, readFile, parserOptions, ...projectOptions }) =
365
502
  },
366
503
  createSourceFile: (filePath) => project.createSourceFile(filePath, readFile(filePath), {
367
504
  overwrite: true,
368
- scriptKind: import_ts_morph4.ScriptKind.TSX
505
+ scriptKind: import_ts_morph5.ScriptKind.TSX
369
506
  }),
370
- parseSourceFile: (filePath) => {
371
- return parser(project.getSourceFile(filePath));
507
+ parseSourceFile: (filePath, properties, mode = "box-extractor") => {
508
+ return parser(project.getSourceFile(filePath), properties, mode);
372
509
  }
373
510
  })),
374
511
  (0, import_lil_fp.tap)(({ createSourceFile }) => {
package/dist/index.mjs CHANGED
@@ -3,8 +3,10 @@ import { Obj, pipe, tap } from "lil-fp";
3
3
  import { Project as TsProject, ScriptKind } from "ts-morph";
4
4
 
5
5
  // src/parser.ts
6
+ import { extract, unbox } from "@box-extractor/core";
6
7
  import { logger } from "@pandacss/logger";
7
8
  import { memo as memo2 } from "@pandacss/shared";
9
+ import { Node as Node4 } from "ts-morph";
8
10
  import { match as match3 } from "ts-pattern";
9
11
 
10
12
  // src/call-expression.ts
@@ -237,11 +239,10 @@ function createImportMatcher(mod, values) {
237
239
  };
238
240
  }
239
241
  function createParser(options) {
240
- return function parse(sourceFile) {
242
+ return function parse(sourceFile, confProperties, mode = "internal") {
241
243
  if (!sourceFile)
242
244
  return;
243
245
  const filePath = sourceFile.getFilePath();
244
- const collector = createParserResult();
245
246
  const { jsx, importMap } = options;
246
247
  const importRegex = [
247
248
  createImportMatcher(importMap.css, ["css", "cva"]),
@@ -256,20 +257,158 @@ function createParser(options) {
256
257
  return importRegex.some(({ regex, mod }) => regex.test(value.id) && value.mod.includes(mod));
257
258
  }
258
259
  });
259
- if (imports.value.length) {
260
- logger.debug("ast:import", `Found import { ${imports} } in ${filePath}`);
260
+ const collector = createParserResult();
261
+ if (!imports.value.length) {
262
+ logger.debug("ast:import", `No import found in ${filePath}`);
263
+ return collector;
261
264
  }
265
+ logger.debug("ast:import", `Found import { ${imports} } in ${filePath}`);
266
+ const [css] = importRegex;
262
267
  const isValidPattern = imports.createMatch(importMap.pattern);
263
268
  const isValidRecipe = imports.createMatch(importMap.recipe);
264
269
  const isValidStyleFn = (name) => name === jsx?.factory;
270
+ const jsxFactoryAlias = jsx ? imports.getAlias(jsx.factory) : "panda";
271
+ const jsxPatternNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "pattern" && node.name).join("|")})$`);
272
+ const jsxRecipeNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "recipe" && node.name).join("|")})$`);
273
+ if (mode === "box-extractor") {
274
+ const recipes = /* @__PURE__ */ new Map();
275
+ imports.value.forEach((importDeclaration) => {
276
+ const { name, alias } = importDeclaration;
277
+ const isRecipe = isValidRecipe(name);
278
+ if (isRecipe) {
279
+ recipes.set(alias, true);
280
+ }
281
+ });
282
+ const functions = /* @__PURE__ */ new Map();
283
+ const components = /* @__PURE__ */ new Map();
284
+ const propertiesMap = new Map(confProperties.map((prop) => [prop, true]));
285
+ const cvaAlias = imports.getAlias("cva");
286
+ const cssAlias = imports.getAlias("css");
287
+ if (options.jsx) {
288
+ options.jsx.nodes.forEach((node) => {
289
+ const properties = node.props ? new Map(propertiesMap) : propertiesMap;
290
+ const alias = imports.getAlias(node.name);
291
+ node.props?.forEach((prop) => properties.set(prop, true));
292
+ functions.set(alias, properties);
293
+ components.set(alias, properties);
294
+ });
295
+ }
296
+ const matchTag = memo2((tagName) => {
297
+ return components.has(tagName) || isUpperCase(tagName) || tagName.startsWith(jsxFactoryAlias);
298
+ });
299
+ const matchTagProp = memo2((tagName, propName) => {
300
+ if (propertiesMap.size === 0)
301
+ return true;
302
+ return Boolean(components.get(tagName)?.get(propName)) || propertiesMap.has(propName);
303
+ });
304
+ const matchFn = memo2((fnName) => {
305
+ if (recipes.has(fnName))
306
+ return true;
307
+ if (fnName === cvaAlias || fnName === cssAlias || fnName.startsWith(jsxFactoryAlias))
308
+ return true;
309
+ return Boolean(functions.get(fnName));
310
+ });
311
+ const matchFnProp = memo2((fnName, propName) => {
312
+ if (propertiesMap.size === 0)
313
+ return true;
314
+ if (recipes.has(fnName))
315
+ return true;
316
+ if (fnName === cvaAlias)
317
+ return true;
318
+ if (fnName.startsWith(jsxFactoryAlias))
319
+ return true;
320
+ if (fnName === cssAlias)
321
+ return Boolean(propertiesMap.get(propName) || propName === "selectors");
322
+ return Boolean(functions.get(fnName)?.get(propName));
323
+ });
324
+ const measure2 = logger.time.debug(`Tokens extracted from ${filePath}`);
325
+ const extractResultByName = extract({
326
+ ast: sourceFile,
327
+ components: {
328
+ matchTag: (prop) => matchTag(prop.tagName),
329
+ matchProp: (prop) => matchTagProp(prop.tagName, prop.propName)
330
+ },
331
+ functions: {
332
+ matchFn: (prop) => matchFn(prop.fnName),
333
+ matchProp: (prop) => matchFnProp(prop.fnName, prop.propName),
334
+ matchArg: (prop) => {
335
+ if (prop.fnName === jsxFactoryAlias && prop.index === 1 && Node4.isIdentifier(prop.argNode))
336
+ return false;
337
+ return true;
338
+ }
339
+ },
340
+ flags: { skipTraverseFiles: true }
341
+ });
342
+ measure2();
343
+ extractResultByName.forEach((result, alias) => {
344
+ const name = imports.getName(alias);
345
+ logger.debug(`ast:${name}`, { filePath, result, alias });
346
+ if (result.kind === "function") {
347
+ match3(name).when(css.match, (name2) => {
348
+ result.queryList.forEach((query) => {
349
+ collector.set(name2, {
350
+ name: name2,
351
+ box: query.box.value[0],
352
+ data: unbox(query.box.value[0])
353
+ });
354
+ });
355
+ }).when(isValidPattern, (name2) => {
356
+ result.queryList.forEach((query) => {
357
+ collector.setPattern(name2, {
358
+ name: name2,
359
+ box: query.box.value[0],
360
+ data: unbox(query.box.value[0])
361
+ });
362
+ });
363
+ }).when(isValidRecipe, (name2) => {
364
+ result.queryList.forEach((query) => {
365
+ collector.setRecipe(name2, {
366
+ name: name2,
367
+ box: query.box.value[0],
368
+ data: unbox(query.box.value[0])
369
+ });
370
+ });
371
+ }).when(isValidStyleFn, () => {
372
+ result.queryList.forEach((query) => {
373
+ collector.setCva({ name, box: query.box, data: unbox(query.box) });
374
+ });
375
+ }).otherwise(() => {
376
+ });
377
+ } else if (result.kind === "component") {
378
+ result.queryList.forEach((query) => {
379
+ let type;
380
+ const data = unbox(query.box);
381
+ logger.debug(`ast:jsx:${name}`, { filePath, result: data });
382
+ if (jsx && name.startsWith(jsxFactoryAlias)) {
383
+ type = "jsx-factory";
384
+ } else if (jsxPatternNodes.test(name)) {
385
+ type = "pattern";
386
+ } else if (jsxRecipeNodes.test(name)) {
387
+ type = "recipe";
388
+ } else {
389
+ type = "jsx";
390
+ }
391
+ collector.jsx.add({
392
+ // from "panda.*" -> "panda.button"
393
+ name,
394
+ box: query.box,
395
+ type,
396
+ data
397
+ });
398
+ });
399
+ }
400
+ });
401
+ return collector;
402
+ }
403
+ const measure = logger.time.debug(`Tokens extracted & collected from ${filePath}`);
265
404
  visitCallExpressions(sourceFile, {
266
405
  match: memo2((name) => imports.match(name)),
267
406
  fn({ name: _name, data }) {
268
407
  const name = imports.getName(_name);
269
- const [css] = importRegex;
408
+ const [css2] = importRegex;
270
409
  const result = { name, data };
271
410
  logger.debug(`ast:${name}`, { filePath, result });
272
- match3(name).when(css.match, (name2) => {
411
+ match3(name).when(css2.match, (name2) => {
273
412
  collector.set(name2, result);
274
413
  }).when(isValidPattern, (name2) => {
275
414
  collector.setPattern(name2, result);
@@ -281,9 +420,6 @@ function createParser(options) {
281
420
  });
282
421
  }
283
422
  });
284
- const jsxFactoryAlias = jsx ? imports.getAlias(jsx.factory) : "panda";
285
- const jsxPatternNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "pattern" && node.name).join("|")})$`);
286
- const jsxRecipeNodes = new RegExp(`(${jsx?.nodes.map((node) => node.type === "recipe" && node.name).join("|")})$`);
287
423
  visitJsxElement(sourceFile, {
288
424
  match: {
289
425
  tag: memo2((name) => {
@@ -309,6 +445,7 @@ function createParser(options) {
309
445
  collector.jsx.add({ type, name, data });
310
446
  }
311
447
  });
448
+ measure();
312
449
  return collector;
313
450
  };
314
451
  }
@@ -343,8 +480,8 @@ var createProject = ({ getFiles, readFile, parserOptions, ...projectOptions }) =
343
480
  overwrite: true,
344
481
  scriptKind: ScriptKind.TSX
345
482
  }),
346
- parseSourceFile: (filePath) => {
347
- return parser(project.getSourceFile(filePath));
483
+ parseSourceFile: (filePath, properties, mode = "box-extractor") => {
484
+ return parser(project.getSourceFile(filePath), properties, mode);
348
485
  }
349
486
  })),
350
487
  tap(({ createSourceFile }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pandacss/parser",
3
- "version": "0.0.0-dev-20230321103030",
3
+ "version": "0.0.0-dev-20230323194924",
4
4
  "description": "The static parser for panda css",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -11,16 +11,17 @@
11
11
  "access": "public"
12
12
  },
13
13
  "dependencies": {
14
+ "@box-extractor/core": "^0.8.4",
14
15
  "lil-fp": "1.2.5",
15
16
  "ts-morph": "17.0.1",
16
17
  "ts-pattern": "4.2.1",
17
- "@pandacss/is-valid-prop": "0.0.0-dev-20230321103030",
18
- "@pandacss/logger": "0.0.0-dev-20230321103030",
19
- "@pandacss/shared": "0.0.0-dev-20230321103030",
20
- "@pandacss/types": "0.0.0-dev-20230321103030"
18
+ "@pandacss/is-valid-prop": "0.0.0-dev-20230323194924",
19
+ "@pandacss/logger": "0.0.0-dev-20230323194924",
20
+ "@pandacss/shared": "0.0.0-dev-20230323194924",
21
+ "@pandacss/types": "0.0.0-dev-20230323194924"
21
22
  },
22
23
  "devDependencies": {
23
- "@pandacss/fixture": "0.0.0-dev-20230321103030"
24
+ "@pandacss/fixture": "0.0.0-dev-20230323194924"
24
25
  },
25
26
  "files": [
26
27
  "dist"