@let-value/translate-extract 1.0.11 → 1.0.13

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/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { run } from "../run-Dl-tr2kf.js";
1
+ import { run } from "../run-CQoAsNNE.js";
2
2
  import path, { basename, dirname, extname, join, relative, resolve } from "node:path";
3
3
  import fs, { readFile } from "node:fs/promises";
4
4
  import * as gettextParser from "gettext-parser";
@@ -10,6 +10,7 @@ import { ResolverFactory } from "oxc-resolver";
10
10
  import { getFormula, getNPlurals } from "plural-forms";
11
11
 
12
12
  //#region src/plugins/cleanup/cleanup.ts
13
+ const namespace$2 = "cleanup";
13
14
  function cleanup() {
14
15
  return {
15
16
  name: "cleanup",
@@ -18,14 +19,14 @@ function cleanup() {
18
19
  const processedDirs = /* @__PURE__ */ new Set();
19
20
  const generated = /* @__PURE__ */ new Set();
20
21
  build.onResolve({
21
- namespace: "cleanup",
22
+ namespace: namespace$2,
22
23
  filter: /.*/
23
24
  }, (args) => {
24
25
  generated.add(args.path);
25
26
  return args;
26
27
  });
27
28
  build.onProcess({
28
- namespace: "cleanup",
29
+ namespace: namespace$2,
29
30
  filter: /.*/
30
31
  }, async ({ path: path$1 }) => {
31
32
  await build.defer("translate");
@@ -39,14 +40,12 @@ function cleanup() {
39
40
  const contents = await fs.readFile(full).catch(() => void 0);
40
41
  if (!contents) continue;
41
42
  const parsed = gettextParser.po.parse(contents);
42
- const hasTranslations = Object.entries(parsed.translations || {}).some(([ctx, msgs]) => Object.keys(msgs).some((id) => !(ctx === "" && id === "")));
43
- if (hasTranslations) build.context.logger?.warn({ path: full }, "stray translation file");
43
+ if (Object.entries(parsed.translations || {}).some(([ctx, msgs]) => Object.keys(msgs).some((id) => !(ctx === "" && id === "")))) build.context.logger?.warn({ path: full }, "stray translation file");
44
44
  else {
45
45
  await fs.unlink(full);
46
46
  build.context.logger?.info({ path: full }, "removed empty translation file");
47
47
  }
48
48
  }
49
- return void 0;
50
49
  });
51
50
  }
52
51
  };
@@ -56,8 +55,7 @@ function cleanup() {
56
55
  //#region src/plugins/core/queries/comment.ts
57
56
  function getReference(node, { path: path$1 }) {
58
57
  const line = node.startPosition.row + 1;
59
- const rel = relative(process.cwd(), path$1).replace(/\\+/g, "/");
60
- return `${rel}:${line}`;
58
+ return `${relative(process.cwd(), path$1).replace(/\\+/g, "/")}:${line}`;
61
59
  }
62
60
  function getComment(node) {
63
61
  const text = node.text;
@@ -109,8 +107,7 @@ const importQuery = {
109
107
  ]
110
108
  `,
111
109
  extract(match) {
112
- const node = match.captures.find((c) => c.name === "import")?.node;
113
- return node?.text;
110
+ return (match.captures.find((c) => c.name === "import")?.node)?.text;
114
111
  }
115
112
  };
116
113
 
@@ -152,7 +149,7 @@ const notInPlural = (query) => ({
152
149
  "ngettext",
153
150
  "pgettext",
154
151
  "npgettext"
155
- ].includes(fn.childForFieldName("property")?.text ?? "")) return void 0;
152
+ ].includes(fn.childForFieldName("property")?.text ?? "")) return;
156
153
  }
157
154
  }
158
155
  return result;
@@ -180,7 +177,7 @@ const messageArg = `[
180
177
  const messageArgs = `[ (arguments ${messageArg}) (template_string) @tpl ]`;
181
178
  const extractMessage = (name) => (match) => {
182
179
  const node = match.captures.find((c) => c.name === "call")?.node;
183
- if (!node) return void 0;
180
+ if (!node) return;
184
181
  const msgid = match.captures.find((c) => c.name === "msgid")?.node.text;
185
182
  if (msgid) return {
186
183
  node,
@@ -211,13 +208,12 @@ const extractMessage = (name) => (match) => {
211
208
  const id = match.captures.find((c) => c.name === "id")?.node.text;
212
209
  const message = match.captures.find((c) => c.name === "message")?.node.text;
213
210
  const msgId = id ?? message;
214
- if (!msgId) return void 0;
215
- const msgstr = message ?? id ?? "";
211
+ if (!msgId) return;
216
212
  return {
217
213
  node,
218
214
  translation: {
219
215
  id: msgId,
220
- message: [msgstr]
216
+ message: [message ?? id ?? ""]
221
217
  }
222
218
  };
223
219
  };
@@ -235,8 +231,8 @@ const messageInvalidQuery = notInPlural({
235
231
  extract(match) {
236
232
  const call = match.captures.find((c) => c.name === "call")?.node;
237
233
  const node = match.captures.find((c) => c.name === "arg")?.node;
238
- if (!call || !node) return void 0;
239
- if (allowed$1.has(node.type)) return void 0;
234
+ if (!call || !node) return;
235
+ if (allowed$1.has(node.type)) return;
240
236
  return {
241
237
  node,
242
238
  error: "message() argument must be a string literal, object literal, or template literal"
@@ -249,7 +245,7 @@ const messageInvalidQuery = notInPlural({
249
245
  const extractPluralForms = (name) => (match) => {
250
246
  const call = match.captures.find((c) => c.name === "call")?.node;
251
247
  const n = match.captures.find((c) => c.name === "n")?.node;
252
- if (!call || !n || n.nextNamedSibling) return void 0;
248
+ if (!call || !n || n.nextNamedSibling) return;
253
249
  const msgctxt = match.captures.find((c) => c.name === "msgctxt")?.node?.text;
254
250
  const msgNodes = match.captures.filter((c) => c.name === "msg").map((c) => c.node);
255
251
  const ids = [];
@@ -279,7 +275,7 @@ const extractPluralForms = (name) => (match) => {
279
275
  strs.push(result.translation.message[0] ?? "");
280
276
  }
281
277
  }
282
- if (ids.length === 0) return void 0;
278
+ if (ids.length === 0) return;
283
279
  const translation = {
284
280
  id: ids[0],
285
281
  plural: ids[1],
@@ -340,12 +336,12 @@ const contextInvalidQuery = withComment({
340
336
  pattern: ctxCall,
341
337
  extract(match) {
342
338
  const call = match.captures.find((c) => c.name === "ctx")?.node;
343
- if (!call) return void 0;
339
+ if (!call) return;
344
340
  const parent = call.parent;
345
341
  if (parent && parent.type === "member_expression" && parent.childForFieldName("object")?.id === call.id) {
346
342
  const property = parent.childForFieldName("property")?.text;
347
343
  const grandparent = parent.parent;
348
- if (grandparent && grandparent.type === "call_expression" && grandparent.childForFieldName("function")?.id === parent.id && (property === "message" || property === "plural")) return void 0;
344
+ if (grandparent && grandparent.type === "call_expression" && grandparent.childForFieldName("function")?.id === parent.id && (property === "message" || property === "plural")) return;
349
345
  }
350
346
  return {
351
347
  node: call,
@@ -372,8 +368,8 @@ const gettextInvalidQuery = {
372
368
  extract(match) {
373
369
  const call = match.captures.find((c) => c.name === "call")?.node;
374
370
  const node = match.captures.find((c) => c.name === "arg")?.node;
375
- if (!call || !node) return void 0;
376
- if (allowed.has(node.type)) return void 0;
371
+ if (!call || !node) return;
372
+ if (allowed.has(node.type)) return;
377
373
  return {
378
374
  node,
379
375
  error: "gettext() argument must be a string literal, object literal, or template literal"
@@ -541,7 +537,7 @@ function findTsconfig(dir) {
541
537
  const config = path.join(current, "tsconfig.json");
542
538
  if (fs$1.existsSync(config)) return config;
543
539
  const parent = path.dirname(current);
544
- if (parent === current) return void 0;
540
+ if (parent === current) return;
545
541
  current = parent;
546
542
  }
547
543
  }
@@ -634,7 +630,6 @@ function core() {
634
630
  namespace: "translate",
635
631
  data: translations
636
632
  });
637
- return void 0;
638
633
  });
639
634
  }
640
635
  };
@@ -780,7 +775,7 @@ function po() {
780
775
  filter: /.*/,
781
776
  namespace
782
777
  }, async ({ entrypoint, path: path$1, data }) => {
783
- if (!data || !Array.isArray(data)) return void 0;
778
+ if (!data || !Array.isArray(data)) return;
784
779
  for (const locale of build.context.config.locales) {
785
780
  const destination = build.context.config.destination({
786
781
  entrypoint,
@@ -802,7 +797,6 @@ function po() {
802
797
  namespace
803
798
  });
804
799
  });
805
- return void 0;
806
800
  });
807
801
  build.onLoad({
808
802
  filter: /.*\.po$/,
@@ -823,7 +817,7 @@ function po() {
823
817
  const collected = collections.get(path$1);
824
818
  if (!collected) {
825
819
  build.context.logger?.warn({ path: path$1 }, "no translations collected for this path");
826
- return void 0;
820
+ return;
827
821
  }
828
822
  const { locale, translations } = collected;
829
823
  const record = collect(translations, locale);
@@ -880,8 +874,7 @@ function resolvePlugins(user) {
880
874
  function defineConfig(config) {
881
875
  const defaultLocale = config.defaultLocale ?? "en";
882
876
  const plugins = resolvePlugins(config.plugins);
883
- const raw = Array.isArray(config.entrypoints) ? config.entrypoints : [config.entrypoints];
884
- const entrypoints = raw.map(resolveEntrypoint);
877
+ const entrypoints = (Array.isArray(config.entrypoints) ? config.entrypoints : [config.entrypoints]).map(resolveEntrypoint);
885
878
  return {
886
879
  plugins,
887
880
  entrypoints,
@@ -898,43 +891,96 @@ function defineConfig(config) {
898
891
  //#endregion
899
892
  //#region src/plugins/react/queries/utils.ts
900
893
  function buildTemplate(node) {
894
+ const source = node.tree.rootNode.text;
895
+ const open = node.childForFieldName("open_tag");
896
+ const close = node.childForFieldName("close_tag");
897
+ const contentStart = open?.endIndex ?? node.startIndex;
898
+ const contentEnd = close?.startIndex ?? node.endIndex;
899
+ const parts = [];
900
+ let segmentStart = contentStart;
901
+ const pushRawText = (endIndex) => {
902
+ if (endIndex <= segmentStart) {
903
+ segmentStart = Math.max(segmentStart, endIndex);
904
+ return;
905
+ }
906
+ const text$1 = source.slice(segmentStart, endIndex);
907
+ if (text$1) parts.push({
908
+ kind: "text",
909
+ text: text$1,
910
+ raw: true
911
+ });
912
+ segmentStart = endIndex;
913
+ };
901
914
  const children = node.namedChildren.slice(1, -1);
902
- const strings = [""];
903
- const values = [];
904
- for (let i = 0; i < children.length; i++) {
905
- const child = children[i];
906
- if (child.type === "jsx_text") {
907
- let text$1 = child.text;
908
- if (i === 0) text$1 = text$1.replace(/^\s+/, "");
909
- if (i === children.length - 1) text$1 = text$1.replace(/\s+$/, "");
910
- if (text$1) strings[strings.length - 1] += text$1;
911
- } else if (child.type === "jsx_expression") {
912
- const expr = child.namedChildren[0];
913
- if (!expr) return {
914
- text: "",
915
- error: "Empty JSX expression"
916
- };
917
- if (expr.type === "identifier") {
918
- values.push(expr.text);
919
- strings.push("");
920
- } else if (expr.type === "string") strings[strings.length - 1] += expr.text.slice(1, -1);
921
- else if (expr.type === "template_string") {
922
- const hasSubstitutions = expr.children.some((c) => c.type === "template_substitution");
923
- if (hasSubstitutions) return {
924
- text: "",
925
- error: "JSX expressions with template substitutions are not supported"
926
- };
927
- const content = expr.text.slice(1, -1);
928
- strings[strings.length - 1] += content;
929
- } else return {
915
+ for (const child of children) if (child.type === "jsx_expression") {
916
+ pushRawText(child.startIndex);
917
+ const expr = child.namedChildren[0];
918
+ if (!expr) return {
919
+ text: "",
920
+ error: "Empty JSX expression"
921
+ };
922
+ if (expr.type === "identifier") parts.push({
923
+ kind: "expr",
924
+ value: expr.text
925
+ });
926
+ else if (expr.type === "string") parts.push({
927
+ kind: "text",
928
+ text: expr.text.slice(1, -1),
929
+ raw: false
930
+ });
931
+ else if (expr.type === "template_string") {
932
+ if (expr.children.some((c) => c.type === "template_substitution")) return {
930
933
  text: "",
931
- error: "JSX expressions must be simple identifiers, strings, or template literals"
934
+ error: "JSX expressions with template substitutions are not supported"
932
935
  };
933
- } else if (child.type === "string") strings[strings.length - 1] += child.text.slice(1, -1);
934
- else return {
936
+ parts.push({
937
+ kind: "text",
938
+ text: expr.text.slice(1, -1),
939
+ raw: false
940
+ });
941
+ } else return {
935
942
  text: "",
936
- error: "Unsupported JSX child"
943
+ error: "JSX expressions must be simple identifiers, strings, or template literals"
937
944
  };
945
+ segmentStart = child.endIndex;
946
+ } else if (child.type === "string") {
947
+ pushRawText(child.startIndex);
948
+ parts.push({
949
+ kind: "text",
950
+ text: child.text.slice(1, -1),
951
+ raw: false
952
+ });
953
+ segmentStart = child.endIndex;
954
+ } else if (child.type === "jsx_text" || child.type === "html_character_reference" || child.isError) continue;
955
+ else return {
956
+ text: "",
957
+ error: "Unsupported JSX child"
958
+ };
959
+ pushRawText(contentEnd);
960
+ const firstRawIndex = parts.findIndex((part) => part.kind === "text" && part.raw);
961
+ if (firstRawIndex === 0) {
962
+ const part = parts[firstRawIndex];
963
+ part.text = part.text.replace(/^\s+/, "");
964
+ }
965
+ let lastRawIndex = -1;
966
+ for (let i = parts.length - 1; i >= 0; i--) {
967
+ const part = parts[i];
968
+ if (part.kind === "text" && part.raw) {
969
+ lastRawIndex = i;
970
+ break;
971
+ }
972
+ }
973
+ if (lastRawIndex !== -1 && lastRawIndex === parts.length - 1) {
974
+ const part = parts[lastRawIndex];
975
+ part.text = part.text.replace(/\s+$/, "");
976
+ }
977
+ const strings = [""];
978
+ const values = [];
979
+ for (const part of parts) if (part.kind === "text") {
980
+ if (part.text) strings[strings.length - 1] += part.text;
981
+ } else {
982
+ values.push(part.value);
983
+ strings.push("");
938
984
  }
939
985
  let text = "";
940
986
  for (let i = 0; i < strings.length; i++) {
@@ -954,13 +1000,11 @@ function buildAttrValue(node) {
954
1000
  if (expr.type === "identifier") return { text: `\${${expr.text}}` };
955
1001
  else if (expr.type === "string") return { text: expr.text.slice(1, -1) };
956
1002
  else if (expr.type === "template_string") {
957
- const hasSubstitutions = expr.children.some((c) => c.type === "template_substitution");
958
- if (hasSubstitutions) return {
1003
+ if (expr.children.some((c) => c.type === "template_substitution")) return {
959
1004
  text: "",
960
1005
  error: "JSX expressions with template substitutions are not supported"
961
1006
  };
962
- const content = expr.text.slice(1, -1);
963
- return { text: content };
1007
+ return { text: expr.text.slice(1, -1) };
964
1008
  } else return {
965
1009
  text: "",
966
1010
  error: "JSX expressions must be simple identifiers, strings, or template literals"
@@ -1150,22 +1194,22 @@ function react() {
1150
1194
  build.onResolve({
1151
1195
  filter: /.*/,
1152
1196
  namespace: "source"
1153
- }, ({ entrypoint, path: path$1, namespace: namespace$2 }) => {
1197
+ }, ({ entrypoint, path: path$1, namespace: namespace$3 }) => {
1154
1198
  return {
1155
1199
  entrypoint,
1156
- namespace: namespace$2,
1200
+ namespace: namespace$3,
1157
1201
  path: resolve(path$1)
1158
1202
  };
1159
1203
  });
1160
1204
  build.onLoad({
1161
1205
  filter,
1162
1206
  namespace: "source"
1163
- }, async ({ entrypoint, path: path$1, namespace: namespace$2 }) => {
1207
+ }, async ({ entrypoint, path: path$1, namespace: namespace$3 }) => {
1164
1208
  const data = await readFile(path$1, "utf8");
1165
1209
  return {
1166
1210
  entrypoint,
1167
1211
  path: path$1,
1168
- namespace: namespace$2,
1212
+ namespace: namespace$3,
1169
1213
  data
1170
1214
  };
1171
1215
  });
@@ -1181,7 +1225,6 @@ function react() {
1181
1225
  namespace: "translate",
1182
1226
  data: translations
1183
1227
  });
1184
- return void 0;
1185
1228
  });
1186
1229
  }
1187
1230
  };