@gtkx/cli 2.0.0-beta.2 → 2.0.0-beta.3

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 (114) hide show
  1. package/dist/cli.d.ts +1 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +8 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/codegen/reference.d.ts.map +1 -1
  6. package/dist/codegen/reference.js +1 -0
  7. package/dist/codegen/reference.js.map +1 -1
  8. package/dist/codegen/run-codegen.d.ts.map +1 -1
  9. package/dist/codegen/run-codegen.js +2 -8
  10. package/dist/codegen/run-codegen.js.map +1 -1
  11. package/dist/codegen/store-resolver.d.ts +1 -0
  12. package/dist/codegen/store-resolver.d.ts.map +1 -1
  13. package/dist/codegen/store-resolver.js +2 -1
  14. package/dist/codegen/store-resolver.js.map +1 -1
  15. package/dist/commands/dev.d.ts +1 -0
  16. package/dist/commands/dev.d.ts.map +1 -1
  17. package/dist/commands/dev.js +11 -4
  18. package/dist/commands/dev.js.map +1 -1
  19. package/dist/commands/docs.d.ts.map +1 -1
  20. package/dist/commands/docs.js +1 -0
  21. package/dist/commands/docs.js.map +1 -1
  22. package/dist/deploy/freedesktop/validate.d.ts.map +1 -1
  23. package/dist/deploy/freedesktop/validate.js +10 -4
  24. package/dist/deploy/freedesktop/validate.js.map +1 -1
  25. package/dist/deploy/nfpm/config.d.ts +3 -2
  26. package/dist/deploy/nfpm/config.d.ts.map +1 -1
  27. package/dist/deploy/nfpm/config.js +3 -3
  28. package/dist/deploy/nfpm/config.js.map +1 -1
  29. package/dist/deploy/node-runtime/index.d.ts.map +1 -1
  30. package/dist/deploy/node-runtime/index.js +2 -1
  31. package/dist/deploy/node-runtime/index.js.map +1 -1
  32. package/dist/deploy/targets/nfpm-target.d.ts.map +1 -1
  33. package/dist/deploy/targets/nfpm-target.js +12 -7
  34. package/dist/deploy/targets/nfpm-target.js.map +1 -1
  35. package/dist/dev/entry-env.d.ts +2 -1
  36. package/dist/dev/entry-env.d.ts.map +1 -1
  37. package/dist/dev/entry-env.js +2 -1
  38. package/dist/dev/entry-env.js.map +1 -1
  39. package/dist/dev/runner-deps.d.ts +1 -1
  40. package/dist/dev/runner-deps.d.ts.map +1 -1
  41. package/dist/dev/runner-deps.js +3 -3
  42. package/dist/dev/runner-deps.js.map +1 -1
  43. package/dist/dev/runner-main.d.ts.map +1 -1
  44. package/dist/dev/runner-main.js +8 -3
  45. package/dist/dev/runner-main.js.map +1 -1
  46. package/dist/dev/supervisor.d.ts +1 -0
  47. package/dist/dev/supervisor.d.ts.map +1 -1
  48. package/dist/dev/supervisor.js +4 -3
  49. package/dist/dev/supervisor.js.map +1 -1
  50. package/dist/i18n/catalogs.d.ts.map +1 -1
  51. package/dist/i18n/catalogs.js +1 -0
  52. package/dist/i18n/catalogs.js.map +1 -1
  53. package/dist/i18n/source-messages.d.ts.map +1 -1
  54. package/dist/i18n/source-messages.js +154 -36
  55. package/dist/i18n/source-messages.js.map +1 -1
  56. package/dist/internal/build-output.d.ts.map +1 -1
  57. package/dist/internal/build-output.js +12 -2
  58. package/dist/internal/build-output.js.map +1 -1
  59. package/dist/internal/docs-elements.d.ts +1 -0
  60. package/dist/internal/docs-elements.d.ts.map +1 -1
  61. package/dist/internal/docs-elements.js +5 -4
  62. package/dist/internal/docs-elements.js.map +1 -1
  63. package/dist/internal/errors.d.ts +2 -1
  64. package/dist/internal/errors.d.ts.map +1 -1
  65. package/dist/internal/errors.js +1 -1
  66. package/dist/internal/errors.js.map +1 -1
  67. package/dist/internal/parent-process.d.ts +12 -0
  68. package/dist/internal/parent-process.d.ts.map +1 -0
  69. package/dist/internal/parent-process.js +74 -0
  70. package/dist/internal/parent-process.js.map +1 -0
  71. package/dist/vite-plugins/ensure-store.d.ts +1 -1
  72. package/dist/vite-plugins/ensure-store.d.ts.map +1 -1
  73. package/dist/vite-plugins/ensure-store.js +2 -2
  74. package/dist/vite-plugins/ensure-store.js.map +1 -1
  75. package/dist/vite-plugins/i18n.d.ts.map +1 -1
  76. package/dist/vite-plugins/i18n.js +7 -7
  77. package/dist/vite-plugins/i18n.js.map +1 -1
  78. package/dist/vite-plugins/native.d.ts.map +1 -1
  79. package/dist/vite-plugins/native.js +0 -4
  80. package/dist/vite-plugins/native.js.map +1 -1
  81. package/dist/vite-plugins/settings-worker-env.d.ts +1 -1
  82. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  83. package/dist/vite-plugins/settings-worker-env.js +2 -2
  84. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  85. package/dist/vitest-plugin.d.ts +2 -1
  86. package/dist/vitest-plugin.d.ts.map +1 -1
  87. package/dist/vitest-plugin.js +6 -6
  88. package/dist/vitest-plugin.js.map +1 -1
  89. package/package.json +10 -9
  90. package/src/cli.ts +8 -3
  91. package/src/codegen/reference.ts +1 -0
  92. package/src/codegen/run-codegen.ts +2 -12
  93. package/src/codegen/store-resolver.ts +3 -1
  94. package/src/commands/dev.ts +19 -4
  95. package/src/commands/docs.ts +1 -0
  96. package/src/deploy/freedesktop/validate.ts +12 -4
  97. package/src/deploy/nfpm/config.ts +9 -3
  98. package/src/deploy/node-runtime/index.ts +2 -1
  99. package/src/deploy/targets/nfpm-target.ts +13 -6
  100. package/src/dev/entry-env.ts +2 -1
  101. package/src/dev/runner-deps.ts +3 -3
  102. package/src/dev/runner-main.ts +10 -3
  103. package/src/dev/supervisor.ts +6 -3
  104. package/src/i18n/catalogs.ts +1 -0
  105. package/src/i18n/source-messages.ts +223 -40
  106. package/src/internal/build-output.ts +16 -2
  107. package/src/internal/docs-elements.ts +10 -4
  108. package/src/internal/errors.ts +1 -1
  109. package/src/internal/parent-process.ts +110 -0
  110. package/src/vite-plugins/ensure-store.ts +2 -2
  111. package/src/vite-plugins/i18n.ts +8 -11
  112. package/src/vite-plugins/native.ts +0 -5
  113. package/src/vite-plugins/settings-worker-env.ts +2 -2
  114. package/src/vitest-plugin.ts +6 -6
