@bamboocss/parser 1.28.1 → 1.29.0

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.cjs CHANGED
@@ -65,7 +65,7 @@ function classifyProject(ctx, resultMap) {
65
65
  const { item, kind, filepath, localMaps } = opts;
66
66
  if (!item.box || _bamboocss_extractor.box.isUnresolvable(item.box)) return;
67
67
  if (!item.data) return;
68
- if (item.type === "cva-call" || item.type === "tokenVar") return;
68
+ if (item.type === "cva-call" || item.type === "tokenValue") return;
69
69
  const componentReportItem = {
70
70
  componentIndex: String(componentIndex++),
71
71
  componentName: item.name,
@@ -963,10 +963,10 @@ var ParserResult = class {
963
963
  if (unresolved.length) this.unresolved.push(...unresolved);
964
964
  }
965
965
  /**
966
- * `kind` separates `token()` from `token.var()`, which resolve to the value and to the
967
- * variable reference respectively. They share this set deliberately: everything that reads
968
- * a result for the token *path* — `collectTokenReferences`, keeping a declaration alive
969
- * through pruning — wants both, and only the fold cares which half was asked for.
966
+ * `kind` separates the variable reference — `token()` and its `token.var()` alias — from
967
+ * `token.value()`, the resolved literal. They share this set deliberately: everything that
968
+ * reads a result for the token *path* — `collectTokenReferences`, keeping a declaration
969
+ * alive through pruning — wants both, and only the fold cares which half was asked for.
970
970
  */
971
971
  setToken(result, kind = "token") {
972
972
  this.token.add(this.append(Object.assign({ type: kind }, result)));
@@ -1108,7 +1108,7 @@ function createParser(context) {
1108
1108
  ast: sourceFile,
1109
1109
  tokens: context.tokens ? {
1110
1110
  view: context.tokens.view,
1111
- isTokenFn: (fnName) => file.isTokenAlias(fnName)
1111
+ isTokenFn: (fnName) => file.isTokenFn(fnName)
1112
1112
  } : void 0,
1113
1113
  components: jsx.isEnabled ? {
1114
1114
  matchTag: (prop) => {
@@ -1171,13 +1171,14 @@ function createParser(context) {
1171
1171
  });
1172
1172
  return;
1173
1173
  }
1174
- if (file.isTokenVarFn(alias)) {
1174
+ const tokenMethod = file.tokenMethod(alias);
1175
+ if (tokenMethod) {
1175
1176
  result.queryList.forEach((query) => {
1176
1177
  if (query.kind === "call-expression") parserResult.setToken({
1177
- name: "token.var",
1178
+ name: `token.${tokenMethod}`,
1178
1179
  box: query.box.value[0] ?? _bamboocss_extractor.box.fallback(query.box),
1179
1180
  data: combineResult((0, _bamboocss_extractor.unbox)(query.box.value[0]))
1180
- }, "tokenVar");
1181
+ }, tokenMethod === "value" ? "tokenValue" : "token");
1181
1182
  });
1182
1183
  return;
1183
1184
  }
@@ -1276,6 +1277,31 @@ const createTsProject = (options) => new ts_morph.Project({
1276
1277
  ...normalizeCompilerOptions(options.compilerOptions)
1277
1278
  }
1278
1279
  });
1280
+ /**
1281
+ * How to parse a file, decided by its extension.
1282
+ *
1283
+ * Everything used to be `TSX`, which is not a superset of `TS`: the two disagree on exactly
1284
+ * the constructs where `<` is ambiguous. Under `TSX` a generic arrow `<T>(x: T) => x` and an
1285
+ * old-style assertion `<HTMLElement>node` parse as a *JSX element*, which then swallows the
1286
+ * rest of the file into its children. The file still reads fine and the bytes are unchanged;
1287
+ * the tree is simply wrong, and every `css()` call below the offending line stops existing as
1288
+ * far as extraction is concerned. It reports as styles that silently never got emitted.
1289
+ *
1290
+ * Only `.ts` moves. A `.ts` file cannot legally contain JSX — TypeScript requires `.tsx` for
1291
+ * that — so parsing one as `TSX` can only ever mis-parse, never accept something real.
1292
+ *
1293
+ * Everything else stays `TSX` deliberately:
1294
+ *
1295
+ * - `.js` and `.jsx` routinely carry JSX in projects that never adopted TypeScript, and `TSX`
1296
+ * accepts the type syntax they do not use anyway.
1297
+ * - a single-file component is stored under its own extension after `parser:before` rewrites
1298
+ * it to tsx, so `.vue` and `.svelte` have to keep parsing as tsx.
1299
+ * - an unknown extension is somebody's template that a hook may have compiled to jsx.
1300
+ */
1301
+ const scriptKindFor = (filePath) => {
1302
+ const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
1303
+ return extension === ".ts" || extension === ".mts" || extension === ".cts" ? ts_morph.ScriptKind.TS : ts_morph.ScriptKind.TSX;
1304
+ };
1279
1305
  var Project = class {
1280
1306
  options;
1281
1307
  project;
@@ -1421,7 +1447,7 @@ var Project = class {
1421
1447
  this.invalidate();
1422
1448
  return this.project.createSourceFile(filePath, readFile(filePath), {
1423
1449
  overwrite: true,
1424
- scriptKind: ts_morph.ScriptKind.TSX
1450
+ scriptKind: scriptKindFor(filePath)
1425
1451
  });
1426
1452
  };
1427
1453
  createSourceFiles = () => {
@@ -1432,7 +1458,7 @@ var Project = class {
1432
1458
  this.invalidate(!(filePath.includes("/") && this.project.getSourceFile(filePath)));
1433
1459
  return this.project.createSourceFile(filePath, content, {
1434
1460
  overwrite: true,
1435
- scriptKind: ts_morph.ScriptKind.TSX
1461
+ scriptKind: scriptKindFor(filePath)
1436
1462
  });
1437
1463
  };
1438
1464
  removeSourceFile = (filePath) => {
package/dist/index.d.cts CHANGED
@@ -95,18 +95,28 @@ declare class Generator extends Context {
95
95
  */
96
96
  private getThemeTokenVars;
97
97
  /**
98
- * Tokens whose javascript value is a `var()` reference rather than a literal.
99
- * `token('colors.text')` hands those to the caller as a reference, so the declaration
100
- * has to survive whether or not the generated css mentions it. Ordinary tokens resolve
101
- * to a literal in javascript and need no such exemption.
98
+ * The token declarations held open so a runtime `token()` can answer for any path.
102
99
  *
103
- * The two cases mirror `generateTokenJs`, which is what decides the value javascript
104
- * actually receives:
100
+ * `token()` hands javascript the *variable reference* for every token, so a path the build
101
+ * cannot resolve could name any of them and every declaration has to survive. That is a
102
+ * blunt instrument, and deliberately so: the alternative failure is a `var()` with no
103
+ * declaration behind it, which resolves to the guaranteed-invalid value and inherits
104
+ * rather than falling back — silently wrong, which is worse than visibly large.
105
105
  *
106
- * - A virtual token, or one carrying a condition, is handed its own `varRef`.
107
- * - A negative token is handed `calc(var(--x) * -1)`, so it is a reference too — but to
108
- * the *positive* token's declaration. Its own var is never declared, so the name has
109
- * to come out of the value.
106
+ * It used to be narrower, because `token()` used to return a *literal* for a plain token
107
+ * and only a `var()` for virtual, conditional and negative ones. That split is gone, and
108
+ * narrowing this to match it would now strand exactly the base tokens the old split made
109
+ * safe.
110
+ *
111
+ * So the gate below carries the whole saving. `styled-system/tokens` is generated into the
112
+ * project, so nothing outside it can import them -- if no file under `include` reaches for
113
+ * a token from javascript, no caller exists to serve and the declarations are as prunable
114
+ * as any other.
115
+ *
116
+ * That gate is all-or-nothing per project, which is the coarse part worth fixing next: a
117
+ * project whose token calls all resolve to string literals needs none of this, because
118
+ * `collectTokenReferences` already kept those paths by name. Deciding that needs the
119
+ * reference accounting the gate does not do yet -- see `tokensReachableFromJs`.
110
120
  */
111
121
  private getAlwaysKeptTokenVars;
112
122
  getParserCss: (decoder: StyleDecoder) => string;
@@ -230,12 +240,12 @@ declare class ParserResult implements ParserResultInterface {
230
240
  */
231
241
  private reportUnresolvedRecipe;
232
242
  /**
233
- * `kind` separates `token()` from `token.var()`, which resolve to the value and to the
234
- * variable reference respectively. They share this set deliberately: everything that reads
235
- * a result for the token *path* — `collectTokenReferences`, keeping a declaration alive
236
- * through pruning — wants both, and only the fold cares which half was asked for.
243
+ * `kind` separates the variable reference — `token()` and its `token.var()` alias — from
244
+ * `token.value()`, the resolved literal. They share this set deliberately: everything that
245
+ * reads a result for the token *path* — `collectTokenReferences`, keeping a declaration
246
+ * alive through pruning — wants both, and only the fold cares which half was asked for.
237
247
  */
238
- setToken(result: ResultItem, kind?: 'token' | 'tokenVar'): void;
248
+ setToken(result: ResultItem, kind?: 'token' | 'tokenValue'): void;
239
249
  setViewTransition(result: ResultItem): void;
240
250
  setPattern(name: string, result: ResultItem): void;
241
251
  setRecipe(recipeName: string, result: ResultItem): void;
package/dist/index.d.mts CHANGED
@@ -95,18 +95,28 @@ declare class Generator extends Context {
95
95
  */
96
96
  private getThemeTokenVars;
97
97
  /**
98
- * Tokens whose javascript value is a `var()` reference rather than a literal.
99
- * `token('colors.text')` hands those to the caller as a reference, so the declaration
100
- * has to survive whether or not the generated css mentions it. Ordinary tokens resolve
101
- * to a literal in javascript and need no such exemption.
98
+ * The token declarations held open so a runtime `token()` can answer for any path.
102
99
  *
103
- * The two cases mirror `generateTokenJs`, which is what decides the value javascript
104
- * actually receives:
100
+ * `token()` hands javascript the *variable reference* for every token, so a path the build
101
+ * cannot resolve could name any of them and every declaration has to survive. That is a
102
+ * blunt instrument, and deliberately so: the alternative failure is a `var()` with no
103
+ * declaration behind it, which resolves to the guaranteed-invalid value and inherits
104
+ * rather than falling back — silently wrong, which is worse than visibly large.
105
105
  *
106
- * - A virtual token, or one carrying a condition, is handed its own `varRef`.
107
- * - A negative token is handed `calc(var(--x) * -1)`, so it is a reference too — but to
108
- * the *positive* token's declaration. Its own var is never declared, so the name has
109
- * to come out of the value.
106
+ * It used to be narrower, because `token()` used to return a *literal* for a plain token
107
+ * and only a `var()` for virtual, conditional and negative ones. That split is gone, and
108
+ * narrowing this to match it would now strand exactly the base tokens the old split made
109
+ * safe.
110
+ *
111
+ * So the gate below carries the whole saving. `styled-system/tokens` is generated into the
112
+ * project, so nothing outside it can import them -- if no file under `include` reaches for
113
+ * a token from javascript, no caller exists to serve and the declarations are as prunable
114
+ * as any other.
115
+ *
116
+ * That gate is all-or-nothing per project, which is the coarse part worth fixing next: a
117
+ * project whose token calls all resolve to string literals needs none of this, because
118
+ * `collectTokenReferences` already kept those paths by name. Deciding that needs the
119
+ * reference accounting the gate does not do yet -- see `tokensReachableFromJs`.
110
120
  */
111
121
  private getAlwaysKeptTokenVars;
112
122
  getParserCss: (decoder: StyleDecoder) => string;
@@ -230,12 +240,12 @@ declare class ParserResult implements ParserResultInterface {
230
240
  */
231
241
  private reportUnresolvedRecipe;
232
242
  /**
233
- * `kind` separates `token()` from `token.var()`, which resolve to the value and to the
234
- * variable reference respectively. They share this set deliberately: everything that reads
235
- * a result for the token *path* — `collectTokenReferences`, keeping a declaration alive
236
- * through pruning — wants both, and only the fold cares which half was asked for.
243
+ * `kind` separates the variable reference — `token()` and its `token.var()` alias — from
244
+ * `token.value()`, the resolved literal. They share this set deliberately: everything that
245
+ * reads a result for the token *path* — `collectTokenReferences`, keeping a declaration
246
+ * alive through pruning — wants both, and only the fold cares which half was asked for.
237
247
  */
238
- setToken(result: ResultItem, kind?: 'token' | 'tokenVar'): void;
248
+ setToken(result: ResultItem, kind?: 'token' | 'tokenValue'): void;
239
249
  setViewTransition(result: ResultItem): void;
240
250
  setPattern(name: string, result: ResultItem): void;
241
251
  setRecipe(recipeName: string, result: ResultItem): void;
package/dist/index.mjs CHANGED
@@ -64,7 +64,7 @@ function classifyProject(ctx, resultMap) {
64
64
  const { item, kind, filepath, localMaps } = opts;
65
65
  if (!item.box || box.isUnresolvable(item.box)) return;
66
66
  if (!item.data) return;
67
- if (item.type === "cva-call" || item.type === "tokenVar") return;
67
+ if (item.type === "cva-call" || item.type === "tokenValue") return;
68
68
  const componentReportItem = {
69
69
  componentIndex: String(componentIndex++),
70
70
  componentName: item.name,
@@ -962,10 +962,10 @@ var ParserResult = class {
962
962
  if (unresolved.length) this.unresolved.push(...unresolved);
963
963
  }
964
964
  /**
965
- * `kind` separates `token()` from `token.var()`, which resolve to the value and to the
966
- * variable reference respectively. They share this set deliberately: everything that reads
967
- * a result for the token *path* — `collectTokenReferences`, keeping a declaration alive
968
- * through pruning — wants both, and only the fold cares which half was asked for.
965
+ * `kind` separates the variable reference — `token()` and its `token.var()` alias — from
966
+ * `token.value()`, the resolved literal. They share this set deliberately: everything that
967
+ * reads a result for the token *path* — `collectTokenReferences`, keeping a declaration
968
+ * alive through pruning — wants both, and only the fold cares which half was asked for.
969
969
  */
970
970
  setToken(result, kind = "token") {
971
971
  this.token.add(this.append(Object.assign({ type: kind }, result)));
@@ -1107,7 +1107,7 @@ function createParser(context) {
1107
1107
  ast: sourceFile,
1108
1108
  tokens: context.tokens ? {
1109
1109
  view: context.tokens.view,
1110
- isTokenFn: (fnName) => file.isTokenAlias(fnName)
1110
+ isTokenFn: (fnName) => file.isTokenFn(fnName)
1111
1111
  } : void 0,
1112
1112
  components: jsx.isEnabled ? {
1113
1113
  matchTag: (prop) => {
@@ -1170,13 +1170,14 @@ function createParser(context) {
1170
1170
  });
1171
1171
  return;
1172
1172
  }
1173
- if (file.isTokenVarFn(alias)) {
1173
+ const tokenMethod = file.tokenMethod(alias);
1174
+ if (tokenMethod) {
1174
1175
  result.queryList.forEach((query) => {
1175
1176
  if (query.kind === "call-expression") parserResult.setToken({
1176
- name: "token.var",
1177
+ name: `token.${tokenMethod}`,
1177
1178
  box: query.box.value[0] ?? box.fallback(query.box),
1178
1179
  data: combineResult(unbox(query.box.value[0]))
1179
- }, "tokenVar");
1180
+ }, tokenMethod === "value" ? "tokenValue" : "token");
1180
1181
  });
1181
1182
  return;
1182
1183
  }
@@ -1275,6 +1276,31 @@ const createTsProject = (options) => new Project$1({
1275
1276
  ...normalizeCompilerOptions(options.compilerOptions)
1276
1277
  }
1277
1278
  });
1279
+ /**
1280
+ * How to parse a file, decided by its extension.
1281
+ *
1282
+ * Everything used to be `TSX`, which is not a superset of `TS`: the two disagree on exactly
1283
+ * the constructs where `<` is ambiguous. Under `TSX` a generic arrow `<T>(x: T) => x` and an
1284
+ * old-style assertion `<HTMLElement>node` parse as a *JSX element*, which then swallows the
1285
+ * rest of the file into its children. The file still reads fine and the bytes are unchanged;
1286
+ * the tree is simply wrong, and every `css()` call below the offending line stops existing as
1287
+ * far as extraction is concerned. It reports as styles that silently never got emitted.
1288
+ *
1289
+ * Only `.ts` moves. A `.ts` file cannot legally contain JSX — TypeScript requires `.tsx` for
1290
+ * that — so parsing one as `TSX` can only ever mis-parse, never accept something real.
1291
+ *
1292
+ * Everything else stays `TSX` deliberately:
1293
+ *
1294
+ * - `.js` and `.jsx` routinely carry JSX in projects that never adopted TypeScript, and `TSX`
1295
+ * accepts the type syntax they do not use anyway.
1296
+ * - a single-file component is stored under its own extension after `parser:before` rewrites
1297
+ * it to tsx, so `.vue` and `.svelte` have to keep parsing as tsx.
1298
+ * - an unknown extension is somebody's template that a hook may have compiled to jsx.
1299
+ */
1300
+ const scriptKindFor = (filePath) => {
1301
+ const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
1302
+ return extension === ".ts" || extension === ".mts" || extension === ".cts" ? ScriptKind.TS : ScriptKind.TSX;
1303
+ };
1278
1304
  var Project = class {
1279
1305
  options;
1280
1306
  project;
@@ -1420,7 +1446,7 @@ var Project = class {
1420
1446
  this.invalidate();
1421
1447
  return this.project.createSourceFile(filePath, readFile(filePath), {
1422
1448
  overwrite: true,
1423
- scriptKind: ScriptKind.TSX
1449
+ scriptKind: scriptKindFor(filePath)
1424
1450
  });
1425
1451
  };
1426
1452
  createSourceFiles = () => {
@@ -1431,7 +1457,7 @@ var Project = class {
1431
1457
  this.invalidate(!(filePath.includes("/") && this.project.getSourceFile(filePath)));
1432
1458
  return this.project.createSourceFile(filePath, content, {
1433
1459
  overwrite: true,
1434
- scriptKind: ScriptKind.TSX
1460
+ scriptKind: scriptKindFor(filePath)
1435
1461
  });
1436
1462
  };
1437
1463
  removeSourceFile = (filePath) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/parser",
3
- "version": "1.28.1",
3
+ "version": "1.29.0",
4
4
  "description": "The static parser for bamboo css",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -34,17 +34,17 @@
34
34
  "dependencies": {
35
35
  "ts-morph": "28.0.0",
36
36
  "ts-pattern": "5.9.0",
37
- "@bamboocss/extractor": "1.28.1",
38
- "@bamboocss/core": "^1.28.1",
39
- "@bamboocss/config": "^1.28.1",
40
- "@bamboocss/logger": "1.28.1",
41
- "@bamboocss/shared": "1.28.1",
42
- "@bamboocss/types": "1.28.1"
37
+ "@bamboocss/config": "^1.29.0",
38
+ "@bamboocss/extractor": "1.29.0",
39
+ "@bamboocss/logger": "1.29.0",
40
+ "@bamboocss/shared": "1.29.0",
41
+ "@bamboocss/core": "^1.29.0",
42
+ "@bamboocss/types": "1.29.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@bamboocss/generator": "1.28.1",
46
- "@bamboocss/plugin-svelte": "1.28.1",
47
- "@bamboocss/plugin-vue": "1.28.1"
45
+ "@bamboocss/generator": "1.29.0",
46
+ "@bamboocss/plugin-svelte": "1.29.0",
47
+ "@bamboocss/plugin-vue": "1.29.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsdown src/index.ts --format=esm,cjs --dts",