@inlang/paraglide-js 2.26.0 → 2.27.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/README.md +2 -1
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +2 -2
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
- package/dist/cli/commands/init/command.js +19 -1
- package/dist/cli/commands/init/command.js.map +1 -1
- package/dist/cli/defaults.js +2 -2
- package/dist/cli/defaults.js.map +1 -1
- package/dist/cli/steps/add-inlang-check.d.ts +19 -0
- package/dist/cli/steps/add-inlang-check.js +60 -0
- package/dist/cli/steps/add-inlang-check.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
- package/dist/cli/steps/add-inlang-check.test.js +88 -0
- package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
- package/dist/cli/steps/agents-md-suggestion.js +19 -0
- package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
- package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
- package/dist/cli/steps/maybe-add-machine-translation.js +3 -2
- package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.js +1 -1
- package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
- package/dist/cli/utils.d.ts +9 -0
- package/dist/cli/utils.js +15 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/compiler/compile-annotation.d.ts +48 -1
- package/dist/compiler/compile-annotation.js +238 -10
- package/dist/compiler/compile-annotation.js.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +3 -2
- package/dist/compiler/compile-bundle.js +30 -1
- package/dist/compiler/compile-bundle.js.map +1 -1
- package/dist/compiler/compile-bundle.test.js +18 -18
- package/dist/compiler/compile-bundle.test.js.map +1 -1
- package/dist/compiler/compile-local-variable.d.ts +3 -0
- package/dist/compiler/compile-local-variable.js +5 -2
- package/dist/compiler/compile-local-variable.js.map +1 -1
- package/dist/compiler/compile-local-variable.test.js +44 -4
- package/dist/compiler/compile-local-variable.test.js.map +1 -1
- package/dist/compiler/compile-message.d.ts +29 -1
- package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
- package/dist/compiler/compile-message.exact-number.test.js +786 -0
- package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
- package/dist/compiler/compile-message.js +162 -66
- package/dist/compiler/compile-message.js.map +1 -1
- package/dist/compiler/compile-message.locals.test.d.ts +1 -0
- package/dist/compiler/compile-message.locals.test.js +498 -0
- package/dist/compiler/compile-message.locals.test.js.map +1 -0
- package/dist/compiler/compile-message.test.js +111 -20
- package/dist/compiler/compile-message.test.js.map +1 -1
- package/dist/compiler/compile-pattern.d.ts +5 -0
- package/dist/compiler/compile-pattern.js +6 -18
- package/dist/compiler/compile-pattern.js.map +1 -1
- package/dist/compiler/compile-pattern.test.js +165 -1
- package/dist/compiler/compile-pattern.test.js.map +1 -1
- package/dist/compiler/compile-project.js +4 -1
- package/dist/compiler/compile-project.js.map +1 -1
- package/dist/compiler/compile-project.test.js +1013 -31
- package/dist/compiler/compile-project.test.js.map +1 -1
- package/dist/compiler/compile.test.js +1 -1
- package/dist/compiler/compile.test.js.map +1 -1
- package/dist/compiler/create-readme.d.ts +4 -1
- package/dist/compiler/create-readme.js +33 -125
- package/dist/compiler/create-readme.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
- package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.test.js +4 -4
- package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.js +1 -1
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/input-alias.d.ts +21 -0
- package/dist/compiler/input-alias.js +42 -0
- package/dist/compiler/input-alias.js.map +1 -0
- package/dist/compiler/input-alias.test.d.ts +1 -0
- package/dist/compiler/input-alias.test.js +58 -0
- package/dist/compiler/input-alias.test.js.map +1 -0
- package/dist/compiler/message-locals.d.ts +46 -0
- package/dist/compiler/message-locals.js +129 -0
- package/dist/compiler/message-locals.js.map +1 -0
- package/dist/compiler/output-structure/locale-modules.js +7 -1
- package/dist/compiler/output-structure/locale-modules.js.map +1 -1
- package/dist/compiler/output-structure/locale-modules.test.js +35 -0
- package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +5 -3
- package/dist/compiler/output-structure/message-modules.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.test.js +35 -0
- package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
- package/dist/compiler/registry.d.ts +12 -0
- package/dist/compiler/registry.js +97 -28
- package/dist/compiler/registry.js.map +1 -1
- package/dist/compiler/server/create-server-file.js +24 -0
- package/dist/compiler/server/create-server-file.js.map +1 -1
- package/dist/compiler/server/create-server-file.test.js +8 -2
- package/dist/compiler/server/create-server-file.test.js.map +1 -1
- package/dist/compiler/server/middleware.js +29 -4
- package/dist/compiler/server/middleware.js.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/env-variables/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maybe-add-machine-translation.js","sourceRoot":"","sources":["../../../src/cli/steps/maybe-add-machine-translation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"maybe-add-machine-translation.js","sourceRoot":"","sources":["../../../src/cli/steps/maybe-add-machine-translation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,CAAC,MAAM,0BAA0B,GAenC,KAAK,EAAE,GAAG,EAAE,EAAE;IACjB,iCAAiC;IACjC,MAAM,qBAAqB,GAAG,MAAM,MAAM,CACzC,6CAA6C,EAC7C;QACC,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,IAAI;KACb,CACD,CAAC;IAEF,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACJ,mDAAmD;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QAE9D,2FAA2F;QAC3F,MAAM,iBAAiB,CAAC;YACvB,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBAClC,iBAAiB;gBACjB,IAAI,OAAO,CAAC,aAAa,CAAC;oBAAE,OAAO,OAAO,CAAC;gBAC3C,OAAO;oBACN,GAAG,OAAO;oBACV,aAAa,EAAE,wBAAwB;iBACvC,CAAC;YACH,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;gBAC1B,iBAAiB;gBACjB,IAAI,OAAO,CAAC,mBAAmB,CAAC;oBAAE,OAAO,OAAO,CAAC;gBACjD,OAAO;oBACN,GAAG,OAAO;oBACV,mBAAmB,EAAE,sCAAsC,YAAY,EAAE;iBACzE,CAAC;YACH,CAAC;SACD,CAAC,CAAC,GAAG,CAAC,CAAC;QAER,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;IACzE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,KAAK,CACf;YACC,+DAA+D;YAC/D,uCAAuC;YACvC,mDAAmD;YACnD,KAAK;SACL,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC","sourcesContent":["import type { Logger } from \"../../services/logger/index.js\";\nimport type { CliStep } from \"../utils.js\";\nimport { prompt } from \"../utils.js\";\nimport { updatePackageJson } from \"./update-package-json.js\";\nimport path from \"node:path\";\nimport { INLANG_CLI_VERSION_RANGE } from \"./add-inlang-check.js\";\n\nexport const maybeAddMachineTranslation: CliStep<\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tlogger: Logger;\n\t\tprojectPath: string;\n\t\troot: string;\n\t\tpackageJsonPath: string;\n\t},\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tlogger: Logger;\n\t\tprojectPath: string;\n\t\troot: string;\n\t\tpackageJsonPath: string;\n\t}\n> = async (ctx) => {\n\t// Prompt for machine translation\n\tconst useMachineTranslation = await prompt(\n\t\t`Do you want to set up machine translations?`,\n\t\t{\n\t\t\ttype: \"confirm\",\n\t\t\tinitial: true,\n\t\t}\n\t);\n\n\tif (!useMachineTranslation) {\n\t\treturn ctx;\n\t}\n\n\ttry {\n\t\t// Determine the relative path from root to project\n\t\tconst relativePath = path.relative(ctx.root, ctx.projectPath);\n\n\t\t// Use updatePackageJson to add @inlang/cli to devDependencies and machine-translate script\n\t\tawait updatePackageJson({\n\t\t\tdevDependencies: async (devDeps) => {\n\t\t\t\t// exists already\n\t\t\t\tif (devDeps[\"@inlang/cli\"]) return devDeps;\n\t\t\t\treturn {\n\t\t\t\t\t...devDeps,\n\t\t\t\t\t\"@inlang/cli\": INLANG_CLI_VERSION_RANGE,\n\t\t\t\t};\n\t\t\t},\n\t\t\tscripts: async (scripts) => {\n\t\t\t\t// exists already\n\t\t\t\tif (scripts[\"machine-translate\"]) return scripts;\n\t\t\t\treturn {\n\t\t\t\t\t...scripts,\n\t\t\t\t\t\"machine-translate\": `inlang machine translate --project ${relativePath}`,\n\t\t\t\t};\n\t\t\t},\n\t\t})(ctx);\n\n\t\tctx.logger.success(\"Added a machine-translate script to package.json.\");\n\t} catch (error) {\n\t\tctx.logger.error(\n\t\t\t[\n\t\t\t\t\"Failed to set up machine translation. Please add it manually:\",\n\t\t\t\t\"1. Add @inlang/cli to devDependencies\",\n\t\t\t\t\"2. Add a machine-translate script to package.json\",\n\t\t\t\terror,\n\t\t\t].join(\"\\n\")\n\t\t);\n\t}\n\n\treturn ctx;\n};\n"]}
|
|
@@ -22,7 +22,7 @@ export const maybeAddSherlock = async (ctx) => {
|
|
|
22
22
|
if (settings.modules?.some((m) => m.includes("plugin-m-function-matcher")) ===
|
|
23
23
|
false) {
|
|
24
24
|
// add the m function matcher plugin
|
|
25
|
-
settings.modules.push("https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2.
|
|
25
|
+
settings.modules.push("https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2.3.0/dist/index.js");
|
|
26
26
|
await ctx.project.settings.set(settings);
|
|
27
27
|
}
|
|
28
28
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maybe-add-sherlock.js","sourceRoot":"","sources":["../../../src/cli/steps/maybe-add-sherlock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,KAAK,QAAQ,MAAM,4BAA4B,CAAC;AAEvD,MAAM,CAAC,MAAM,gBAAgB,GAOzB,KAAK,EAAE,GAAG,EAAE,EAAE;IACjB,MAAM,iBAAiB,GAAG,OAAO,EAAE,GAAG,EAAE,YAAY,KAAK,QAAQ,CAAC;IAClE,IAAI,aAAa,GAAG,iBAAiB,CAAC;IAEtC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACxB,aAAa,GAAG,MAAM,MAAM,CAC3B,sEAAsE,EACtE;YACC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,IAAI;SACb,CACD,CAAC;IACH,CAAC;IACD,IAAI,aAAa,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IAExC,MAAM,iBAAiB,GAAG,MAAM,MAAM,CACrC,+EAA+E,EAC/E;QACC,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,IAAI;KACb,CACD,CAAC;IACF,IAAI,iBAAiB,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IAE5C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;IAElD,sCAAsC;IACtC,IACC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC;QACtE,KAAK,EACJ,CAAC;QACF,oCAAoC;QACpC,QAAQ,CAAC,OAAO,CAAC,IAAI,CACpB,oFAAoF,CACpF,CAAC;QACF,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC;QACJ,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,GAAG,CAAC,MAAM,CAAC,OAAO,CACjB,uEAAuE,CACvE,CAAC;QACH,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,KAAK,CACf;YACC,mEAAmE;YACnE,KAAK;SACL,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC","sourcesContent":["import type { Logger } from \"../../services/logger/index.js\";\nimport { prompt } from \"../utils.js\";\nimport type { CliStep } from \"../utils.js\";\nimport type { InlangProject } from \"@inlang/sdk\";\nimport * as Sherlock from \"@inlang/recommend-sherlock\";\n\nexport const maybeAddSherlock: CliStep<\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tlogger: Logger;\n\t\tproject: InlangProject;\n\t},\n\tunknown\n> = async (ctx) => {\n\tconst isCertainlyVsCode = process?.env?.TERM_PROGRAM === \"vscode\";\n\tlet isUsingVsCode = isCertainlyVsCode;\n\n\tif (!isCertainlyVsCode) {\n\t\tisUsingVsCode = await prompt(\n\t\t\t`Are you using Visual Studio Code or a compatible fork (like Cursor)?`,\n\t\t\t{\n\t\t\t\ttype: \"confirm\",\n\t\t\t\tinitial: true,\n\t\t\t}\n\t\t);\n\t}\n\tif (isUsingVsCode === false) return ctx;\n\n\tconst shouldAddSherlock = await prompt(\n\t\t`Do you want to use the Sherlock VSCode (or Cursor) extension for a better DX?`,\n\t\t{\n\t\t\ttype: \"confirm\",\n\t\t\tinitial: true,\n\t\t}\n\t);\n\tif (shouldAddSherlock === false) return ctx;\n\n\tconst settings = await ctx.project.settings.get();\n\n\t// m function matcher is not installed\n\tif (\n\t\tsettings.modules?.some((m) => m.includes(\"plugin-m-function-matcher\")) ===\n\t\tfalse\n\t) {\n\t\t// add the m function matcher plugin\n\t\tsettings.modules.push(\n\t\t\t\"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2.
|
|
1
|
+
{"version":3,"file":"maybe-add-sherlock.js","sourceRoot":"","sources":["../../../src/cli/steps/maybe-add-sherlock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,KAAK,QAAQ,MAAM,4BAA4B,CAAC;AAEvD,MAAM,CAAC,MAAM,gBAAgB,GAOzB,KAAK,EAAE,GAAG,EAAE,EAAE;IACjB,MAAM,iBAAiB,GAAG,OAAO,EAAE,GAAG,EAAE,YAAY,KAAK,QAAQ,CAAC;IAClE,IAAI,aAAa,GAAG,iBAAiB,CAAC;IAEtC,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACxB,aAAa,GAAG,MAAM,MAAM,CAC3B,sEAAsE,EACtE;YACC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,IAAI;SACb,CACD,CAAC;IACH,CAAC;IACD,IAAI,aAAa,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IAExC,MAAM,iBAAiB,GAAG,MAAM,MAAM,CACrC,+EAA+E,EAC/E;QACC,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,IAAI;KACb,CACD,CAAC;IACF,IAAI,iBAAiB,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IAE5C,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;IAElD,sCAAsC;IACtC,IACC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC;QACtE,KAAK,EACJ,CAAC;QACF,oCAAoC;QACpC,QAAQ,CAAC,OAAO,CAAC,IAAI,CACpB,oFAAoF,CACpF,CAAC;QACF,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC;QACJ,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,GAAG,CAAC,MAAM,CAAC,OAAO,CACjB,uEAAuE,CACvE,CAAC;QACH,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,GAAG,CAAC,MAAM,CAAC,KAAK,CACf;YACC,mEAAmE;YACnE,KAAK;SACL,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC","sourcesContent":["import type { Logger } from \"../../services/logger/index.js\";\nimport { prompt } from \"../utils.js\";\nimport type { CliStep } from \"../utils.js\";\nimport type { InlangProject } from \"@inlang/sdk\";\nimport * as Sherlock from \"@inlang/recommend-sherlock\";\n\nexport const maybeAddSherlock: CliStep<\n\t{\n\t\tfs: typeof import(\"node:fs/promises\");\n\t\tlogger: Logger;\n\t\tproject: InlangProject;\n\t},\n\tunknown\n> = async (ctx) => {\n\tconst isCertainlyVsCode = process?.env?.TERM_PROGRAM === \"vscode\";\n\tlet isUsingVsCode = isCertainlyVsCode;\n\n\tif (!isCertainlyVsCode) {\n\t\tisUsingVsCode = await prompt(\n\t\t\t`Are you using Visual Studio Code or a compatible fork (like Cursor)?`,\n\t\t\t{\n\t\t\t\ttype: \"confirm\",\n\t\t\t\tinitial: true,\n\t\t\t}\n\t\t);\n\t}\n\tif (isUsingVsCode === false) return ctx;\n\n\tconst shouldAddSherlock = await prompt(\n\t\t`Do you want to use the Sherlock VSCode (or Cursor) extension for a better DX?`,\n\t\t{\n\t\t\ttype: \"confirm\",\n\t\t\tinitial: true,\n\t\t}\n\t);\n\tif (shouldAddSherlock === false) return ctx;\n\n\tconst settings = await ctx.project.settings.get();\n\n\t// m function matcher is not installed\n\tif (\n\t\tsettings.modules?.some((m) => m.includes(\"plugin-m-function-matcher\")) ===\n\t\tfalse\n\t) {\n\t\t// add the m function matcher plugin\n\t\tsettings.modules.push(\n\t\t\t\"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2.3.0/dist/index.js\"\n\t\t);\n\t\tawait ctx.project.settings.set(settings);\n\t}\n\n\ttry {\n\t\tif (!(await Sherlock.isAdopted({ fs: ctx.fs }))) {\n\t\t\tawait Sherlock.add({ fs: ctx.fs });\n\t\t\tctx.logger.success(\n\t\t\t\t\"Added the Sherlock VSCode extension to the workspace recommendations.\"\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tctx.logger.error(\n\t\t\t[\n\t\t\t\t\"Failed to add the Sherlock VSCode extension. Please open an issue\",\n\t\t\t\terror,\n\t\t\t].join(\"\\n\")\n\t\t);\n\t}\n\n\treturn ctx;\n};\n"]}
|
package/dist/cli/utils.d.ts
CHANGED
|
@@ -34,3 +34,12 @@ export declare const promptSelection: <T extends string>(message: string, option
|
|
|
34
34
|
value: T;
|
|
35
35
|
}[];
|
|
36
36
|
}) => Promise<T>;
|
|
37
|
+
/**
|
|
38
|
+
* A path relative to `root` with forward slashes and without a leading `./`,
|
|
39
|
+
* for messages and package.json scripts.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* toRelativeDisplayPath("/app", "./project.inlang") // "project.inlang"
|
|
43
|
+
* toRelativeDisplayPath("/app", "/app/src/paraglide") // "src/paraglide"
|
|
44
|
+
*/
|
|
45
|
+
export declare function toRelativeDisplayPath(root: string, path: string): string;
|
package/dist/cli/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import consola from "consola";
|
|
2
|
+
import nodePath from "node:path";
|
|
2
3
|
/**
|
|
3
4
|
* Wrapper to exit the process if the user presses CTRL+C.
|
|
4
5
|
*/
|
|
@@ -17,4 +18,18 @@ export const promptSelection = async (message, options = {
|
|
|
17
18
|
...options,
|
|
18
19
|
});
|
|
19
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* A path relative to `root` with forward slashes and without a leading `./`,
|
|
23
|
+
* for messages and package.json scripts.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* toRelativeDisplayPath("/app", "./project.inlang") // "project.inlang"
|
|
27
|
+
* toRelativeDisplayPath("/app", "/app/src/paraglide") // "src/paraglide"
|
|
28
|
+
*/
|
|
29
|
+
export function toRelativeDisplayPath(root, path) {
|
|
30
|
+
return nodePath
|
|
31
|
+
.relative(root, nodePath.resolve(root, path))
|
|
32
|
+
.split(nodePath.sep)
|
|
33
|
+
.join("/");
|
|
34
|
+
}
|
|
20
35
|
//# sourceMappingURL=utils.js.map
|
package/dist/cli/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/cli/utils.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,QAAQ,MAAM,WAAW,CAAC;AA6BjC;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAA0B,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IACvE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,IAAI,QAAQ,EAAE,QAAQ,EAAE,KAAK,sBAAsB,EAAE,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EACnC,OAAe,EACf,OAAO,GAA4D;IAClE,OAAO,EAAE,EAAE;CACX,EACY,EAAE;IACf,OAAO,MAAM,CAAC,OAAO,EAAE;QACtB,IAAI,EAAE,QAAQ;QACd,GAAG,OAAO;KACV,CAA0B,CAAC;AAC7B,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,IAAY;IAC/D,OAAO,QAAQ;SACb,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;SAC5C,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;SACnB,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC","sourcesContent":["import consola from \"consola\";\nimport nodePath from \"node:path\";\n\n/**\n * One step in a CLI chain.\n * Defines which types the context needs to extend and how it extends the context\n *\n * Cli Steps can be chained to slowly build up the context over time\n *\n * @example\n * ```ts\n * const step1: CliStep<unknown, { foo: string }> = async (ctx) => {\n * return {...ctx, foo: \"hello\" }\n * }\n *\n * const step2: CliStep<{ foo: string }, { bar: number }> = async (ctx) => {\n * return { ...ctx, bar: 42 }\n * }\n *\n * const initial = { baz: \"baz\" } as const;\n * const ctx1 = await step1(initial);\n * const ctx2 = await step2(ctx1);\n *\n * ctx2 // Has type { foo: string, bar: number, baz: \"baz\" }\n * ```\n */\nexport type CliStep<In extends object, Out> = <Ctx extends In>(\n\tctx: Ctx\n) => Promise<Ctx & Out>;\n\n/**\n * Wrapper to exit the process if the user presses CTRL+C.\n */\nexport const prompt: typeof consola.prompt = async (message, options) => {\n\tconst response = await consola.prompt(message, options);\n\tif (response?.toString() === \"Symbol(clack:cancel)\") {\n\t\tprocess.exit(0);\n\t}\n\treturn response;\n};\n\nexport const promptSelection = async <T extends string>(\n\tmessage: string,\n\toptions: { initial?: T; options: { label: string; value: T }[] } = {\n\t\toptions: [],\n\t}\n): Promise<T> => {\n\treturn prompt(message, {\n\t\ttype: \"select\",\n\t\t...options,\n\t}) as unknown as Promise<T>;\n};\n\n/**\n * A path relative to `root` with forward slashes and without a leading `./`,\n * for messages and package.json scripts.\n *\n * @example\n * toRelativeDisplayPath(\"/app\", \"./project.inlang\") // \"project.inlang\"\n * toRelativeDisplayPath(\"/app\", \"/app/src/paraglide\") // \"src/paraglide\"\n */\nexport function toRelativeDisplayPath(root: string, path: string): string {\n\treturn nodePath\n\t\t.relative(root, nodePath.resolve(root, path))\n\t\t.split(nodePath.sep)\n\t\t.join(\"/\");\n}\n"]}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import type { Declaration, FunctionReference } from "@inlang/sdk";
|
|
2
2
|
export declare function isRegistryFunction(name: string): boolean;
|
|
3
3
|
export declare function registryFunctionNamesForDisplay(): string;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the value unformatted, and warns once per formatter name.
|
|
6
|
+
*
|
|
7
|
+
* Unknown annotations, on pattern expressions and on local variables, fall
|
|
8
|
+
* back to plain interpolation to avoid breaking compilation of messages
|
|
9
|
+
* imported from other i18n libraries (e.g. i18next's `{{value, customFormat}}`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function ignoreUnknownFormatter(name: string, value: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* The names of the registry functions a message calls, collected while it is
|
|
14
|
+
* compiled. The output decides from it whether to import the registry.
|
|
15
|
+
*/
|
|
16
|
+
export type RegistryUsage = Set<string>;
|
|
4
17
|
/**
|
|
5
18
|
* Wraps a compiled expression value in a `registry.*` call if an
|
|
6
19
|
* annotation is present.
|
|
@@ -9,4 +22,38 @@ export declare function registryFunctionNamesForDisplay(): string;
|
|
|
9
22
|
* compileAnnotation("i?.count", "en", { type: "function-reference", name: "number", options: [] })
|
|
10
23
|
* >> 'registry.number("en", i?.count, {})'
|
|
11
24
|
*/
|
|
12
|
-
export declare function compileAnnotation(str: string, locale: string, annotation?: FunctionReference, declarations?: Declaration[]): string;
|
|
25
|
+
export declare function compileAnnotation(str: string, locale: string, annotation?: FunctionReference, declarations?: Declaration[], registryUsage?: RegistryUsage): string;
|
|
26
|
+
/**
|
|
27
|
+
* Translates the ICU MessageFormat 1 `style` of an annotation to the options
|
|
28
|
+
* of the registry function.
|
|
29
|
+
*
|
|
30
|
+
* The ICU1 plugin imports `{n, number, integer}` as `{$n :number style=integer}`
|
|
31
|
+
* and `{d, date, short}` as `{$d :date style=short}`. Intl knows the number
|
|
32
|
+
* styles "decimal", "percent", "currency" (with a `currency`) and "unit", and
|
|
33
|
+
* throws for others. The date and time styles are Intl's `dateStyle` and
|
|
34
|
+
* `timeStyle`. A style without an Intl equivalent, like an ICU skeleton
|
|
35
|
+
* (`::currency/EUR`), is left out with a warning.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* icuStyleAnnotation({ name: "date", options: [{ name: "style", value: "short" }] })
|
|
39
|
+
* >> { name: "date", options: [{ name: "dateStyle", value: "short" }] }
|
|
40
|
+
*/
|
|
41
|
+
export declare function icuStyleAnnotation(annotation: FunctionReference): FunctionReference;
|
|
42
|
+
/**
|
|
43
|
+
* Adds the default styles of `date`, `time` and `datetime` when the options
|
|
44
|
+
* pick no fields. Options like `timeZone` or `hour12` are kept.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* withDefaultDateTimeStyles({ name: "datetime", options: [] })
|
|
48
|
+
* >> { name: "datetime", options: [{ name: "dateStyle", value: "medium" }, { name: "timeStyle", value: "short" }] }
|
|
49
|
+
*/
|
|
50
|
+
export declare function withDefaultDateTimeStyles(annotation: FunctionReference): FunctionReference;
|
|
51
|
+
/**
|
|
52
|
+
* Returns the names of the variables the compiled options of an annotation
|
|
53
|
+
* read.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // {$date :relativetime unit=$unit}
|
|
57
|
+
* annotationVariableReferences(annotation) // ["unit"]
|
|
58
|
+
*/
|
|
59
|
+
export declare function annotationVariableReferences(annotation: FunctionReference): string[];
|
|
@@ -1,21 +1,55 @@
|
|
|
1
1
|
import { compileVariableAccess } from "./variable-access.js";
|
|
2
2
|
import { escapeForDoubleQuoteString } from "../services/codegen/escape.js";
|
|
3
|
+
import { Logger } from "../services/logger/index.js";
|
|
3
4
|
/**
|
|
4
|
-
* The functions shipped in the generated registry.js file
|
|
5
|
+
* The functions shipped in the generated registry.js file, by the annotation
|
|
6
|
+
* name that calls them.
|
|
5
7
|
*
|
|
6
8
|
* @see createRegistry()
|
|
7
9
|
*/
|
|
8
|
-
const
|
|
9
|
-
"plural",
|
|
10
|
-
"number",
|
|
11
|
-
"datetime",
|
|
12
|
-
"relativetime",
|
|
10
|
+
const registryFunctionByAnnotation = new Map([
|
|
11
|
+
["plural", "plural"],
|
|
12
|
+
["number", "number"],
|
|
13
|
+
["datetime", "datetime"],
|
|
14
|
+
["relativetime", "relativetime"],
|
|
15
|
+
// `#` in ICU MessageFormat 1 plurals, as imported by the ICU1 plugin
|
|
16
|
+
["icu:pound", "icuPound"],
|
|
17
|
+
// `{d, date, short}` and `{d, time, short}` in ICU MessageFormat 1, as
|
|
18
|
+
// imported by the ICU1 plugin, see icuStyleAnnotation()
|
|
19
|
+
["date", "datetime"],
|
|
20
|
+
["time", "datetime"],
|
|
13
21
|
]);
|
|
22
|
+
/**
|
|
23
|
+
* The formatter names listed in warnings: the annotation names that call a
|
|
24
|
+
* registry function.
|
|
25
|
+
*/
|
|
26
|
+
const displayedRegistryFunctions = Array.from(registryFunctionByAnnotation.keys());
|
|
14
27
|
export function isRegistryFunction(name) {
|
|
15
|
-
return
|
|
28
|
+
return registryFunctionByAnnotation.has(name);
|
|
16
29
|
}
|
|
17
30
|
export function registryFunctionNamesForDisplay() {
|
|
18
|
-
return
|
|
31
|
+
return displayedRegistryFunctions.join(", ");
|
|
32
|
+
}
|
|
33
|
+
const logger = new Logger();
|
|
34
|
+
/**
|
|
35
|
+
* Tracks annotation names that have already been warned about to avoid
|
|
36
|
+
* spamming the console when the same unsupported formatter is used in
|
|
37
|
+
* many messages (or across watch-mode recompiles).
|
|
38
|
+
*/
|
|
39
|
+
const warnedUnsupportedAnnotations = new Set();
|
|
40
|
+
/**
|
|
41
|
+
* Returns the value unformatted, and warns once per formatter name.
|
|
42
|
+
*
|
|
43
|
+
* Unknown annotations, on pattern expressions and on local variables, fall
|
|
44
|
+
* back to plain interpolation to avoid breaking compilation of messages
|
|
45
|
+
* imported from other i18n libraries (e.g. i18next's `{{value, customFormat}}`).
|
|
46
|
+
*/
|
|
47
|
+
export function ignoreUnknownFormatter(name, value) {
|
|
48
|
+
if (!warnedUnsupportedAnnotations.has(name)) {
|
|
49
|
+
warnedUnsupportedAnnotations.add(name);
|
|
50
|
+
logger.warn(`The formatter "${name}" is unknown and will be ignored. The value is interpolated without formatting. Supported formatters: ${registryFunctionNamesForDisplay()}.`);
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
19
53
|
}
|
|
20
54
|
/**
|
|
21
55
|
* Wraps a compiled expression value in a `registry.*` call if an
|
|
@@ -25,14 +59,186 @@ export function registryFunctionNamesForDisplay() {
|
|
|
25
59
|
* compileAnnotation("i?.count", "en", { type: "function-reference", name: "number", options: [] })
|
|
26
60
|
* >> 'registry.number("en", i?.count, {})'
|
|
27
61
|
*/
|
|
28
|
-
export function compileAnnotation(str, locale, annotation, declarations) {
|
|
62
|
+
export function compileAnnotation(str, locale, annotation, declarations, registryUsage) {
|
|
29
63
|
if (!annotation) {
|
|
30
64
|
return str;
|
|
31
65
|
}
|
|
32
66
|
if (annotation.name === "relativetime") {
|
|
33
67
|
validateRelativeTimeOptions(annotation);
|
|
34
68
|
}
|
|
35
|
-
|
|
69
|
+
if (offsetAnnotations.has(annotation.name)) {
|
|
70
|
+
validateOffsetOptions(annotation);
|
|
71
|
+
}
|
|
72
|
+
const functionName = registryFunctionByAnnotation.get(annotation.name) ?? annotation.name;
|
|
73
|
+
registryUsage?.add(functionName);
|
|
74
|
+
const options = withDefaultDateTimeStyles(icuStyleAnnotation(annotation)).options;
|
|
75
|
+
// the options of `date` and `time` are those of `datetime`
|
|
76
|
+
const optionsOf = functionName === "datetime" ? "datetime" : annotation.name;
|
|
77
|
+
return `registry.${functionName}("${locale}", ${str}, ${compileOptions(optionsOf, options, declarations)})`;
|
|
78
|
+
}
|
|
79
|
+
const icuDateTimeStyles = new Set(["short", "medium", "long", "full"]);
|
|
80
|
+
const intlNumberStyles = new Set(["decimal", "percent", "currency", "unit"]);
|
|
81
|
+
/**
|
|
82
|
+
* Translates the ICU MessageFormat 1 `style` of an annotation to the options
|
|
83
|
+
* of the registry function.
|
|
84
|
+
*
|
|
85
|
+
* The ICU1 plugin imports `{n, number, integer}` as `{$n :number style=integer}`
|
|
86
|
+
* and `{d, date, short}` as `{$d :date style=short}`. Intl knows the number
|
|
87
|
+
* styles "decimal", "percent", "currency" (with a `currency`) and "unit", and
|
|
88
|
+
* throws for others. The date and time styles are Intl's `dateStyle` and
|
|
89
|
+
* `timeStyle`. A style without an Intl equivalent, like an ICU skeleton
|
|
90
|
+
* (`::currency/EUR`), is left out with a warning.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* icuStyleAnnotation({ name: "date", options: [{ name: "style", value: "short" }] })
|
|
94
|
+
* >> { name: "date", options: [{ name: "dateStyle", value: "short" }] }
|
|
95
|
+
*/
|
|
96
|
+
export function icuStyleAnnotation(annotation) {
|
|
97
|
+
const style = annotation.options.find((option) => option.name === "style");
|
|
98
|
+
const others = annotation.options.filter((option) => option !== style);
|
|
99
|
+
const literal = (name, value) => ({
|
|
100
|
+
name,
|
|
101
|
+
value: { type: "literal", value },
|
|
102
|
+
});
|
|
103
|
+
if (annotation.name === "date" || annotation.name === "time") {
|
|
104
|
+
const optionName = annotation.name === "date" ? "dateStyle" : "timeStyle";
|
|
105
|
+
if (style?.value.type === "literal") {
|
|
106
|
+
if (icuDateTimeStyles.has(style.value.value)) {
|
|
107
|
+
return {
|
|
108
|
+
...annotation,
|
|
109
|
+
options: [literal(optionName, style.value.value), ...others],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
ignoreUnknownStyle(annotation.name, style.value.value);
|
|
113
|
+
}
|
|
114
|
+
else if (style) {
|
|
115
|
+
return {
|
|
116
|
+
...annotation,
|
|
117
|
+
options: [{ name: optionName, value: style.value }, ...others],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// without a style, withDefaultDateTimeStyles() applies the default
|
|
121
|
+
return { ...annotation, options: others };
|
|
122
|
+
}
|
|
123
|
+
if (annotation.name === "number" && style?.value.type === "literal") {
|
|
124
|
+
const value = style.value.value;
|
|
125
|
+
if (value === "integer") {
|
|
126
|
+
const hasFractionDigits = others.some((option) => option.name === "maximumFractionDigits");
|
|
127
|
+
return {
|
|
128
|
+
...annotation,
|
|
129
|
+
options: hasFractionDigits
|
|
130
|
+
? others
|
|
131
|
+
: [literal("maximumFractionDigits", "0"), ...others],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const hasCurrency = others.some((option) => option.name === "currency");
|
|
135
|
+
if (!intlNumberStyles.has(value) ||
|
|
136
|
+
(value === "currency" && !hasCurrency)) {
|
|
137
|
+
ignoreUnknownStyle(annotation.name, value);
|
|
138
|
+
return { ...annotation, options: others };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return annotation;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The `Intl.DateTimeFormat` options that pick which parts of a date are shown.
|
|
145
|
+
* Without any of them, Intl shows only the numeric date, e.g. "10/9/2026".
|
|
146
|
+
* `dateStyle` and `timeStyle` cannot be combined with the others: Intl throws.
|
|
147
|
+
*/
|
|
148
|
+
const dateTimeFieldOptions = new Set([
|
|
149
|
+
"dateStyle",
|
|
150
|
+
"timeStyle",
|
|
151
|
+
"weekday",
|
|
152
|
+
"era",
|
|
153
|
+
"year",
|
|
154
|
+
"month",
|
|
155
|
+
"day",
|
|
156
|
+
"dayPeriod",
|
|
157
|
+
"hour",
|
|
158
|
+
"minute",
|
|
159
|
+
"second",
|
|
160
|
+
"fractionalSecondDigits",
|
|
161
|
+
"timeZoneName",
|
|
162
|
+
]);
|
|
163
|
+
/**
|
|
164
|
+
* The styles a date formatter uses when its options pick no fields.
|
|
165
|
+
*
|
|
166
|
+
* - `date`: MessageFormat 2 (LDML 47 `:date` `style=medium`) and ICU
|
|
167
|
+
* MessageFormat 1 (`{d, date}`) both default to "medium", e.g. "Oct 9, 2026".
|
|
168
|
+
* - `time`: ICU MessageFormat 1 `{d, time}` defaults to "medium", e.g.
|
|
169
|
+
* "4:30:00 PM", while MessageFormat 2 (LDML 47 `:time`) defaults to "short".
|
|
170
|
+
* `{$d :time}` is what the ICU1 plugin imports `{d, time}` as, so it keeps
|
|
171
|
+
* ICU's default. Write `{$d :time style=short}` for MessageFormat 2's.
|
|
172
|
+
* - `datetime`: MessageFormat 2 (LDML 47 `:datetime`) defaults to
|
|
173
|
+
* `dateStyle=medium timeStyle=short`, e.g. "Oct 9, 2026, 4:30 PM".
|
|
174
|
+
*/
|
|
175
|
+
const defaultDateTimeStyles = new Map([
|
|
176
|
+
["date", [["dateStyle", "medium"]]],
|
|
177
|
+
["time", [["timeStyle", "medium"]]],
|
|
178
|
+
[
|
|
179
|
+
"datetime",
|
|
180
|
+
[
|
|
181
|
+
["dateStyle", "medium"],
|
|
182
|
+
["timeStyle", "short"],
|
|
183
|
+
],
|
|
184
|
+
],
|
|
185
|
+
]);
|
|
186
|
+
/**
|
|
187
|
+
* Adds the default styles of `date`, `time` and `datetime` when the options
|
|
188
|
+
* pick no fields. Options like `timeZone` or `hour12` are kept.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* withDefaultDateTimeStyles({ name: "datetime", options: [] })
|
|
192
|
+
* >> { name: "datetime", options: [{ name: "dateStyle", value: "medium" }, { name: "timeStyle", value: "short" }] }
|
|
193
|
+
*/
|
|
194
|
+
export function withDefaultDateTimeStyles(annotation) {
|
|
195
|
+
const defaults = defaultDateTimeStyles.get(annotation.name);
|
|
196
|
+
if (!defaults ||
|
|
197
|
+
annotation.options.some((option) => dateTimeFieldOptions.has(option.name))) {
|
|
198
|
+
return annotation;
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
...annotation,
|
|
202
|
+
options: [
|
|
203
|
+
...defaults.map(([name, value]) => ({
|
|
204
|
+
name,
|
|
205
|
+
value: { type: "literal", value },
|
|
206
|
+
})),
|
|
207
|
+
...annotation.options,
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const warnedUnknownStyles = new Set();
|
|
212
|
+
function ignoreUnknownStyle(name, style) {
|
|
213
|
+
const key = `${name} ${style}`;
|
|
214
|
+
if (warnedUnknownStyles.has(key))
|
|
215
|
+
return;
|
|
216
|
+
warnedUnknownStyles.add(key);
|
|
217
|
+
logger.warn(`The style "${style}" of the formatter "${name}" is not supported and will be ignored.${name === "number" && style === "currency"
|
|
218
|
+
? ' The "currency" style needs a "currency" option.'
|
|
219
|
+
: ""}`);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Returns the names of the variables the compiled options of an annotation
|
|
223
|
+
* read.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* // {$date :relativetime unit=$unit}
|
|
227
|
+
* annotationVariableReferences(annotation) // ["unit"]
|
|
228
|
+
*/
|
|
229
|
+
export function annotationVariableReferences(annotation) {
|
|
230
|
+
const names = [];
|
|
231
|
+
for (const option of annotation.options) {
|
|
232
|
+
if (option.value.type === "variable-reference") {
|
|
233
|
+
names.push(option.value.name);
|
|
234
|
+
}
|
|
235
|
+
else if (annotation.name === "relativetime" &&
|
|
236
|
+
option.name === "unit" &&
|
|
237
|
+
isDollarVariableReference(option.value.value)) {
|
|
238
|
+
names.push(option.value.value.slice(1));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return names;
|
|
36
242
|
}
|
|
37
243
|
function compileOptions(annotationName, options, declarations) {
|
|
38
244
|
if (options.length === 0) {
|
|
@@ -83,6 +289,10 @@ function compileOptionLiteralOrVarRef(annotationName, optionName, value, declara
|
|
|
83
289
|
if (shouldEmitBooleanLiteral(annotationName, optionName, value.value)) {
|
|
84
290
|
return value.value;
|
|
85
291
|
}
|
|
292
|
+
if (offsetAnnotations.has(annotationName) && optionName === "offset") {
|
|
293
|
+
// validated by validateOffsetOptions()
|
|
294
|
+
return String(Number(value.value));
|
|
295
|
+
}
|
|
86
296
|
return `"${escapeForDoubleQuoteString(value.value)}"`;
|
|
87
297
|
}
|
|
88
298
|
function shouldEmitNumberLiteral(annotationName, optionName, literal) {
|
|
@@ -130,6 +340,24 @@ function validateRelativeTimeOptions(annotation) {
|
|
|
130
340
|
throw new Error(`Invalid "relativetime" unit "${unitOption.value.value}". Expected one of: ${Array.from(relativeTimeUnits).join(", ")}.`);
|
|
131
341
|
}
|
|
132
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Annotations with an ICU MessageFormat 1 plural `offset` option.
|
|
345
|
+
*
|
|
346
|
+
* `{count, plural, offset:1 …}` imports as `{$count :plural offset=1}`, and
|
|
347
|
+
* `#` inside it as `{$count :icu:pound offset=1}`. The registry subtracts the
|
|
348
|
+
* offset from the input, so it has to be a number.
|
|
349
|
+
*/
|
|
350
|
+
const offsetAnnotations = new Set(["plural", "icu:pound"]);
|
|
351
|
+
const offsetPattern = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
352
|
+
function validateOffsetOptions(annotation) {
|
|
353
|
+
for (const option of annotation.options) {
|
|
354
|
+
if (option.name === "offset" &&
|
|
355
|
+
option.value.type === "literal" &&
|
|
356
|
+
!offsetPattern.test(option.value.value)) {
|
|
357
|
+
throw new Error(`Invalid "${annotation.name}" offset "${option.value.value}". Expected a number.`);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
133
361
|
function isDollarVariableReference(value) {
|
|
134
362
|
return value.startsWith("$") && value.length > 1;
|
|
135
363
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-annotation.js","sourceRoot":"","sources":["../../src/compiler/compile-annotation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tDeclaration,\n\tFunctionReference,\n\tLiteral,\n\tVariableReference,\n} from \"@inlang/sdk\";\nimport { compileVariableAccess } from \"./variable-access.js\";\nimport { escapeForDoubleQuoteString } from \"../services/codegen/escape.js\";\n\n/**\n * The functions shipped in the generated registry.js file.\n *\n * @see createRegistry()\n */\nconst registryFunctionNames = new Set([\n\t\"plural\",\n\t\"number\",\n\t\"datetime\",\n\t\"relativetime\",\n]);\n\nexport function isRegistryFunction(name: string): boolean {\n\treturn registryFunctionNames.has(name);\n}\n\nexport function registryFunctionNamesForDisplay(): string {\n\treturn Array.from(registryFunctionNames).join(\", \");\n}\n\n/**\n * Wraps a compiled expression value in a `registry.*` call if an\n * annotation is present.\n *\n * @example\n * compileAnnotation(\"i?.count\", \"en\", { type: \"function-reference\", name: \"number\", options: [] })\n * >> 'registry.number(\"en\", i?.count, {})'\n */\nexport function compileAnnotation(\n\tstr: string,\n\tlocale: string,\n\tannotation?: FunctionReference,\n\tdeclarations?: Declaration[]\n): string {\n\tif (!annotation) {\n\t\treturn str;\n\t}\n\tif (annotation.name === \"relativetime\") {\n\t\tvalidateRelativeTimeOptions(annotation);\n\t}\n\treturn `registry.${annotation.name}(\"${locale}\", ${str}, ${compileOptions(annotation.name, annotation.options, declarations)})`;\n}\n\nfunction compileOptions(\n\tannotationName: string,\n\toptions: FunctionReference[\"options\"],\n\tdeclarations?: Declaration[]\n): string {\n\tif (options.length === 0) {\n\t\treturn \"{}\";\n\t}\n\tconst entries: string[] = options.map(\n\t\t(option) =>\n\t\t\t`${option.name}: ${compileOptionLiteralOrVarRef(\n\t\t\t\tannotationName,\n\t\t\t\toption.name,\n\t\t\t\toption.value,\n\t\t\t\tdeclarations\n\t\t\t)}`\n\t);\n\tconst code = \"{ \" + entries.join(\", \") + \" }\";\n\n\treturn code;\n}\n\nconst numericOptionNamesByAnnotation: Record<string, ReadonlySet<string>> = {\n\tnumber: new Set([\n\t\t\"minimumIntegerDigits\",\n\t\t\"minimumFractionDigits\",\n\t\t\"maximumFractionDigits\",\n\t\t\"minimumSignificantDigits\",\n\t\t\"maximumSignificantDigits\",\n\t\t\"roundingIncrement\",\n\t]),\n\tplural: new Set([\n\t\t\"minimumIntegerDigits\",\n\t\t\"minimumFractionDigits\",\n\t\t\"maximumFractionDigits\",\n\t\t\"minimumSignificantDigits\",\n\t\t\"maximumSignificantDigits\",\n\t]),\n\tdatetime: new Set([\"fractionalSecondDigits\"]),\n};\n\nconst booleanOptionNamesByAnnotation: Record<string, ReadonlySet<string>> = {\n\tnumber: new Set([\"useGrouping\"]),\n\tdatetime: new Set([\"hour12\"]),\n};\n\nconst jsNonNegativeIntegerPattern = /^(?:0|[1-9]\\d*)$/;\n\nfunction compileOptionLiteralOrVarRef(\n\tannotationName: string,\n\toptionName: string,\n\tvalue: Literal | VariableReference,\n\tdeclarations?: Declaration[]\n): string {\n\tif (value.type === \"variable-reference\") {\n\t\tif (annotationName === \"relativetime\" && optionName === \"unit\") {\n\t\t\treturn `/** @type {import(\"../registry.js\").RelativeTimeFormatUnit} */ (${compileVariableAccess(value.name, declarations)})`;\n\t\t}\n\t\treturn compileVariableAccess(value.name, declarations);\n\t}\n\n\tif (\n\t\tannotationName === \"relativetime\" &&\n\t\toptionName === \"unit\" &&\n\t\tisDollarVariableReference(value.value)\n\t) {\n\t\treturn `/** @type {import(\"../registry.js\").RelativeTimeFormatUnit} */ (${compileVariableAccess(value.value.slice(1), declarations)})`;\n\t}\n\n\tif (shouldEmitNumberLiteral(annotationName, optionName, value.value)) {\n\t\treturn value.value;\n\t}\n\n\tif (shouldEmitBooleanLiteral(annotationName, optionName, value.value)) {\n\t\treturn value.value;\n\t}\n\n\treturn `\"${escapeForDoubleQuoteString(value.value)}\"`;\n}\n\nfunction shouldEmitNumberLiteral(\n\tannotationName: string,\n\toptionName: string,\n\tliteral: string\n): boolean {\n\treturn (\n\t\tnumericOptionNamesByAnnotation[annotationName]?.has(optionName) === true &&\n\t\tjsNonNegativeIntegerPattern.test(literal)\n\t);\n}\n\nfunction shouldEmitBooleanLiteral(\n\tannotationName: string,\n\toptionName: string,\n\tliteral: string\n): boolean {\n\treturn (\n\t\tbooleanOptionNamesByAnnotation[annotationName]?.has(optionName) === true &&\n\t\t(literal === \"true\" || literal === \"false\")\n\t);\n}\n\nconst relativeTimeUnits = new Set([\n\t\"year\",\n\t\"years\",\n\t\"quarter\",\n\t\"quarters\",\n\t\"month\",\n\t\"months\",\n\t\"week\",\n\t\"weeks\",\n\t\"day\",\n\t\"days\",\n\t\"hour\",\n\t\"hours\",\n\t\"minute\",\n\t\"minutes\",\n\t\"second\",\n\t\"seconds\",\n]);\n\nfunction validateRelativeTimeOptions(annotation: FunctionReference): void {\n\tconst unitOptions = annotation.options.filter(\n\t\t(option) => option.name === \"unit\"\n\t);\n\n\tif (unitOptions.length === 0) {\n\t\tthrow new Error('The \"relativetime\" formatter requires a \"unit\" option.');\n\t}\n\n\tif (unitOptions.length > 1) {\n\t\tthrow new Error(\n\t\t\t'The \"relativetime\" formatter requires exactly one \"unit\" option.'\n\t\t);\n\t}\n\n\tconst [unitOption] = unitOptions;\n\tif (!unitOption || unitOption.value.type === \"variable-reference\") {\n\t\treturn;\n\t}\n\n\tif (isDollarVariableReference(unitOption.value.value)) {\n\t\treturn;\n\t}\n\n\tif (!relativeTimeUnits.has(unitOption.value.value)) {\n\t\tthrow new Error(\n\t\t\t`Invalid \"relativetime\" unit \"${unitOption.value.value}\". Expected one of: ${Array.from(\n\t\t\t\trelativeTimeUnits\n\t\t\t).join(\", \")}.`\n\t\t);\n\t}\n}\n\nfunction isDollarVariableReference(value: string): boolean {\n\treturn value.startsWith(\"$\") && value.length > 1;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"compile-annotation.js","sourceRoot":"","sources":["../../src/compiler/compile-annotation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tDeclaration,\n\tFunctionReference,\n\tLiteral,\n\tVariableReference,\n} from \"@inlang/sdk\";\nimport { compileVariableAccess } from \"./variable-access.js\";\nimport { escapeForDoubleQuoteString } from \"../services/codegen/escape.js\";\nimport { Logger } from \"../services/logger/index.js\";\n\n/**\n * The functions shipped in the generated registry.js file, by the annotation\n * name that calls them.\n *\n * @see createRegistry()\n */\nconst registryFunctionByAnnotation = new Map([\n\t[\"plural\", \"plural\"],\n\t[\"number\", \"number\"],\n\t[\"datetime\", \"datetime\"],\n\t[\"relativetime\", \"relativetime\"],\n\t// `#` in ICU MessageFormat 1 plurals, as imported by the ICU1 plugin\n\t[\"icu:pound\", \"icuPound\"],\n\t// `{d, date, short}` and `{d, time, short}` in ICU MessageFormat 1, as\n\t// imported by the ICU1 plugin, see icuStyleAnnotation()\n\t[\"date\", \"datetime\"],\n\t[\"time\", \"datetime\"],\n]);\n\n/**\n * The formatter names listed in warnings: the annotation names that call a\n * registry function.\n */\nconst displayedRegistryFunctions = Array.from(\n\tregistryFunctionByAnnotation.keys()\n);\n\nexport function isRegistryFunction(name: string): boolean {\n\treturn registryFunctionByAnnotation.has(name);\n}\n\nexport function registryFunctionNamesForDisplay(): string {\n\treturn displayedRegistryFunctions.join(\", \");\n}\n\nconst logger = new Logger();\n\n/**\n * Tracks annotation names that have already been warned about to avoid\n * spamming the console when the same unsupported formatter is used in\n * many messages (or across watch-mode recompiles).\n */\nconst warnedUnsupportedAnnotations = new Set<string>();\n\n/**\n * Returns the value unformatted, and warns once per formatter name.\n *\n * Unknown annotations, on pattern expressions and on local variables, fall\n * back to plain interpolation to avoid breaking compilation of messages\n * imported from other i18n libraries (e.g. i18next's `{{value, customFormat}}`).\n */\nexport function ignoreUnknownFormatter(name: string, value: string): string {\n\tif (!warnedUnsupportedAnnotations.has(name)) {\n\t\twarnedUnsupportedAnnotations.add(name);\n\t\tlogger.warn(\n\t\t\t`The formatter \"${name}\" is unknown and will be ignored. The value is interpolated without formatting. Supported formatters: ${registryFunctionNamesForDisplay()}.`\n\t\t);\n\t}\n\treturn value;\n}\n\n/**\n * The names of the registry functions a message calls, collected while it is\n * compiled. The output decides from it whether to import the registry.\n */\nexport type RegistryUsage = Set<string>;\n\n/**\n * Wraps a compiled expression value in a `registry.*` call if an\n * annotation is present.\n *\n * @example\n * compileAnnotation(\"i?.count\", \"en\", { type: \"function-reference\", name: \"number\", options: [] })\n * >> 'registry.number(\"en\", i?.count, {})'\n */\nexport function compileAnnotation(\n\tstr: string,\n\tlocale: string,\n\tannotation?: FunctionReference,\n\tdeclarations?: Declaration[],\n\tregistryUsage?: RegistryUsage\n): string {\n\tif (!annotation) {\n\t\treturn str;\n\t}\n\tif (annotation.name === \"relativetime\") {\n\t\tvalidateRelativeTimeOptions(annotation);\n\t}\n\tif (offsetAnnotations.has(annotation.name)) {\n\t\tvalidateOffsetOptions(annotation);\n\t}\n\tconst functionName =\n\t\tregistryFunctionByAnnotation.get(annotation.name) ?? annotation.name;\n\tregistryUsage?.add(functionName);\n\tconst options = withDefaultDateTimeStyles(\n\t\ticuStyleAnnotation(annotation)\n\t).options;\n\t// the options of `date` and `time` are those of `datetime`\n\tconst optionsOf = functionName === \"datetime\" ? \"datetime\" : annotation.name;\n\treturn `registry.${functionName}(\"${locale}\", ${str}, ${compileOptions(optionsOf, options, declarations)})`;\n}\n\nconst icuDateTimeStyles = new Set([\"short\", \"medium\", \"long\", \"full\"]);\n\nconst intlNumberStyles = new Set([\"decimal\", \"percent\", \"currency\", \"unit\"]);\n\n/**\n * Translates the ICU MessageFormat 1 `style` of an annotation to the options\n * of the registry function.\n *\n * The ICU1 plugin imports `{n, number, integer}` as `{$n :number style=integer}`\n * and `{d, date, short}` as `{$d :date style=short}`. Intl knows the number\n * styles \"decimal\", \"percent\", \"currency\" (with a `currency`) and \"unit\", and\n * throws for others. The date and time styles are Intl's `dateStyle` and\n * `timeStyle`. A style without an Intl equivalent, like an ICU skeleton\n * (`::currency/EUR`), is left out with a warning.\n *\n * @example\n * icuStyleAnnotation({ name: \"date\", options: [{ name: \"style\", value: \"short\" }] })\n * >> { name: \"date\", options: [{ name: \"dateStyle\", value: \"short\" }] }\n */\nexport function icuStyleAnnotation(\n\tannotation: FunctionReference\n): FunctionReference {\n\tconst style = annotation.options.find((option) => option.name === \"style\");\n\tconst others = annotation.options.filter((option) => option !== style);\n\tconst literal = (name: string, value: string) => ({\n\t\tname,\n\t\tvalue: { type: \"literal\" as const, value },\n\t});\n\n\tif (annotation.name === \"date\" || annotation.name === \"time\") {\n\t\tconst optionName = annotation.name === \"date\" ? \"dateStyle\" : \"timeStyle\";\n\t\tif (style?.value.type === \"literal\") {\n\t\t\tif (icuDateTimeStyles.has(style.value.value)) {\n\t\t\t\treturn {\n\t\t\t\t\t...annotation,\n\t\t\t\t\toptions: [literal(optionName, style.value.value), ...others],\n\t\t\t\t};\n\t\t\t}\n\t\t\tignoreUnknownStyle(annotation.name, style.value.value);\n\t\t} else if (style) {\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\toptions: [{ name: optionName, value: style.value }, ...others],\n\t\t\t};\n\t\t}\n\t\t// without a style, withDefaultDateTimeStyles() applies the default\n\t\treturn { ...annotation, options: others };\n\t}\n\n\tif (annotation.name === \"number\" && style?.value.type === \"literal\") {\n\t\tconst value = style.value.value;\n\t\tif (value === \"integer\") {\n\t\t\tconst hasFractionDigits = others.some(\n\t\t\t\t(option) => option.name === \"maximumFractionDigits\"\n\t\t\t);\n\t\t\treturn {\n\t\t\t\t...annotation,\n\t\t\t\toptions: hasFractionDigits\n\t\t\t\t\t? others\n\t\t\t\t\t: [literal(\"maximumFractionDigits\", \"0\"), ...others],\n\t\t\t};\n\t\t}\n\t\tconst hasCurrency = others.some((option) => option.name === \"currency\");\n\t\tif (\n\t\t\t!intlNumberStyles.has(value) ||\n\t\t\t(value === \"currency\" && !hasCurrency)\n\t\t) {\n\t\t\tignoreUnknownStyle(annotation.name, value);\n\t\t\treturn { ...annotation, options: others };\n\t\t}\n\t}\n\n\treturn annotation;\n}\n\n/**\n * The `Intl.DateTimeFormat` options that pick which parts of a date are shown.\n * Without any of them, Intl shows only the numeric date, e.g. \"10/9/2026\".\n * `dateStyle` and `timeStyle` cannot be combined with the others: Intl throws.\n */\nconst dateTimeFieldOptions = new Set([\n\t\"dateStyle\",\n\t\"timeStyle\",\n\t\"weekday\",\n\t\"era\",\n\t\"year\",\n\t\"month\",\n\t\"day\",\n\t\"dayPeriod\",\n\t\"hour\",\n\t\"minute\",\n\t\"second\",\n\t\"fractionalSecondDigits\",\n\t\"timeZoneName\",\n]);\n\n/**\n * The styles a date formatter uses when its options pick no fields.\n *\n * - `date`: MessageFormat 2 (LDML 47 `:date` `style=medium`) and ICU\n * MessageFormat 1 (`{d, date}`) both default to \"medium\", e.g. \"Oct 9, 2026\".\n * - `time`: ICU MessageFormat 1 `{d, time}` defaults to \"medium\", e.g.\n * \"4:30:00 PM\", while MessageFormat 2 (LDML 47 `:time`) defaults to \"short\".\n * `{$d :time}` is what the ICU1 plugin imports `{d, time}` as, so it keeps\n * ICU's default. Write `{$d :time style=short}` for MessageFormat 2's.\n * - `datetime`: MessageFormat 2 (LDML 47 `:datetime`) defaults to\n * `dateStyle=medium timeStyle=short`, e.g. \"Oct 9, 2026, 4:30 PM\".\n */\nconst defaultDateTimeStyles = new Map<string, Array<[string, string]>>([\n\t[\"date\", [[\"dateStyle\", \"medium\"]]],\n\t[\"time\", [[\"timeStyle\", \"medium\"]]],\n\t[\n\t\t\"datetime\",\n\t\t[\n\t\t\t[\"dateStyle\", \"medium\"],\n\t\t\t[\"timeStyle\", \"short\"],\n\t\t],\n\t],\n]);\n\n/**\n * Adds the default styles of `date`, `time` and `datetime` when the options\n * pick no fields. Options like `timeZone` or `hour12` are kept.\n *\n * @example\n * withDefaultDateTimeStyles({ name: \"datetime\", options: [] })\n * >> { name: \"datetime\", options: [{ name: \"dateStyle\", value: \"medium\" }, { name: \"timeStyle\", value: \"short\" }] }\n */\nexport function withDefaultDateTimeStyles(\n\tannotation: FunctionReference\n): FunctionReference {\n\tconst defaults = defaultDateTimeStyles.get(annotation.name);\n\tif (\n\t\t!defaults ||\n\t\tannotation.options.some((option) => dateTimeFieldOptions.has(option.name))\n\t) {\n\t\treturn annotation;\n\t}\n\treturn {\n\t\t...annotation,\n\t\toptions: [\n\t\t\t...defaults.map(([name, value]) => ({\n\t\t\t\tname,\n\t\t\t\tvalue: { type: \"literal\" as const, value },\n\t\t\t})),\n\t\t\t...annotation.options,\n\t\t],\n\t};\n}\n\nconst warnedUnknownStyles = new Set<string>();\n\nfunction ignoreUnknownStyle(name: string, style: string): void {\n\tconst key = `${name} ${style}`;\n\tif (warnedUnknownStyles.has(key)) return;\n\twarnedUnknownStyles.add(key);\n\tlogger.warn(\n\t\t`The style \"${style}\" of the formatter \"${name}\" is not supported and will be ignored.${\n\t\t\tname === \"number\" && style === \"currency\"\n\t\t\t\t? ' The \"currency\" style needs a \"currency\" option.'\n\t\t\t\t: \"\"\n\t\t}`\n\t);\n}\n\n/**\n * Returns the names of the variables the compiled options of an annotation\n * read.\n *\n * @example\n * // {$date :relativetime unit=$unit}\n * annotationVariableReferences(annotation) // [\"unit\"]\n */\nexport function annotationVariableReferences(\n\tannotation: FunctionReference\n): string[] {\n\tconst names: string[] = [];\n\tfor (const option of annotation.options) {\n\t\tif (option.value.type === \"variable-reference\") {\n\t\t\tnames.push(option.value.name);\n\t\t} else if (\n\t\t\tannotation.name === \"relativetime\" &&\n\t\t\toption.name === \"unit\" &&\n\t\t\tisDollarVariableReference(option.value.value)\n\t\t) {\n\t\t\tnames.push(option.value.value.slice(1));\n\t\t}\n\t}\n\treturn names;\n}\n\nfunction compileOptions(\n\tannotationName: string,\n\toptions: FunctionReference[\"options\"],\n\tdeclarations?: Declaration[]\n): string {\n\tif (options.length === 0) {\n\t\treturn \"{}\";\n\t}\n\tconst entries: string[] = options.map(\n\t\t(option) =>\n\t\t\t`${option.name}: ${compileOptionLiteralOrVarRef(\n\t\t\t\tannotationName,\n\t\t\t\toption.name,\n\t\t\t\toption.value,\n\t\t\t\tdeclarations\n\t\t\t)}`\n\t);\n\tconst code = \"{ \" + entries.join(\", \") + \" }\";\n\n\treturn code;\n}\n\nconst numericOptionNamesByAnnotation: Record<string, ReadonlySet<string>> = {\n\tnumber: new Set([\n\t\t\"minimumIntegerDigits\",\n\t\t\"minimumFractionDigits\",\n\t\t\"maximumFractionDigits\",\n\t\t\"minimumSignificantDigits\",\n\t\t\"maximumSignificantDigits\",\n\t\t\"roundingIncrement\",\n\t]),\n\tplural: new Set([\n\t\t\"minimumIntegerDigits\",\n\t\t\"minimumFractionDigits\",\n\t\t\"maximumFractionDigits\",\n\t\t\"minimumSignificantDigits\",\n\t\t\"maximumSignificantDigits\",\n\t]),\n\tdatetime: new Set([\"fractionalSecondDigits\"]),\n};\n\nconst booleanOptionNamesByAnnotation: Record<string, ReadonlySet<string>> = {\n\tnumber: new Set([\"useGrouping\"]),\n\tdatetime: new Set([\"hour12\"]),\n};\n\nconst jsNonNegativeIntegerPattern = /^(?:0|[1-9]\\d*)$/;\n\nfunction compileOptionLiteralOrVarRef(\n\tannotationName: string,\n\toptionName: string,\n\tvalue: Literal | VariableReference,\n\tdeclarations?: Declaration[]\n): string {\n\tif (value.type === \"variable-reference\") {\n\t\tif (annotationName === \"relativetime\" && optionName === \"unit\") {\n\t\t\treturn `/** @type {import(\"../registry.js\").RelativeTimeFormatUnit} */ (${compileVariableAccess(value.name, declarations)})`;\n\t\t}\n\t\treturn compileVariableAccess(value.name, declarations);\n\t}\n\n\tif (\n\t\tannotationName === \"relativetime\" &&\n\t\toptionName === \"unit\" &&\n\t\tisDollarVariableReference(value.value)\n\t) {\n\t\treturn `/** @type {import(\"../registry.js\").RelativeTimeFormatUnit} */ (${compileVariableAccess(value.value.slice(1), declarations)})`;\n\t}\n\n\tif (shouldEmitNumberLiteral(annotationName, optionName, value.value)) {\n\t\treturn value.value;\n\t}\n\n\tif (shouldEmitBooleanLiteral(annotationName, optionName, value.value)) {\n\t\treturn value.value;\n\t}\n\n\tif (offsetAnnotations.has(annotationName) && optionName === \"offset\") {\n\t\t// validated by validateOffsetOptions()\n\t\treturn String(Number(value.value));\n\t}\n\n\treturn `\"${escapeForDoubleQuoteString(value.value)}\"`;\n}\n\nfunction shouldEmitNumberLiteral(\n\tannotationName: string,\n\toptionName: string,\n\tliteral: string\n): boolean {\n\treturn (\n\t\tnumericOptionNamesByAnnotation[annotationName]?.has(optionName) === true &&\n\t\tjsNonNegativeIntegerPattern.test(literal)\n\t);\n}\n\nfunction shouldEmitBooleanLiteral(\n\tannotationName: string,\n\toptionName: string,\n\tliteral: string\n): boolean {\n\treturn (\n\t\tbooleanOptionNamesByAnnotation[annotationName]?.has(optionName) === true &&\n\t\t(literal === \"true\" || literal === \"false\")\n\t);\n}\n\nconst relativeTimeUnits = new Set([\n\t\"year\",\n\t\"years\",\n\t\"quarter\",\n\t\"quarters\",\n\t\"month\",\n\t\"months\",\n\t\"week\",\n\t\"weeks\",\n\t\"day\",\n\t\"days\",\n\t\"hour\",\n\t\"hours\",\n\t\"minute\",\n\t\"minutes\",\n\t\"second\",\n\t\"seconds\",\n]);\n\nfunction validateRelativeTimeOptions(annotation: FunctionReference): void {\n\tconst unitOptions = annotation.options.filter(\n\t\t(option) => option.name === \"unit\"\n\t);\n\n\tif (unitOptions.length === 0) {\n\t\tthrow new Error('The \"relativetime\" formatter requires a \"unit\" option.');\n\t}\n\n\tif (unitOptions.length > 1) {\n\t\tthrow new Error(\n\t\t\t'The \"relativetime\" formatter requires exactly one \"unit\" option.'\n\t\t);\n\t}\n\n\tconst [unitOption] = unitOptions;\n\tif (!unitOption || unitOption.value.type === \"variable-reference\") {\n\t\treturn;\n\t}\n\n\tif (isDollarVariableReference(unitOption.value.value)) {\n\t\treturn;\n\t}\n\n\tif (!relativeTimeUnits.has(unitOption.value.value)) {\n\t\tthrow new Error(\n\t\t\t`Invalid \"relativetime\" unit \"${unitOption.value.value}\". Expected one of: ${Array.from(\n\t\t\t\trelativeTimeUnits\n\t\t\t).join(\", \")}.`\n\t\t);\n\t}\n}\n\n/**\n * Annotations with an ICU MessageFormat 1 plural `offset` option.\n *\n * `{count, plural, offset:1 …}` imports as `{$count :plural offset=1}`, and\n * `#` inside it as `{$count :icu:pound offset=1}`. The registry subtracts the\n * offset from the input, so it has to be a number.\n */\nconst offsetAnnotations = new Set([\"plural\", \"icu:pound\"]);\n\nconst offsetPattern = /^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$/;\n\nfunction validateOffsetOptions(annotation: FunctionReference): void {\n\tfor (const option of annotation.options) {\n\t\tif (\n\t\t\toption.name === \"offset\" &&\n\t\t\toption.value.type === \"literal\" &&\n\t\t\t!offsetPattern.test(option.value.value)\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid \"${annotation.name}\" offset \"${option.value.value}\". Expected a number.`\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction isDollarVariableReference(value: string): boolean {\n\treturn value.startsWith(\"$\") && value.length > 1;\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Bundle, BundleNested,
|
|
1
|
+
import type { Bundle, BundleNested, ProjectSettings } from "@inlang/sdk";
|
|
2
|
+
import { type CompiledMessage } from "./compile-message.js";
|
|
2
3
|
import type { Compiled } from "./types.js";
|
|
3
4
|
import { type InputMatchTypes } from "./jsdoc-types.js";
|
|
4
5
|
import type { CompilerOptions } from "./compiler-options.js";
|
|
@@ -7,7 +8,7 @@ export type CompiledBundleWithMessages = {
|
|
|
7
8
|
bundle: Compiled<Bundle>;
|
|
8
9
|
/** The compilation results for the languages */
|
|
9
10
|
messages: {
|
|
10
|
-
[locale: string]:
|
|
11
|
+
[locale: string]: CompiledMessage;
|
|
11
12
|
};
|
|
12
13
|
/** Match literal types inferred from bundle variants */
|
|
13
14
|
matchTypes: InputMatchTypes;
|
|
@@ -4,6 +4,7 @@ import { isValidIdentifier, quotePropertyKey } from "./variable-access.js";
|
|
|
4
4
|
import { toSafeModuleId } from "./safe-module-id.js";
|
|
5
5
|
import { escapeForDoubleQuoteString } from "../services/codegen/escape.js";
|
|
6
6
|
import { perLocaleBuildStaticLocaleExpression } from "./per-locale-build.js";
|
|
7
|
+
import { resolveInputAlias } from "./input-alias.js";
|
|
7
8
|
/**
|
|
8
9
|
* Compiles all the messages in the bundle and returns an index-function + each compiled message
|
|
9
10
|
*/
|
|
@@ -71,7 +72,10 @@ const compileBundleFunction = (args) => {
|
|
|
71
72
|
if (mode === "string") {
|
|
72
73
|
return `${prefix}${condition}return ${messageRef}(inputs)`;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
// A locale's message has .parts() only if its own variants have
|
|
76
|
+
// markup. Fallbacks and messages without markup are typed without
|
|
77
|
+
// it, so read it through a type that declares it optional.
|
|
78
|
+
return `${prefix}${condition}return /** @type {{ parts?: (inputs: ${inputType}) => import('../runtime.js').MessagePart[] }} */ (${messageRef}).parts?.(inputs) ?? [{ type: "text", value: ${messageRef}(inputs) }]`;
|
|
75
79
|
})
|
|
76
80
|
.join("\n");
|
|
77
81
|
const perLocaleBuild = args.experimentalStaticLocale === perLocaleBuildStaticLocaleExpression;
|
|
@@ -421,6 +425,31 @@ function collectInputMatchTypes(bundle) {
|
|
|
421
425
|
}
|
|
422
426
|
}
|
|
423
427
|
}
|
|
428
|
+
// Matches on un-annotated aliases of an input match the input value too.
|
|
429
|
+
// Widen an input type that was narrowed by direct matches: alias literals
|
|
430
|
+
// join the union and an alias catchall accepts any value. Inputs that are
|
|
431
|
+
// only matched through aliases keep their unnarrowed type.
|
|
432
|
+
const declarations = bundle.declarations ?? [];
|
|
433
|
+
for (const message of bundle.messages) {
|
|
434
|
+
for (const variant of message.variants) {
|
|
435
|
+
for (const match of variant.matches ?? []) {
|
|
436
|
+
if (inputNames.has(match.key))
|
|
437
|
+
continue;
|
|
438
|
+
const inputName = resolveInputAlias(match.key, declarations);
|
|
439
|
+
if (inputName === undefined)
|
|
440
|
+
continue;
|
|
441
|
+
const info = matchTypes.get(inputName);
|
|
442
|
+
if (!info)
|
|
443
|
+
continue;
|
|
444
|
+
if (match.type === "catchall-match") {
|
|
445
|
+
info.hasCatchAll = true;
|
|
446
|
+
}
|
|
447
|
+
else if (match.type === "literal-match") {
|
|
448
|
+
info.literals.add(match.value);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
424
453
|
return matchTypes;
|
|
425
454
|
}
|
|
426
455
|
function bundleHasMarkup(bundle) {
|