@@ -33,6 +33,62 @@ const STATIC_KEY_WRAPPER_TYPES = new Set([
33
33
  "TSTypeAssertion",
34
34
  "TSNonNullExpression",
35
35
  ]);
36
+ class SourceExtractionError extends Error {
37
+ }
38
+ const sourceErrorMessage = (error) => error instanceof Error ? error.message : String(error);
39
+ const projectSourcePath = (root, path) => {
40
+ const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);
41
+ return toPosixPath(isPathInside(root, absolute) ? relative(root, absolute) : path);
42
+ };
43
+ const sourceExtractionError = (root, path, point, error) => {
44
+ if (error instanceof SourceExtractionError) {
45
+ return error;
46
+ }
47
+ const file = projectSourcePath(root, path);
48
+ const location = point === null
49
+ ? file
50
+ : `${file}:${String(point.line)}:${String(point.column + 1)}`;
51
+ return new SourceExtractionError(`${location}: ${sourceErrorMessage(error)}`, { cause: error });
52
+ };
53
+ const locatablePoint = (node) => {
54
+ const location = node.loc?.start;
55
+ return location === undefined ? null : { column: location.column, line: location.line };
56
+ };
57
+ const isSourcePoint = (value) => typeof value === "object" &&
58
+ value !== null &&
59
+ "column" in value &&
60
+ typeof value.column === "number" &&
61
+ "line" in value &&
62
+ typeof value.line === "number";
63
+ const errorSourcePoint = (error) => {
64
+ if (typeof error !== "object" || error === null) {
65
+ return null;
66
+ }
67
+ if ("loc" in error && isSourcePoint(error.loc)) {
68
+ return error.loc;
69
+ }
70
+ return "location" in error && isSourcePoint(error.location) ? error.location : null;
71
+ };
72
+ const atSourceNode = (root, path, node, operation) => {
73
+ try {
74
+ return operation();
75
+ }
76
+ catch (error) {
77
+ throw sourceExtractionError(root, path, locatablePoint(node), error);
78
+ }
79
+ };
80
+ const atExtractedLocation = (root, locations, operation) => {
81
+ const location = locations.find((candidate) => candidate.line !== undefined && candidate.column !== undefined);
82
+ if (location?.line === undefined || location.column === undefined) {
83
+ return operation();
84
+ }
85
+ try {
86
+ return operation();
87
+ }
88
+ catch (error) {
89
+ throw sourceExtractionError(root, location.file, { column: location.column, line: location.line }, error);
90
+ }
91
+ };
36
92
  const quietLogger = () => {
37
93
  const reports = [];
38
94
  return {
@@ -121,10 +177,10 @@ const expandedPlural = (entry) => {
121
177
  },
122
178
  };
123
179
  };
