@lingo.dev/_compiler 0.2.0 → 0.2.2

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.
Files changed (3) hide show
  1. package/build/index.cjs +184 -153
  2. package/build/index.mjs +181 -150
  3. package/package.json +1 -1
package/build/index.mjs CHANGED
@@ -4,7 +4,7 @@ import { createUnplugin } from "unplugin";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "@lingo.dev/_compiler",
7
- version: "0.2.0",
7
+ version: "0.2.2",
8
8
  description: "Lingo.dev Compiler",
9
9
  private: false,
10
10
  publishConfig: {
@@ -174,9 +174,9 @@ function extractAttributeValue(attribute) {
174
174
  function getJsxRoots(node) {
175
175
  const result = [];
176
176
  traverse(node, {
177
- JSXElement(path6) {
178
- result.push(path6);
179
- path6.skip();
177
+ JSXElement(path7) {
178
+ result.push(path7);
179
+ path7.skip();
180
180
  }
181
181
  });
182
182
  return result;
@@ -203,14 +203,14 @@ function getOrCreateImport(ast, params) {
203
203
  function findExistingImport(ast, exportedName, moduleName) {
204
204
  let result = null;
205
205
  traverse(ast, {
206
- ImportDeclaration(path6) {
207
- if (path6.node.source.value !== moduleName) {
206
+ ImportDeclaration(path7) {
207
+ if (path7.node.source.value !== moduleName) {
208
208
  return;
209
209
  }
210
- for (const specifier of path6.node.specifiers) {
210
+ for (const specifier of path7.node.specifiers) {
211
211
  if (t2.isImportSpecifier(specifier) && (t2.isIdentifier(specifier.imported) && specifier.imported.name === exportedName || specifier.importKind === "value" && t2.isIdentifier(specifier.local) && specifier.local.name === exportedName)) {
212
212
  result = specifier.local.name;
213
- path6.stop();
213
+ path7.stop();
214
214
  return;
215
215
  }
216
216
  }
@@ -221,8 +221,8 @@ function findExistingImport(ast, exportedName, moduleName) {
221
221
  function generateUniqueImportName(ast, baseName) {
222
222
  const usedNames = /* @__PURE__ */ new Set();
223
223
  traverse(ast, {
224
- Identifier(path6) {
225
- usedNames.add(path6.node.name);
224
+ Identifier(path7) {
225
+ usedNames.add(path7.node.name);
226
226
  }
227
227
  });
228
228
  if (!usedNames.has(baseName)) {
@@ -238,12 +238,12 @@ function generateUniqueImportName(ast, baseName) {
238
238
  }
239
239
  function createImportDeclaration(ast, localName, exportedName, moduleName) {
240
240
  traverse(ast, {
241
- Program(path6) {
241
+ Program(path7) {
242
242
  const importSpecifier2 = t2.importSpecifier(
243
243
  t2.identifier(localName),
244
244
  t2.identifier(exportedName)
245
245
  );
246
- const existingImport = path6.get("body").find(
246
+ const existingImport = path7.get("body").find(
247
247
  (nodePath) => t2.isImportDeclaration(nodePath.node) && nodePath.node.source.value === moduleName
248
248
  );
249
249
  if (existingImport && t2.isImportDeclaration(existingImport.node)) {
@@ -253,10 +253,10 @@ function createImportDeclaration(ast, localName, exportedName, moduleName) {
253
253
  [importSpecifier2],
254
254
  t2.stringLiteral(moduleName)
255
255
  );
256
- const lastImportIndex = findLastImportIndex(path6);
257
- path6.node.body.splice(lastImportIndex + 1, 0, importDeclaration2);
256
+ const lastImportIndex = findLastImportIndex(path7);
257
+ path7.node.body.splice(lastImportIndex + 1, 0, importDeclaration2);
258
258
  }
259
- path6.stop();
259
+ path7.stop();
260
260
  }
261
261
  });
262
262
  }
@@ -272,10 +272,10 @@ function findLastImportIndex(programPath) {
272
272
  function _hasFileDirective(ast, directiveValue) {
273
273
  let hasDirective = false;
274
274
  traverse(ast, {
275
- Directive(path6) {
276
- if (path6.node.value.value === directiveValue) {
275
+ Directive(path7) {
276
+ if (path7.node.value.value === directiveValue) {
277
277
  hasDirective = true;
278
- path6.stop();
278
+ path7.stop();
279
279
  }
280
280
  }
281
281
  });
@@ -325,9 +325,9 @@ function getJsxElementName(nodePath) {
325
325
  function getNestedJsxElements(nodePath) {
326
326
  const nestedElements = [];
327
327
  nodePath.traverse({
328
- JSXElement(path6) {
329
- if (path6.node !== nodePath.node) {
330
- nestedElements.push(path6.node);
328
+ JSXElement(path7) {
329
+ if (path7.node !== nodePath.node) {
330
+ nestedElements.push(path7.node);
331
331
  }
332
332
  }
333
333
  });
@@ -350,8 +350,8 @@ var LCP_DICTIONARY_FILE_NAME = "dictionary.js";
350
350
  // src/jsx-provider.ts
351
351
  var jsxProviderMutation = createCodeMutation((payload) => {
352
352
  traverse2(payload.ast, {
353
- JSXElement: (path6) => {
354
- if (getJsxElementName(path6)?.toLowerCase() === "html") {
353
+ JSXElement: (path7) => {
354
+ if (getJsxElementName(path7)?.toLowerCase() === "html") {
355
355
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
356
356
  if (mode === "client") {
357
357
  return;
@@ -385,11 +385,11 @@ var jsxProviderMutation = createCodeMutation((payload) => {
385
385
  t4.jsxClosingElement(
386
386
  t4.jsxIdentifier(lingoProviderImport.importedName)
387
387
  ),
388
- [path6.node],
388
+ [path7.node],
389
389
  false
390
390
  );
391
- path6.replaceWith(provider);
392
- path6.skip();
391
+ path7.replaceWith(provider);
392
+ path7.skip();
393
393
  }
394
394
  }
395
395
  });
@@ -438,10 +438,10 @@ import traverse4 from "@babel/traverse";
438
438
  function collectJsxScopes(ast) {
439
439
  const jsxScopes = [];
440
440
  traverse4(ast, {
441
- JSXElement: (path6) => {
442
- if (!hasJsxScopeAttribute(path6)) return;
443
- path6.skip();
444
- jsxScopes.push(path6);
441
+ JSXElement: (path7) => {
442
+ if (!hasJsxScopeAttribute(path7)) return;
443
+ path7.skip();
444
+ jsxScopes.push(path7);
445
445
  }
446
446
  });
447
447
  return jsxScopes;
@@ -449,32 +449,32 @@ function collectJsxScopes(ast) {
449
449
  function getJsxScopes(node) {
450
450
  const result = [];
451
451
  traverse4(node, {
452
- JSXElement(path6) {
453
- if (getJsxElementName(path6) === "LingoProvider") {
452
+ JSXElement(path7) {
453
+ if (getJsxElementName(path7) === "LingoProvider") {
454
454
  return;
455
455
  }
456
- const hasNonEmptyTextSiblings = path6.getAllPrevSiblings().concat(path6.getAllNextSiblings()).some(
456
+ const hasNonEmptyTextSiblings = path7.getAllPrevSiblings().concat(path7.getAllNextSiblings()).some(
457
457
  (sibling) => t7.isJSXText(sibling.node) && sibling.node.value?.trim() !== ""
458
458
  );
459
459
  if (hasNonEmptyTextSiblings) {
460
460
  return;
461
461
  }
462
- const hasNonEmptyTextChild = path6.get("children").some(
462
+ const hasNonEmptyTextChild = path7.get("children").some(
463
463
  (child) => t7.isJSXText(child.node) && child.node.value?.trim() !== ""
464
464
  );
465
465
  if (hasNonEmptyTextChild) {
466
- result.push(path6);
467
- path6.skip();
466
+ result.push(path7);
467
+ path7.skip();
468
468
  }
469
469
  }
470
470
  });
471
471
  return result;
472
472
  }
473
- function hasJsxScopeAttribute(path6) {
474
- return !!getJsxScopeAttribute(path6);
473
+ function hasJsxScopeAttribute(path7) {
474
+ return !!getJsxScopeAttribute(path7);
475
475
  }
476
- function getJsxScopeAttribute(path6) {
477
- const attribute = path6.node.openingElement.attributes.find(
476
+ function getJsxScopeAttribute(path7) {
477
+ const attribute = path7.node.openingElement.attributes.find(
478
478
  (attr) => attr.type === "JSXAttribute" && attr.name.name === "data-jsx-scope"
479
479
  );
480
480
  return attribute && t7.isJSXAttribute(attribute) && t7.isStringLiteral(attribute.value) ? attribute.value.value : void 0;
@@ -506,11 +506,11 @@ import traverse5 from "@babel/traverse";
506
506
  function collectJsxAttributeScopes(node) {
507
507
  const result = [];
508
508
  traverse5(node, {
509
- JSXElement(path6) {
510
- if (!hasJsxAttributeScopeAttribute(path6)) return;
511
- const localizableAttributes = getJsxAttributeScopeAttribute(path6);
509
+ JSXElement(path7) {
510
+ if (!hasJsxAttributeScopeAttribute(path7)) return;
511
+ const localizableAttributes = getJsxAttributeScopeAttribute(path7);
512
512
  if (!localizableAttributes) return;
513
- result.push([path6, localizableAttributes]);
513
+ result.push([path7, localizableAttributes]);
514
514
  }
515
515
  });
516
516
  return result;
@@ -529,8 +529,8 @@ function getJsxAttributeScopes(node) {
529
529
  "subtitle"
530
530
  ];
531
531
  traverse5(node, {
532
- JSXElement(path6) {
533
- const openingElement = path6.node.openingElement;
532
+ JSXElement(path7) {
533
+ const openingElement = path7.node.openingElement;
534
534
  const elementName = openingElement.name;
535
535
  if (!t9.isJSXIdentifier(elementName) || !elementName.name) {
536
536
  return;
@@ -551,17 +551,17 @@ function getJsxAttributeScopes(node) {
551
551
  }
552
552
  ).map((attr) => attr.name.name);
553
553
  if (localizableAttrs.length > 0) {
554
- result.push([path6, localizableAttrs]);
554
+ result.push([path7, localizableAttrs]);
555
555
  }
556
556
  }
557
557
  });
558
558
  return result;
559
559
  }
560
- function hasJsxAttributeScopeAttribute(path6) {
561
- return !!getJsxAttributeScopeAttribute(path6);
560
+ function hasJsxAttributeScopeAttribute(path7) {
561
+ return !!getJsxAttributeScopeAttribute(path7);
562
562
  }
563
- function getJsxAttributeScopeAttribute(path6) {
564
- const attribute = path6.node.openingElement.attributes.find(
563
+ function getJsxAttributeScopeAttribute(path7) {
564
+ const attribute = path7.node.openingElement.attributes.find(
565
565
  (attr) => attr.type === "JSXAttribute" && attr.name.name === "data-jsx-attribute-scope"
566
566
  );
567
567
  if (!attribute || !t9.isJSXAttribute(attribute)) {
@@ -604,7 +604,7 @@ var jsxAttributeFlagMutation = createCodeMutation(
604
604
  var jsx_attribute_flag_default = jsxAttributeFlagMutation;
605
605
 
606
606
  // src/index.ts
607
- import path5 from "path";
607
+ import path6 from "path";
608
608
 
609
609
  // src/utils/module-params.ts
610
610
  function parseParametrizedModuleId(rawId) {
@@ -1155,10 +1155,19 @@ function getRc() {
1155
1155
  // src/utils/llm-api-key.ts
1156
1156
  import _5 from "lodash";
1157
1157
  import * as dotenv from "dotenv";
1158
+ import path4 from "path";
1158
1159
  function getKeyFromEnv(envVarName) {
1159
- const ephemeralEnv = {};
1160
- dotenv.config({ processEnv: ephemeralEnv });
1161
- return ephemeralEnv[envVarName];
1160
+ if (process.env[envVarName]) {
1161
+ return process.env[envVarName];
1162
+ }
1163
+ const result = dotenv.config({
1164
+ path: [
1165
+ path4.resolve(process.cwd(), ".env"),
1166
+ path4.resolve(process.cwd(), ".env.local"),
1167
+ path4.resolve(process.cwd(), ".env.development")
1168
+ ]
1169
+ });
1170
+ return result?.parsed?.[envVarName];
1162
1171
  }
1163
1172
  function getKeyFromRc(rcPath) {
1164
1173
  const rc = getRc();
@@ -1721,10 +1730,10 @@ import traverse6 from "@babel/traverse";
1721
1730
  function findInvokations(ast, params) {
1722
1731
  const result = [];
1723
1732
  traverse6(ast, {
1724
- ImportDeclaration(path6) {
1725
- if (path6.node.source.value !== params.moduleName) return;
1733
+ ImportDeclaration(path7) {
1734
+ if (path7.node.source.value !== params.moduleName) return;
1726
1735
  const importNames = /* @__PURE__ */ new Map();
1727
- const specifiers = path6.node.specifiers;
1736
+ const specifiers = path7.node.specifiers;
1728
1737
  specifiers.forEach((specifier) => {
1729
1738
  if (t11.isImportSpecifier(specifier) && t11.isIdentifier(specifier.imported) && specifier.imported.name === params.functionName) {
1730
1739
  importNames.set(specifier.local.name, true);
@@ -1734,13 +1743,13 @@ function findInvokations(ast, params) {
1734
1743
  importNames.set(specifier.local.name, "namespace");
1735
1744
  }
1736
1745
  });
1737
- collectCallExpressions(path6, importNames, result, params.functionName);
1746
+ collectCallExpressions(path7, importNames, result, params.functionName);
1738
1747
  }
1739
1748
  });
1740
1749
  return result;
1741
1750
  }
1742
- function collectCallExpressions(path6, importNames, result, functionName) {
1743
- const program = path6.findParent(
1751
+ function collectCallExpressions(path7, importNames, result, functionName) {
1752
+ const program = path7.findParent(
1744
1753
  (p) => p.isProgram()
1745
1754
  );
1746
1755
  if (!program) return;
@@ -1758,6 +1767,17 @@ function collectCallExpressions(path6, importNames, result, functionName) {
1758
1767
 
1759
1768
  // src/rsc-dictionary-loader.ts
1760
1769
  import * as t12 from "@babel/types";
1770
+
1771
+ // src/_utils.ts
1772
+ import path5 from "path";
1773
+ var getDictionaryPath = (params) => {
1774
+ return path5.relative(
1775
+ params.relativeFilePath,
1776
+ path5.resolve(params.sourceRoot, params.lingoDir, LCP_DICTIONARY_FILE_NAME)
1777
+ );
1778
+ };
1779
+
1780
+ // src/rsc-dictionary-loader.ts
1761
1781
  var rscDictionaryLoaderMutation = createCodeMutation((payload) => {
1762
1782
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
1763
1783
  if (mode === "client") {
@@ -1778,6 +1798,11 @@ var rscDictionaryLoaderMutation = createCodeMutation((payload) => {
1778
1798
  if (t12.isIdentifier(invokation.callee)) {
1779
1799
  invokation.callee.name = internalDictionaryLoader.importedName;
1780
1800
  }
1801
+ const dictionaryPath = getDictionaryPath({
1802
+ sourceRoot: payload.params.sourceRoot,
1803
+ lingoDir: payload.params.lingoDir,
1804
+ relativeFilePath: payload.relativeFilePath
1805
+ });
1781
1806
  const localeImportMap = t12.objectExpression(
1782
1807
  allLocales.map(
1783
1808
  (locale) => t12.objectProperty(
@@ -1785,9 +1810,7 @@ var rscDictionaryLoaderMutation = createCodeMutation((payload) => {
1785
1810
  t12.arrowFunctionExpression(
1786
1811
  [],
1787
1812
  t12.callExpression(t12.identifier("import"), [
1788
- t12.stringLiteral(
1789
- `@/${payload.params.lingoDir}/${LCP_DICTIONARY_FILE_NAME}?locale=${locale}`
1790
- )
1813
+ t12.stringLiteral(`${dictionaryPath}?locale=${locale}`)
1791
1814
  ])
1792
1815
  )
1793
1816
  )
@@ -1821,6 +1844,11 @@ var reactRouterDictionaryLoaderMutation = createCodeMutation(
1821
1844
  if (t13.isIdentifier(invokation.callee)) {
1822
1845
  invokation.callee.name = internalDictionaryLoader.importedName;
1823
1846
  }
1847
+ const dictionaryPath = getDictionaryPath({
1848
+ sourceRoot: payload.params.sourceRoot,
1849
+ lingoDir: payload.params.lingoDir,
1850
+ relativeFilePath: payload.relativeFilePath
1851
+ });
1824
1852
  const localeImportMap = t13.objectExpression(
1825
1853
  allLocales.map(
1826
1854
  (locale) => t13.objectProperty(
@@ -1828,9 +1856,7 @@ var reactRouterDictionaryLoaderMutation = createCodeMutation(
1828
1856
  t13.arrowFunctionExpression(
1829
1857
  [],
1830
1858
  t13.callExpression(t13.identifier("import"), [
1831
- t13.stringLiteral(
1832
- `~/${payload.params.lingoDir}/${LCP_DICTIONARY_FILE_NAME}?locale=${locale}`
1833
- )
1859
+ t13.stringLiteral(`${dictionaryPath}?locale=${locale}`)
1834
1860
  ])
1835
1861
  )
1836
1862
  )
@@ -1850,18 +1876,18 @@ function jsxFragmentMutation(payload) {
1850
1876
  let foundFragments = false;
1851
1877
  let fragmentImportName = null;
1852
1878
  traverse7(ast, {
1853
- ImportDeclaration(path6) {
1854
- if (path6.node.source.value !== "react") return;
1855
- for (const specifier of path6.node.specifiers) {
1879
+ ImportDeclaration(path7) {
1880
+ if (path7.node.source.value !== "react") return;
1881
+ for (const specifier of path7.node.specifiers) {
1856
1882
  if (t14.isImportSpecifier(specifier) && t14.isIdentifier(specifier.imported) && specifier.imported.name === "Fragment") {
1857
1883
  fragmentImportName = specifier.local.name;
1858
- path6.stop();
1884
+ path7.stop();
1859
1885
  }
1860
1886
  }
1861
1887
  }
1862
1888
  });
1863
1889
  traverse7(ast, {
1864
- JSXFragment(path6) {
1890
+ JSXFragment(path7) {
1865
1891
  foundFragments = true;
1866
1892
  if (!fragmentImportName) {
1867
1893
  const result = getOrCreateImport(ast, {
@@ -1873,10 +1899,10 @@ function jsxFragmentMutation(payload) {
1873
1899
  const fragmentElement = t14.jsxElement(
1874
1900
  t14.jsxOpeningElement(t14.jsxIdentifier(fragmentImportName), [], false),
1875
1901
  t14.jsxClosingElement(t14.jsxIdentifier(fragmentImportName)),
1876
- path6.node.children,
1902
+ path7.node.children,
1877
1903
  false
1878
1904
  );
1879
- path6.replaceWith(fragmentElement);
1905
+ path7.replaceWith(fragmentElement);
1880
1906
  }
1881
1907
  });
1882
1908
  return payload;
@@ -1887,23 +1913,23 @@ import traverse8 from "@babel/traverse";
1887
1913
  import * as t15 from "@babel/types";
1888
1914
  var jsxHtmlLangMutation = createCodeMutation((payload) => {
1889
1915
  traverse8(payload.ast, {
1890
- JSXElement: (path6) => {
1891
- if (getJsxElementName(path6)?.toLowerCase() === "html") {
1916
+ JSXElement: (path7) => {
1917
+ if (getJsxElementName(path7)?.toLowerCase() === "html") {
1892
1918
  const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
1893
1919
  const packagePath = mode === "client" ? "lingo.dev/react/client" /* ReactClient */ : "lingo.dev/react/rsc" /* ReactRSC */;
1894
1920
  const lingoHtmlComponentImport = getOrCreateImport(payload.ast, {
1895
1921
  moduleName: packagePath,
1896
1922
  exportedName: "LingoHtmlComponent"
1897
1923
  });
1898
- path6.node.openingElement.name = t15.jsxIdentifier(
1924
+ path7.node.openingElement.name = t15.jsxIdentifier(
1899
1925
  lingoHtmlComponentImport.importedName
1900
1926
  );
1901
- if (path6.node.closingElement) {
1902
- path6.node.closingElement.name = t15.jsxIdentifier(
1927
+ if (path7.node.closingElement) {
1928
+ path7.node.closingElement.name = t15.jsxIdentifier(
1903
1929
  lingoHtmlComponentImport.importedName
1904
1930
  );
1905
1931
  }
1906
- path6.skip();
1932
+ path7.skip();
1907
1933
  }
1908
1934
  }
1909
1935
  });
@@ -1942,18 +1968,22 @@ function jsxAttributeScopesExportMutation(payload) {
1942
1968
  for (const [scope, attributes] of attributeScopes) {
1943
1969
  for (const attributeDefinition of attributes) {
1944
1970
  const [attribute, scopeKey] = attributeDefinition.split(":");
1945
- lcp.resetScope(payload.fileKey, scopeKey);
1971
+ lcp.resetScope(payload.relativeFilePath, scopeKey);
1946
1972
  const attributeValue = getJsxAttributeValue(scope, attribute);
1947
1973
  if (!attributeValue) {
1948
1974
  continue;
1949
1975
  }
1950
- lcp.setScopeType(payload.fileKey, scopeKey, "attribute");
1976
+ lcp.setScopeType(payload.relativeFilePath, scopeKey, "attribute");
1951
1977
  const hash = getJsxAttributeValueHash(String(attributeValue));
1952
- lcp.setScopeHash(payload.fileKey, scopeKey, hash);
1953
- lcp.setScopeContext(payload.fileKey, scopeKey, "");
1954
- lcp.setScopeSkip(payload.fileKey, scopeKey, false);
1955
- lcp.setScopeOverrides(payload.fileKey, scopeKey, {});
1956
- lcp.setScopeContent(payload.fileKey, scopeKey, String(attributeValue));
1978
+ lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);
1979
+ lcp.setScopeContext(payload.relativeFilePath, scopeKey, "");
1980
+ lcp.setScopeSkip(payload.relativeFilePath, scopeKey, false);
1981
+ lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, {});
1982
+ lcp.setScopeContent(
1983
+ payload.relativeFilePath,
1984
+ scopeKey,
1985
+ String(attributeValue)
1986
+ );
1957
1987
  }
1958
1988
  }
1959
1989
  lcp.save();
@@ -1970,22 +2000,22 @@ var WHITESPACE_PLACEHOLDER = "[lingo-whitespace-placeholder]";
1970
2000
  function extractJsxContent(nodePath, replaceWhitespacePlaceholders = true) {
1971
2001
  const chunks = [];
1972
2002
  nodePath.traverse({
1973
- JSXElement(path6) {
1974
- if (path6.parent === nodePath.node) {
1975
- const content = extractJsxContent(path6, false);
1976
- const name = getJsxElementName(path6);
2003
+ JSXElement(path7) {
2004
+ if (path7.parent === nodePath.node) {
2005
+ const content = extractJsxContent(path7, false);
2006
+ const name = getJsxElementName(path7);
1977
2007
  chunks.push(`<element:${name}>${content}</element:${name}>`);
1978
- path6.skip();
2008
+ path7.skip();
1979
2009
  }
1980
2010
  },
1981
- JSXText(path6) {
1982
- chunks.push(path6.node.value);
2011
+ JSXText(path7) {
2012
+ chunks.push(path7.node.value);
1983
2013
  },
1984
- JSXExpressionContainer(path6) {
1985
- if (path6.parent !== nodePath.node) {
2014
+ JSXExpressionContainer(path7) {
2015
+ if (path7.parent !== nodePath.node) {
1986
2016
  return;
1987
2017
  }
1988
- const expr = path6.node.expression;
2018
+ const expr = path7.node.expression;
1989
2019
  if (t16.isCallExpression(expr)) {
1990
2020
  let key = "";
1991
2021
  if (t16.isIdentifier(expr.callee)) {
@@ -2031,12 +2061,12 @@ function extractJsxContent(nodePath, replaceWhitespacePlaceholders = true) {
2031
2061
  parts.unshift(current.name);
2032
2062
  chunks.push(`{${parts.join(".").replaceAll(".[", "[")}}`);
2033
2063
  }
2034
- } else if (isWhitespace(path6)) {
2064
+ } else if (isWhitespace(path7)) {
2035
2065
  chunks.push(WHITESPACE_PLACEHOLDER);
2036
- } else if (isExpression2(path6)) {
2066
+ } else if (isExpression2(path7)) {
2037
2067
  chunks.push("<expression/>");
2038
2068
  }
2039
- path6.skip();
2069
+ path7.skip();
2040
2070
  }
2041
2071
  });
2042
2072
  const result = chunks.join("");
@@ -2084,21 +2114,29 @@ function jsxScopesExportMutation(payload) {
2084
2114
  });
2085
2115
  for (const scope of scopes) {
2086
2116
  const scopeKey = getAstKey(scope);
2087
- lcp.resetScope(payload.fileKey, scopeKey);
2088
- lcp.setScopeType(payload.fileKey, scopeKey, "element");
2117
+ lcp.resetScope(payload.relativeFilePath, scopeKey);
2118
+ lcp.setScopeType(payload.relativeFilePath, scopeKey, "element");
2089
2119
  const hash = getJsxElementHash(scope);
2090
- lcp.setScopeHash(payload.fileKey, scopeKey, hash);
2120
+ lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);
2091
2121
  const context = getJsxAttributeValue(scope, "data-lingo-context");
2092
- lcp.setScopeContext(payload.fileKey, scopeKey, String(context || ""));
2122
+ lcp.setScopeContext(
2123
+ payload.relativeFilePath,
2124
+ scopeKey,
2125
+ String(context || "")
2126
+ );
2093
2127
  const skip = getJsxAttributeValue(scope, "data-lingo-skip");
2094
- lcp.setScopeSkip(payload.fileKey, scopeKey, Boolean(skip || false));
2128
+ lcp.setScopeSkip(
2129
+ payload.relativeFilePath,
2130
+ scopeKey,
2131
+ Boolean(skip || false)
2132
+ );
2095
2133
  const attributesMap = getJsxAttributesMap(scope);
2096
2134
  const overrides = _10.chain(attributesMap).entries().filter(
2097
2135
  ([attributeKey]) => attributeKey.startsWith("data-lingo-override-")
2098
2136
  ).map(([k, v]) => [k.split("data-lingo-override-")[1], v]).filter(([k]) => !!k).filter(([, v]) => !!v).fromPairs().value();
2099
- lcp.setScopeOverrides(payload.fileKey, scopeKey, overrides);
2137
+ lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, overrides);
2100
2138
  const content = extractJsxContent(scope);
2101
- lcp.setScopeContent(payload.fileKey, scopeKey, content);
2139
+ lcp.setScopeContent(payload.relativeFilePath, scopeKey, content);
2102
2140
  }
2103
2141
  lcp.save();
2104
2142
  return payload;
@@ -2135,7 +2173,7 @@ var lingoJsxAttributeScopeInjectMutation = createCodeMutation(
2135
2173
  jsxScope.node.openingElement.attributes.push(
2136
2174
  t17.jsxAttribute(
2137
2175
  t17.jsxIdentifier("$fileKey"),
2138
- t17.stringLiteral(payload.fileKey)
2176
+ t17.stringLiteral(payload.relativeFilePath)
2139
2177
  )
2140
2178
  );
2141
2179
  jsxScope.node.openingElement.attributes.push(
@@ -2187,14 +2225,14 @@ import * as t18 from "@babel/types";
2187
2225
  var getJsxVariables = (nodePath) => {
2188
2226
  const variables = /* @__PURE__ */ new Set();
2189
2227
  nodePath.traverse({
2190
- JSXOpeningElement(path6) {
2191
- path6.skip();
2228
+ JSXOpeningElement(path7) {
2229
+ path7.skip();
2192
2230
  },
2193
- JSXExpressionContainer(path6) {
2194
- if (t18.isIdentifier(path6.node.expression)) {
2195
- variables.add(path6.node.expression.name);
2196
- } else if (t18.isMemberExpression(path6.node.expression)) {
2197
- let current = path6.node.expression;
2231
+ JSXExpressionContainer(path7) {
2232
+ if (t18.isIdentifier(path7.node.expression)) {
2233
+ variables.add(path7.node.expression.name);
2234
+ } else if (t18.isMemberExpression(path7.node.expression)) {
2235
+ let current = path7.node.expression;
2198
2236
  const parts = [];
2199
2237
  while (t18.isMemberExpression(current)) {
2200
2238
  if (t18.isIdentifier(current.property)) {
@@ -2211,7 +2249,7 @@ var getJsxVariables = (nodePath) => {
2211
2249
  variables.add(parts.join(".").replaceAll(".[", "["));
2212
2250
  }
2213
2251
  }
2214
- path6.skip();
2252
+ path7.skip();
2215
2253
  }
2216
2254
  });
2217
2255
  const properties = Array.from(variables).map(
@@ -2227,16 +2265,16 @@ var getJsxFunctions = (nodePath) => {
2227
2265
  const functions = /* @__PURE__ */ new Map();
2228
2266
  let fnCounter = 0;
2229
2267
  nodePath.traverse({
2230
- JSXOpeningElement(path6) {
2231
- path6.skip();
2268
+ JSXOpeningElement(path7) {
2269
+ path7.skip();
2232
2270
  },
2233
- JSXExpressionContainer(path6) {
2234
- if (t19.isCallExpression(path6.node.expression)) {
2271
+ JSXExpressionContainer(path7) {
2272
+ if (t19.isCallExpression(path7.node.expression)) {
2235
2273
  let key = "";
2236
- if (t19.isIdentifier(path6.node.expression.callee)) {
2237
- key = `${path6.node.expression.callee.name}`;
2238
- } else if (t19.isMemberExpression(path6.node.expression.callee)) {
2239
- let firstCallee = path6.node.expression.callee;
2274
+ if (t19.isIdentifier(path7.node.expression.callee)) {
2275
+ key = `${path7.node.expression.callee.name}`;
2276
+ } else if (t19.isMemberExpression(path7.node.expression.callee)) {
2277
+ let firstCallee = path7.node.expression.callee;
2240
2278
  while (t19.isMemberExpression(firstCallee) && t19.isCallExpression(firstCallee.object)) {
2241
2279
  firstCallee = firstCallee.object.callee;
2242
2280
  }
@@ -2257,10 +2295,10 @@ var getJsxFunctions = (nodePath) => {
2257
2295
  key = parts.join(".");
2258
2296
  }
2259
2297
  const existing = functions.get(key) ?? [];
2260
- functions.set(key, [...existing, path6.node.expression]);
2298
+ functions.set(key, [...existing, path7.node.expression]);
2261
2299
  fnCounter++;
2262
2300
  }
2263
- path6.skip();
2301
+ path7.skip();
2264
2302
  }
2265
2303
  });
2266
2304
  const properties = Array.from(functions.entries()).map(
@@ -2274,15 +2312,15 @@ import * as t20 from "@babel/types";
2274
2312
  var getJsxExpressions = (nodePath) => {
2275
2313
  const expressions = [];
2276
2314
  nodePath.traverse({
2277
- JSXOpeningElement(path6) {
2278
- path6.skip();
2315
+ JSXOpeningElement(path7) {
2316
+ path7.skip();
2279
2317
  },
2280
- JSXExpressionContainer(path6) {
2281
- const expr = path6.node.expression;
2318
+ JSXExpressionContainer(path7) {
2319
+ const expr = path7.node.expression;
2282
2320
  if (!t20.isJSXEmptyExpression(expr) && !t20.isIdentifier(expr) && !t20.isMemberExpression(expr) && !t20.isCallExpression(expr) && !(t20.isStringLiteral(expr) && expr.value === " ")) {
2283
2321
  expressions.push(expr);
2284
2322
  }
2285
- path6.skip();
2323
+ path7.skip();
2286
2324
  }
2287
2325
  });
2288
2326
  return t20.arrayExpression(expressions);
@@ -2312,7 +2350,7 @@ var lingoJsxScopeInjectMutation = createCodeMutation((payload) => {
2312
2350
  originalAttributes.push(
2313
2351
  t21.jsxAttribute(
2314
2352
  t21.jsxIdentifier("$fileKey"),
2315
- t21.stringLiteral(payload.fileKey)
2353
+ t21.stringLiteral(payload.relativeFilePath)
2316
2354
  )
2317
2355
  );
2318
2356
  originalAttributes.push(
@@ -2407,8 +2445,8 @@ var jsxRemoveAttributesMutation = createCodeMutation(
2407
2445
  "data-jsx-attribute-scope"
2408
2446
  ];
2409
2447
  traverse9(payload.ast, {
2410
- JSXElement(path6) {
2411
- const openingElement = path6.node.openingElement;
2448
+ JSXElement(path7) {
2449
+ const openingElement = path7.node.openingElement;
2412
2450
  openingElement.attributes = openingElement.attributes.filter((attr) => {
2413
2451
  const removeAttr = t22.isJSXAttribute(attr) && t22.isJSXIdentifier(attr.name) && ATTRIBUTES_TO_REMOVE.includes(attr.name.name);
2414
2452
  return !removeAttr;
@@ -2422,18 +2460,8 @@ var jsxRemoveAttributesMutation = createCodeMutation(
2422
2460
  );
2423
2461
 
2424
2462
  // src/client-dictionary-loader.ts
2425
- import path4 from "path";
2426
2463
  import * as t23 from "@babel/types";
2427
2464
  var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
2428
- const lingoDir = path4.resolve(
2429
- process.cwd(),
2430
- payload.params.sourceRoot,
2431
- payload.params.lingoDir
2432
- );
2433
- const currentDir = path4.dirname(
2434
- path4.resolve(process.cwd(), payload.params.sourceRoot, payload.fileKey)
2435
- );
2436
- const relativeLingoPath = path4.relative(currentDir, lingoDir);
2437
2465
  const invokations = findInvokations(payload.ast, {
2438
2466
  moduleName: "lingo.dev/react/client" /* ReactClient */,
2439
2467
  functionName: "loadDictionary"
@@ -2449,6 +2477,11 @@ var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
2449
2477
  if (t23.isIdentifier(invokation.callee)) {
2450
2478
  invokation.callee.name = internalDictionaryLoader.importedName;
2451
2479
  }
2480
+ const dictionaryPath = getDictionaryPath({
2481
+ sourceRoot: payload.params.sourceRoot,
2482
+ lingoDir: payload.params.lingoDir,
2483
+ relativeFilePath: payload.relativeFilePath
2484
+ });
2452
2485
  const localeImportMap = t23.objectExpression(
2453
2486
  allLocales.map(
2454
2487
  (locale) => t23.objectProperty(
@@ -2456,9 +2489,7 @@ var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
2456
2489
  t23.arrowFunctionExpression(
2457
2490
  [],
2458
2491
  t23.callExpression(t23.identifier("import"), [
2459
- t23.stringLiteral(
2460
- `./${relativeLingoPath}/${LCP_DICTIONARY_FILE_NAME}?locale=${locale}`
2461
- )
2492
+ t23.stringLiteral(`${dictionaryPath}?locale=${locale}`)
2462
2493
  ])
2463
2494
  )
2464
2495
  )
@@ -2543,7 +2574,7 @@ var unplugin = createUnplugin(
2543
2574
  const result = _11.chain({
2544
2575
  code,
2545
2576
  params,
2546
- fileKey: path5.relative(path5.resolve(process.cwd(), params.sourceRoot), id).split(path5.sep).join("/")
2577
+ relativeFilePath: path6.relative(path6.resolve(process.cwd(), params.sourceRoot), id).split(path6.sep).join("/")
2547
2578
  // Always normalize for consistent dictionaries
2548
2579
  }).thru(createPayload).thru(
2549
2580
  composeMutations(
@@ -2614,8 +2645,8 @@ function validateLLMKeyDetails(models) {
2614
2645
  const details = providerDetails[providerId];
2615
2646
  const checkers = keyCheckers[providerId];
2616
2647
  if (!details || !checkers) continue;
2617
- const foundInEnv = checkers.checkEnv() !== void 0;
2618
- const foundInRc = checkers.checkRc() !== void 0;
2648
+ const foundInEnv = !!checkers.checkEnv();
2649
+ const foundInRc = !!checkers.checkRc();
2619
2650
  keyStatuses[providerId] = { foundInEnv, foundInRc, details };
2620
2651
  if (!foundInEnv && !foundInRc) {
2621
2652
  missingProviders.push(providerId);