124
- const groupedPlurals = (entries) => {
180
+ const groupedPlurals = (root, entries) => {
125
181
  const groups = new Map();
126
182
  for (const entry of entries) {
127
- const { baseKey, variant } = expandedPlural(entry);
183
+ const { baseKey, variant } = atExtractedLocation(root, entry.locations ?? [], () => expandedPlural(entry));
128
184
  const namespace = namespaceFor(entry);
129
185
  const key = `${namespace}\0${baseKey}`;
130
186
  const group = groups.get(key) ?? { baseKey, namespace, variants: [] };
@@ -163,17 +219,19 @@ const pluralMessage = ({ baseKey, namespace, variants }) => {
163
219
  sourceKey: msgid,
164
220
  };
165
221
  };
166
- const pluralMessages = (entries) => groupedPlurals(entries).map((group) => pluralMessage(group));
222
+ const pluralMessages = (root, entries) => groupedPlurals(root, entries).map((group) => atExtractedLocation(root, group.variants.flatMap((variant) => variant.locations), () => pluralMessage(group)));
167
223
  const assertCardinal = (entry) => {
168
224
  if (entry.isOrdinal === true) {
169
225
  throw new Error("GNU gettext catalogs do not support i18next ordinal plurals");
170
226
  }
171
227
  };
172
- const sourceMessages = (entries) => {
228
+ const sourceMessages = (root, entries) => {
173
229
  const points = [];
174
230
  const plurals = [];
175
231
  for (const entry of entries) {
176
- assertCardinal(entry);
232
+ atExtractedLocation(root, entry.locations ?? [], () => {
233
+ assertCardinal(entry);
234
+ });
177
235
  if (entry.isExpandedPlural === true) {
178
236
  plurals.push(entry);
179
237
  continue;
@@ -183,7 +241,10 @@ const sourceMessages = (entries) => {
183
241
  }
184
242
  points.push(entry);
185
243
  }
186
- return [...points.map((entry) => pointMessage(entry)), ...pluralMessages(plurals)];
244
+ return [
245
+ ...points.map((entry) => atExtractedLocation(root, entry.locations ?? [], () => pointMessage(entry))),
246
+ ...pluralMessages(root, plurals),
247
+ ];
187
248
  };
188
249
  const compareMessages = (left, right) => left.namespace.localeCompare(right.namespace) ||
189
250
  (left.context ?? "").localeCompare(right.context ?? "") ||
@@ -497,13 +558,12 @@ const registerSourceMask = (node, references) => {
497
558
  };
498
559
  const sourceLocationKey = (line, column) => `${String(line)}:${String(column)}`;
499
560
  const sourcePoint = (node) => {
500
- const location = node.loc?.start;
501
- return location === undefined ? null : { column: location.column, line: location.line };
561
+ return locatablePoint(node);
502
562
  };
503
563
  const registerSourceLocation = (node, references) => {
504
564
  const point = sourcePoint(node);
505
565
  if (point !== null) {
506
- references.locations.add(sourceLocationKey(point.line, point.column));
566
+ references.locations.set(sourceLocationKey(point.line, point.column), point);
507
567
  }
508
568
  return point;
509
569
  };
@@ -603,6 +663,9 @@ const registerCallReference = (callPath, references, keyPrefix) => {
603
663
  references.calls.add(nodeStart(callPath));
604
664
  const firstArgument = callPath.node.arguments[0];
605
665
  const point = registerSourceLocation(firstArgument ?? callPath.node, references);
666
+ if (point !== null) {
667
+ references.sourcePoints.set(nodeStart(callPath), point);
668
+ }
606
669
  registerEntryLocation(extractedEntryKey(callPath.node, keyPrefix), point, references);
607
670
  };
608
671
  const parserPlugins = (lang) => [
@@ -610,6 +673,21 @@ const parserPlugins = (lang) => [
610
673
  ...(lang === "ts" || lang === "tsx" ? ["typescript"] : []),
611
674
  ...(lang === "jsx" || lang === "tsx" ? ["jsx"] : []),
612
675
  ];
676
+ const parseTranslationReferences = (root, path, source, lang) => {
677
+ try {
678
+ return parseBabelSync(source, {
679
+ ast: true,
680
+ babelrc: false,
681
+ configFile: false,
682
+ filename: projectSourcePath(root, path),
683
+ parserOpts: { createParenthesizedExpressions: true, plugins: parserPlugins(lang) },
684
+ sourceType: "module",
685
+ });
686
+ }
687
+ catch (error) {
688
+ throw sourceExtractionError(root, path, errorSourcePoint(error), error);
689
+ }
690
+ };
613
691
  const registerIdentifierTranslationCall = (callPath, callee, references) => {
614
692
  if (!callee.isIdentifier()) {
615
693
  return;
@@ -680,6 +758,14 @@ const registerUnrecognizedElementMasks = (elementPath, name, references) => {
680
758
  registerSourceMask(closingName, references);
681
759
  }
682
760
  };
761
+ const registerElementReference = (elementPath, references) => {
762
+ const start = nodeStart(elementPath);
763
+ const point = registerSourceLocation(elementPath.node, references);
764
+ references.elements.add(start);
765
+ if (point !== null) {
766
+ references.sourcePoints.set(start, point);
767
+ }
768
+ };
683
769
  const registerTranslationElement = (elementPath, references) => {
684
770
  const name = elementPath.get("name");
685
771
  if (!name.isJSXIdentifier()) {
@@ -690,8 +776,7 @@ const registerTranslationElement = (elementPath, references) => {
690
776
  throw new Error("Translation components must use their imported names");
691
777
  }
692
778
  if (kind === "canonical") {
693
- references.elements.add(nodeStart(elementPath));
694
- registerSourceLocation(elementPath.node, references);
779
+ registerElementReference(elementPath, references);
695
780
  }
696
781
  else if (TRANS_ELEMENTS.has(name.node.name)) {
697
782
  registerUnrecognizedElementMasks(elementPath, name, references);
@@ -705,15 +790,8 @@ const maskUnrecognizedTranslations = (source, references) => {
705
790
  }
706
791
  return masked;
707
792
  };
708
- const translationReferences = (path, source, lang) => {
709
- const parsed = parseBabelSync(source, {
710
- ast: true,
711
- babelrc: false,
712
- configFile: false,
713
- filename: path,
714
- parserOpts: { createParenthesizedExpressions: true, plugins: parserPlugins(lang) },
715
- sourceType: "module",
716
- });
793
+ const translationReferences = (root, path, source, lang) => {
794
+ const parsed = parseTranslationReferences(root, path, source, lang);
717
795
  if (parsed === null) {
718
796
  throw new Error(`Translation extraction could not parse ${path}`);
719
797
  }
@@ -721,21 +799,30 @@ const translationReferences = (path, source, lang) => {
721
799
  calls: new Set(),
722
800
  elements: new Set(),
723
801
  entryLocations: new Map(),
724
- locations: new Set(),
802
+ locations: new Map(),
725
803
  masks: [],
804
+ sourcePoints: new Map(),
726
805
  };
727
806
  traverse(parsed, {
728
807
  CallExpression(callPath) {
729
- registerTranslationCall(callPath, references);
808
+ atSourceNode(root, path, callPath.node, () => {
809
+ registerTranslationCall(callPath, references);
810
+ });
730
811
  },
731
812
  JSXOpeningElement(elementPath) {
732
- registerTranslationElement(elementPath, references);
813
+ atSourceNode(root, path, elementPath.node, () => {
814
+ registerTranslationElement(elementPath, references);
815
+ });
733
816
  },
734
817
  OptionalCallExpression(callPath) {
735
- assertSupportedOptionalCall(callPath);
818
+ atSourceNode(root, path, callPath.node, () => {
819
+ assertSupportedOptionalCall(callPath);
820
+ });
736
821
  },
737
822
  TaggedTemplateExpression(tagPath) {
738
- assertUnsupportedTranslationTag(tagPath);
823
+ atSourceNode(root, path, tagPath.node, () => {
824
+ assertUnsupportedTranslationTag(tagPath);
825
+ });
739
826
  },
740
827
  });
741
828
  return references;
@@ -799,19 +886,42 @@ const assertSupportedTransElement = (node, references) => {
799
886
  assertSupportedTransAttribute(attribute);
800
887
  }
801
888
  };
802
- const assertSupportedTranslationSyntax = (path, source) => {
889
+ const assertSupportedTranslationSyntax = (root, path, source) => {
803
890
  const lang = sourceLanguage(path);
804
891
  if (lang === undefined) {
805
- return { calls: new Set(), elements: new Set(), entryLocations: new Map(), locations: new Set(), masks: [] };
892
+ return {
893
+ calls: new Set(),
894
+ elements: new Set(),
895
+ entryLocations: new Map(),
896
+ locations: new Map(),
897
+ masks: [],
898
+ sourcePoints: new Map(),
899
+ };
900
+ }
901
+ let parsed;
902
+ try {
903
+ parsed = parseSync(projectSourcePath(root, path), source, { lang });
904
+ }
905
+ catch (error) {
906
+ throw sourceExtractionError(root, path, errorSourcePoint(error), error);
806
907
  }
807
- const parsed = parseSync(path, source, { lang });
808
- const references = translationReferences(path, source, lang);
908
+ const references = translationReferences(root, path, source, lang);
809
909
  new Visitor({
810
910
  CallExpression(node) {
811
- assertSupportedTranslationCall(node, references);
911
+ try {
912
+ assertSupportedTranslationCall(node, references);
913
+ }
914
+ catch (error) {
915
+ throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
916
+ }
812
917
  },
813
918
  JSXOpeningElement(node) {
814
- assertSupportedTransElement(node, references);
919
+ try {
920
+ assertSupportedTransElement(node, references);
921
+ }
922
+ catch (error) {
923
+ throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
924
+ }
815
925
  },
816
926
  }).visit(parsed.program);
817
927
  return references;
@@ -997,12 +1107,20 @@ const extractedSourcePoints = (root, entries) => {
997
1107
  }
998
1108
  return points;
999
1109
  };
1000
- const hasMissingSourcePoint = (file, references, extracted) => references.locations.values().some((location) => !extracted.has(`${file}\0${location}`));
1110
+ const missingSourcePoint = (file, references, extracted) => {
1111
+ for (const [location, point] of references.locations) {
1112
+ if (!extracted.has(`${file}\0${location}`)) {
1113
+ return point;
1114
+ }
1115
+ }
1116
+ return null;
1117
+ };
1001
1118
  const assertAllReferencesExtracted = (root, references, entries) => {
1002
1119
  const extracted = extractedSourcePoints(root, entries);
1003
1120
  for (const [file, sourceReferences] of references) {
1004
- if (hasMissingSourcePoint(file, sourceReferences, extracted)) {
1005
- throw new Error("A translation expression could not be extracted safely");
1121
+ const point = missingSourcePoint(file, sourceReferences, extracted);
1122
+ if (point !== null) {
1123
+ throw sourceExtractionError(root, file, point, new Error("A translation expression could not be extracted safely"));
1006
1124
  }
1007
1125
  }
1008
1126
  };
@@ -1014,7 +1132,7 @@ const findSourceMessages = async (root, sourceFiles) => {
1014
1132
  const sources = new Map(sourceFiles.map((file) => [file, readFileSync(file, "utf8")]));
1015
1133
  const references = new Map();
1016
1134
  for (const [file, source] of sources) {
1017
- references.set(file, assertSupportedTranslationSyntax(file, source));
1135
+ references.set(file, assertSupportedTranslationSyntax(root, file, source));
1018
1136
  }
1019
1137
  let extracted;
1020
1138
  const { logger, reports } = quietLogger();
@@ -1042,7 +1160,7 @@ const findSourceMessages = async (root, sourceFiles) => {
1042
1160
  if (extracted === undefined || reports.length > 0 || result.hasErrors) {
1043
1161
  throw new Error(reports.join("\n") || "i18next extraction failed");
1044
1162
  }
1045
- return sourceMessages(extracted.values().toArray())
1163
+ return sourceMessages(root, extracted.values().toArray())
1046
1164
  .map((message) => inferLocations(message, sources))
1047
1165
  .toSorted(compareMessages);
1048
1166
  };