@gtkx/cli 2.0.0-beta.1 → 2.0.0-beta.10
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 +43 -40
- package/bin/gtkx-dev-runner.js +5 -1
- package/bin/gtkx.js +5 -1
- package/dist/builder.d.ts +1 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +44 -12
- package/dist/builder.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -2
- package/dist/cli.js.map +1 -1
- package/dist/codegen/config-dependencies.d.ts +3 -0
- package/dist/codegen/config-dependencies.d.ts.map +1 -0
- package/dist/codegen/config-dependencies.js +355 -0
- package/dist/codegen/config-dependencies.js.map +1 -0
- package/dist/codegen/freshness.d.ts.map +1 -1
- package/dist/codegen/freshness.js +5 -1
- package/dist/codegen/freshness.js.map +1 -1
- package/dist/codegen/reference.d.ts.map +1 -1
- package/dist/codegen/reference.js +1 -0
- package/dist/codegen/reference.js.map +1 -1
- package/dist/codegen/run-codegen.d.ts +6 -3
- package/dist/codegen/run-codegen.d.ts.map +1 -1
- package/dist/codegen/run-codegen.js +42 -18
- package/dist/codegen/run-codegen.js.map +1 -1
- package/dist/codegen/store-resolver.d.ts +3 -1
- package/dist/codegen/store-resolver.d.ts.map +1 -1
- package/dist/codegen/store-resolver.js +7 -4
- package/dist/codegen/store-resolver.js.map +1 -1
- package/dist/commands/build.d.ts +5 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +83 -10
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cleanup.d.ts +9 -0
- package/dist/commands/cleanup.d.ts.map +1 -0
- package/dist/commands/cleanup.js +42 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/codegen.d.ts +1 -0
- package/dist/commands/codegen.d.ts.map +1 -1
- package/dist/commands/codegen.js +6 -5
- package/dist/commands/codegen.js.map +1 -1
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +10 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +9 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +31 -4
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +1 -0
- package/dist/commands/docs.js.map +1 -1
- package/dist/deploy/depends.d.ts.map +1 -1
- package/dist/deploy/depends.js +24 -2
- package/dist/deploy/depends.js.map +1 -1
- package/dist/deploy/download.d.ts +7 -3
- package/dist/deploy/download.d.ts.map +1 -1
- package/dist/deploy/download.js +19 -20
- package/dist/deploy/download.js.map +1 -1
- package/dist/deploy/freedesktop/metainfo.d.ts.map +1 -1
- package/dist/deploy/freedesktop/metainfo.js +41 -2
- package/dist/deploy/freedesktop/metainfo.js.map +1 -1
- package/dist/deploy/freedesktop/validate.d.ts.map +1 -1
- package/dist/deploy/freedesktop/validate.js +58 -14
- package/dist/deploy/freedesktop/validate.js.map +1 -1
- package/dist/deploy/native-addon.d.ts +5 -0
- package/dist/deploy/native-addon.d.ts.map +1 -0
- package/dist/deploy/native-addon.js +134 -0
- package/dist/deploy/native-addon.js.map +1 -0
- package/dist/deploy/nfpm/config.d.ts +3 -2
- package/dist/deploy/nfpm/config.d.ts.map +1 -1
- package/dist/deploy/nfpm/config.js +7 -4
- package/dist/deploy/nfpm/config.js.map +1 -1
- package/dist/deploy/nfpm/contents.d.ts.map +1 -1
- package/dist/deploy/nfpm/contents.js +8 -0
- package/dist/deploy/nfpm/contents.js.map +1 -1
- package/dist/deploy/node-runtime/download.js +2 -2
- package/dist/deploy/node-runtime/download.js.map +1 -1
- package/dist/deploy/node-runtime/elf.d.ts +4 -1
- package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
- package/dist/deploy/node-runtime/elf.js +34 -5
- package/dist/deploy/node-runtime/elf.js.map +1 -1
- package/dist/deploy/node-runtime/guard.d.ts.map +1 -1
- package/dist/deploy/node-runtime/guard.js +7 -14
- package/dist/deploy/node-runtime/guard.js.map +1 -1
- package/dist/deploy/node-runtime/index.d.ts +3 -1
- package/dist/deploy/node-runtime/index.d.ts.map +1 -1
- package/dist/deploy/node-runtime/index.js +103 -10
- package/dist/deploy/node-runtime/index.js.map +1 -1
- package/dist/deploy/node-runtime/sonames.d.ts +5 -0
- package/dist/deploy/node-runtime/sonames.d.ts.map +1 -0
- package/dist/deploy/node-runtime/sonames.js +13 -0
- package/dist/deploy/node-runtime/sonames.js.map +1 -0
- package/dist/deploy/notices/node-runtime.js +2 -2
- package/dist/deploy/notices/node-runtime.js.map +1 -1
- package/dist/deploy/payload/launcher.d.ts.map +1 -1
- package/dist/deploy/payload/launcher.js +14 -1
- package/dist/deploy/payload/launcher.js.map +1 -1
- package/dist/deploy/payload/stage.d.ts +2 -1
- package/dist/deploy/payload/stage.d.ts.map +1 -1
- package/dist/deploy/payload/stage.js +46 -5
- package/dist/deploy/payload/stage.js.map +1 -1
- package/dist/deploy/run-deploy.d.ts +2 -0
- package/dist/deploy/run-deploy.d.ts.map +1 -1
- package/dist/deploy/run-deploy.js +197 -52
- package/dist/deploy/run-deploy.js.map +1 -1
- package/dist/deploy/settings/arch.d.ts +9 -3
- package/dist/deploy/settings/arch.d.ts.map +1 -1
- package/dist/deploy/settings/arch.js +27 -6
- package/dist/deploy/settings/arch.js.map +1 -1
- package/dist/deploy/settings/build-manifest.d.ts +6 -1
- package/dist/deploy/settings/build-manifest.d.ts.map +1 -1
- package/dist/deploy/settings/build-manifest.js +15 -4
- package/dist/deploy/settings/build-manifest.js.map +1 -1
- package/dist/deploy/settings/extra-files.d.ts +1 -1
- package/dist/deploy/settings/extra-files.d.ts.map +1 -1
- package/dist/deploy/settings/extra-files.js +25 -3
- package/dist/deploy/settings/extra-files.js.map +1 -1
- package/dist/deploy/settings/index.d.ts +3 -1
- package/dist/deploy/settings/index.d.ts.map +1 -1
- package/dist/deploy/settings/index.js +4 -2
- package/dist/deploy/settings/index.js.map +1 -1
- package/dist/deploy/settings/libraries.d.ts.map +1 -1
- package/dist/deploy/settings/libraries.js +2 -1
- package/dist/deploy/settings/libraries.js.map +1 -1
- package/dist/deploy/settings/paths.d.ts +4 -2
- package/dist/deploy/settings/paths.d.ts.map +1 -1
- package/dist/deploy/settings/paths.js +121 -12
- package/dist/deploy/settings/paths.js.map +1 -1
- package/dist/deploy/targets/appimage.d.ts.map +1 -1
- package/dist/deploy/targets/appimage.js +1 -0
- package/dist/deploy/targets/appimage.js.map +1 -1
- package/dist/deploy/targets/flatpak-pnpm.js +4 -4
- package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
- package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak-source.js +13 -2
- package/dist/deploy/targets/flatpak-source.js.map +1 -1
- package/dist/deploy/targets/flatpak.d.ts.map +1 -1
- package/dist/deploy/targets/flatpak.js +1 -0
- package/dist/deploy/targets/flatpak.js.map +1 -1
- package/dist/deploy/targets/nfpm-target.d.ts.map +1 -1
- package/dist/deploy/targets/nfpm-target.js +13 -7
- package/dist/deploy/targets/nfpm-target.js.map +1 -1
- package/dist/deploy/types.d.ts +5 -2
- package/dist/deploy/types.d.ts.map +1 -1
- package/dist/deploy/types.js.map +1 -1
- package/dist/deploy/vendored/appimagetool.js +2 -2
- package/dist/deploy/vendored/appimagetool.js.map +1 -1
- package/dist/deploy/vendored/nfpm.js +1 -1
- package/dist/deploy/vendored/nfpm.js.map +1 -1
- package/dist/dev/catalog-writes.d.ts +8 -0
- package/dist/dev/catalog-writes.d.ts.map +1 -0
- package/dist/dev/catalog-writes.js +26 -0
- package/dist/dev/catalog-writes.js.map +1 -0
- package/dist/dev/entry-env.d.ts +2 -1
- package/dist/dev/entry-env.d.ts.map +1 -1
- package/dist/dev/entry-env.js +2 -1
- package/dist/dev/entry-env.js.map +1 -1
- package/dist/dev/font-dir.d.ts +3 -0
- package/dist/dev/font-dir.d.ts.map +1 -0
- package/dist/dev/font-dir.js +9 -0
- package/dist/dev/font-dir.js.map +1 -0
- package/dist/dev/headless.d.ts +3 -0
- package/dist/dev/headless.d.ts.map +1 -0
- package/dist/dev/headless.js +35 -0
- package/dist/dev/headless.js.map +1 -0
- package/dist/dev/runner-deps.d.ts +1 -1
- package/dist/dev/runner-deps.d.ts.map +1 -1
- package/dist/dev/runner-deps.js +12 -7
- package/dist/dev/runner-deps.js.map +1 -1
- package/dist/dev/runner-main.d.ts.map +1 -1
- package/dist/dev/runner-main.js +10 -3
- package/dist/dev/runner-main.js.map +1 -1
- package/dist/dev/runner.d.ts +2 -0
- package/dist/dev/runner.d.ts.map +1 -1
- package/dist/dev/runner.js +26 -7
- package/dist/dev/runner.js.map +1 -1
- package/dist/dev/supervisor.d.ts +3 -1
- package/dist/dev/supervisor.d.ts.map +1 -1
- package/dist/dev/supervisor.js +132 -29
- package/dist/dev/supervisor.js.map +1 -1
- package/dist/dev/vite-dev-server.d.ts +1 -1
- package/dist/dev/vite-dev-server.d.ts.map +1 -1
- package/dist/dev/vite-dev-server.js +14 -2
- package/dist/dev/vite-dev-server.js.map +1 -1
- package/dist/dev/watch-ignore.d.ts +3 -0
- package/dist/dev/watch-ignore.d.ts.map +1 -0
- package/dist/dev/watch-ignore.js +11 -0
- package/dist/dev/watch-ignore.js.map +1 -0
- package/dist/i18n/catalogs.d.ts +6 -2
- package/dist/i18n/catalogs.d.ts.map +1 -1
- package/dist/i18n/catalogs.js +10 -7
- package/dist/i18n/catalogs.js.map +1 -1
- package/dist/i18n/source-messages.d.ts +3 -1
- package/dist/i18n/source-messages.d.ts.map +1 -1
- package/dist/i18n/source-messages.js +973 -9
- package/dist/i18n/source-messages.js.map +1 -1
- package/dist/internal/agent-rules.d.ts.map +1 -1
- package/dist/internal/agent-rules.js +7 -2
- package/dist/internal/agent-rules.js.map +1 -1
- package/dist/internal/banner.d.ts +4 -2
- package/dist/internal/banner.d.ts.map +1 -1
- package/dist/internal/banner.js +19 -5
- package/dist/internal/banner.js.map +1 -1
- package/dist/internal/build-manifest.d.ts +5 -2
- package/dist/internal/build-manifest.d.ts.map +1 -1
- package/dist/internal/build-manifest.js +15 -2
- package/dist/internal/build-manifest.js.map +1 -1
- package/dist/internal/build-output.d.ts +8 -0
- package/dist/internal/build-output.d.ts.map +1 -0
- package/dist/internal/build-output.js +116 -0
- package/dist/internal/build-output.js.map +1 -0
- package/dist/internal/cache-root.d.ts +3 -0
- package/dist/internal/cache-root.d.ts.map +1 -0
- package/dist/internal/cache-root.js +9 -0
- package/dist/internal/cache-root.js.map +1 -0
- package/dist/internal/compile-cache-store.d.ts +4 -0
- package/dist/internal/compile-cache-store.d.ts.map +1 -0
- package/dist/internal/compile-cache-store.js +41 -0
- package/dist/internal/compile-cache-store.js.map +1 -0
- package/dist/internal/compile-cache.d.ts +4 -0
- package/dist/internal/compile-cache.d.ts.map +1 -0
- package/dist/internal/compile-cache.js +16 -0
- package/dist/internal/compile-cache.js.map +1 -0
- package/dist/internal/deploy-out-dir.d.ts +4 -0
- package/dist/internal/deploy-out-dir.d.ts.map +1 -0
- package/dist/internal/deploy-out-dir.js +5 -0
- package/dist/internal/deploy-out-dir.js.map +1 -0
- package/dist/internal/docs-elements.d.ts +1 -0
- package/dist/internal/docs-elements.d.ts.map +1 -1
- package/dist/internal/docs-elements.js +5 -4
- package/dist/internal/docs-elements.js.map +1 -1
- package/dist/internal/entry-arg.d.ts +4 -1
- package/dist/internal/entry-arg.d.ts.map +1 -1
- package/dist/internal/entry-arg.js +7 -1
- package/dist/internal/entry-arg.js.map +1 -1
- package/dist/internal/errors.d.ts +2 -1
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +1 -1
- package/dist/internal/errors.js.map +1 -1
- package/dist/internal/font-path.d.ts +4 -0
- package/dist/internal/font-path.d.ts.map +1 -0
- package/dist/internal/font-path.js +12 -0
- package/dist/internal/font-path.js.map +1 -0
- package/dist/internal/font-staging.d.ts +6 -0
- package/dist/internal/font-staging.d.ts.map +1 -0
- package/dist/internal/font-staging.js +94 -0
- package/dist/internal/font-staging.js.map +1 -0
- package/dist/internal/icon-staging.d.ts +3 -0
- package/dist/internal/icon-staging.d.ts.map +1 -0
- package/dist/internal/icon-staging.js +40 -0
- package/dist/internal/icon-staging.js.map +1 -0
- package/dist/internal/import-scan.d.ts +4 -0
- package/dist/internal/import-scan.d.ts.map +1 -0
- package/dist/internal/import-scan.js +138 -0
- package/dist/internal/import-scan.js.map +1 -0
- package/dist/internal/module-hash.d.ts +3 -0
- package/dist/internal/module-hash.d.ts.map +1 -0
- package/dist/internal/module-hash.js +19 -0
- package/dist/internal/module-hash.js.map +1 -0
- package/dist/internal/output-directory.d.ts +15 -0
- package/dist/internal/output-directory.d.ts.map +1 -0
- package/dist/internal/output-directory.js +490 -0
- package/dist/internal/output-directory.js.map +1 -0
- package/dist/internal/parent-process.d.ts +12 -0
- package/dist/internal/parent-process.d.ts.map +1 -0
- package/dist/internal/parent-process.js +74 -0
- package/dist/internal/parent-process.js.map +1 -0
- package/dist/internal/prepare-project.d.ts +3 -0
- package/dist/internal/prepare-project.d.ts.map +1 -1
- package/dist/internal/prepare-project.js +9 -3
- package/dist/internal/prepare-project.js.map +1 -1
- package/dist/internal/react-compiler-cache.d.ts +13 -0
- package/dist/internal/react-compiler-cache.d.ts.map +1 -0
- package/dist/internal/react-compiler-cache.js +182 -0
- package/dist/internal/react-compiler-cache.js.map +1 -0
- package/dist/internal/source-imports.d.ts +7 -2
- package/dist/internal/source-imports.d.ts.map +1 -1
- package/dist/internal/source-imports.js +31 -11
- package/dist/internal/source-imports.js.map +1 -1
- package/dist/internal/staging-file.d.ts +5 -0
- package/dist/internal/staging-file.d.ts.map +1 -0
- package/dist/internal/staging-file.js +35 -0
- package/dist/internal/staging-file.js.map +1 -0
- package/dist/internal/xdg-banner.d.ts +4 -0
- package/dist/internal/xdg-banner.d.ts.map +1 -0
- package/dist/internal/xdg-banner.js +11 -0
- package/dist/internal/xdg-banner.js.map +1 -0
- package/dist/internal/xdg-data-dirs.d.ts +2 -1
- package/dist/internal/xdg-data-dirs.d.ts.map +1 -1
- package/dist/internal/xdg-data-dirs.js +1 -1
- package/dist/internal/xdg-data-dirs.js.map +1 -1
- package/dist/mcp/client.js +2 -2
- package/dist/mcp/client.js.map +1 -1
- package/dist/settings/schema.d.ts.map +1 -1
- package/dist/settings/schema.js +3 -8
- package/dist/settings/schema.js.map +1 -1
- package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
- package/dist/vite-plugins/asset-extensions.js +2 -0
- package/dist/vite-plugins/asset-extensions.js.map +1 -1
- package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
- package/dist/vite-plugins/asset-imports.js +20 -6
- package/dist/vite-plugins/asset-imports.js.map +1 -1
- package/dist/vite-plugins/asset-specifier.d.ts +5 -1
- package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
- package/dist/vite-plugins/asset-specifier.js +10 -1
- package/dist/vite-plugins/asset-specifier.js.map +1 -1
- package/dist/vite-plugins/build-manifest.d.ts +5 -1
- package/dist/vite-plugins/build-manifest.d.ts.map +1 -1
- package/dist/vite-plugins/build-manifest.js +2 -1
- package/dist/vite-plugins/build-manifest.js.map +1 -1
- package/dist/vite-plugins/built-url.d.ts.map +1 -1
- package/dist/vite-plugins/built-url.js +5 -2
- package/dist/vite-plugins/built-url.js.map +1 -1
- package/dist/vite-plugins/css.d.ts.map +1 -1
- package/dist/vite-plugins/css.js +13 -5
- package/dist/vite-plugins/css.js.map +1 -1
- package/dist/vite-plugins/ensure-store.d.ts +1 -1
- package/dist/vite-plugins/ensure-store.d.ts.map +1 -1
- package/dist/vite-plugins/ensure-store.js +2 -2
- package/dist/vite-plugins/ensure-store.js.map +1 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts +6 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.d.ts.map +1 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.js +3 -1
- package/dist/vite-plugins/fast-refresh/refresh-filter.js.map +1 -1
- package/dist/vite-plugins/fast-refresh/swc-refresh.d.ts.map +1 -1
- package/dist/vite-plugins/fast-refresh/swc-refresh.js +23 -14
- package/dist/vite-plugins/fast-refresh/swc-refresh.js.map +1 -1
- package/dist/vite-plugins/font-name.d.ts +3 -0
- package/dist/vite-plugins/font-name.d.ts.map +1 -0
- package/dist/vite-plugins/font-name.js +406 -0
- package/dist/vite-plugins/font-name.js.map +1 -0
- package/dist/vite-plugins/font-worker-env.d.ts +4 -0
- package/dist/vite-plugins/font-worker-env.d.ts.map +1 -0
- package/dist/vite-plugins/font-worker-env.js +19 -0
- package/dist/vite-plugins/font-worker-env.js.map +1 -0
- package/dist/vite-plugins/font.d.ts +4 -0
- package/dist/vite-plugins/font.d.ts.map +1 -0
- package/dist/vite-plugins/font.js +111 -0
- package/dist/vite-plugins/font.js.map +1 -0
- package/dist/vite-plugins/i18n.d.ts +11 -2
- package/dist/vite-plugins/i18n.d.ts.map +1 -1
- package/dist/vite-plugins/i18n.js +74 -8
- package/dist/vite-plugins/i18n.js.map +1 -1
- package/dist/vite-plugins/icon-worker-env.d.ts +4 -0
- package/dist/vite-plugins/icon-worker-env.d.ts.map +1 -0
- package/dist/vite-plugins/icon-worker-env.js +23 -0
- package/dist/vite-plugins/icon-worker-env.js.map +1 -0
- package/dist/vite-plugins/icons.d.ts.map +1 -1
- package/dist/vite-plugins/icons.js +4 -9
- package/dist/vite-plugins/icons.js.map +1 -1
- package/dist/vite-plugins/index.d.ts +10 -1
- package/dist/vite-plugins/index.d.ts.map +1 -1
- package/dist/vite-plugins/index.js +17 -3
- package/dist/vite-plugins/index.js.map +1 -1
- package/dist/vite-plugins/native.d.ts.map +1 -1
- package/dist/vite-plugins/native.js +0 -4
- package/dist/vite-plugins/native.js.map +1 -1
- package/dist/vite-plugins/react-compiler.d.ts.map +1 -1
- package/dist/vite-plugins/react-compiler.js +57 -18
- package/dist/vite-plugins/react-compiler.js.map +1 -1
- package/dist/vite-plugins/resource-shared.d.ts +3 -1
- package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
- package/dist/vite-plugins/resource-shared.js +3 -1
- package/dist/vite-plugins/resource-shared.js.map +1 -1
- package/dist/vite-plugins/resources.d.ts.map +1 -1
- package/dist/vite-plugins/resources.js +9 -6
- package/dist/vite-plugins/resources.js.map +1 -1
- package/dist/vite-plugins/self-contained.d.ts.map +1 -1
- package/dist/vite-plugins/self-contained.js +159 -158
- package/dist/vite-plugins/self-contained.js.map +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts +1 -1
- package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
- package/dist/vite-plugins/settings-worker-env.js +4 -4
- package/dist/vite-plugins/settings-worker-env.js.map +1 -1
- package/dist/vite-plugins/settings.d.ts.map +1 -1
- package/dist/vite-plugins/settings.js +25 -14
- package/dist/vite-plugins/settings.js.map +1 -1
- package/dist/vite-plugins/store-links.d.ts.map +1 -1
- package/dist/vite-plugins/store-links.js +9 -5
- package/dist/vite-plugins/store-links.js.map +1 -1
- package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
- package/dist/vite-plugins/undeclared-library.js +18 -15
- package/dist/vite-plugins/undeclared-library.js.map +1 -1
- package/dist/vite-plugins/worker.d.ts.map +1 -1
- package/dist/vite-plugins/worker.js +21 -13
- package/dist/vite-plugins/worker.js.map +1 -1
- package/dist/vitest-plugin.d.ts +4 -3
- package/dist/vitest-plugin.d.ts.map +1 -1
- package/dist/vitest-plugin.js +12 -8
- package/dist/vitest-plugin.js.map +1 -1
- package/env.d.ts +9 -0
- package/package.json +18 -13
- package/src/builder.ts +45 -12
- package/src/cli.ts +15 -2
- package/src/codegen/config-dependencies.ts +470 -0
- package/src/codegen/freshness.ts +5 -1
- package/src/codegen/reference.ts +1 -0
- package/src/codegen/run-codegen.ts +51 -21
- package/src/codegen/store-resolver.ts +9 -4
- package/src/commands/build.ts +13 -2
- package/src/commands/cleanup.ts +48 -0
- package/src/commands/codegen.ts +6 -5
- package/src/commands/deploy.ts +10 -2
- package/src/commands/dev.ts +45 -4
- package/src/commands/docs.ts +1 -0
- package/src/deploy/depends.ts +30 -3
- package/src/deploy/download.ts +33 -24
- package/src/deploy/freedesktop/metainfo.ts +73 -21
- package/src/deploy/freedesktop/validate.ts +80 -15
- package/src/deploy/native-addon.ts +183 -0
- package/src/deploy/nfpm/config.ts +13 -4
- package/src/deploy/nfpm/contents.ts +8 -0
- package/src/deploy/node-runtime/download.ts +2 -2
- package/src/deploy/node-runtime/elf.ts +46 -5
- package/src/deploy/node-runtime/guard.ts +10 -14
- package/src/deploy/node-runtime/index.ts +148 -12
- package/src/deploy/node-runtime/sonames.ts +17 -0
- package/src/deploy/notices/node-runtime.ts +2 -2
- package/src/deploy/payload/launcher.ts +20 -1
- package/src/deploy/payload/stage.ts +76 -5
- package/src/deploy/run-deploy.ts +227 -72
- package/src/deploy/settings/arch.ts +40 -8
- package/src/deploy/settings/build-manifest.ts +28 -3
- package/src/deploy/settings/extra-files.ts +30 -4
- package/src/deploy/settings/index.ts +7 -2
- package/src/deploy/settings/libraries.ts +2 -1
- package/src/deploy/settings/paths.ts +80 -13
- package/src/deploy/targets/appimage.ts +1 -0
- package/src/deploy/targets/flatpak-pnpm.ts +4 -4
- package/src/deploy/targets/flatpak-source.ts +15 -2
- package/src/deploy/targets/flatpak.ts +1 -0
- package/src/deploy/targets/nfpm-target.ts +14 -6
- package/src/deploy/types.ts +5 -1
- package/src/deploy/vendored/appimagetool.ts +2 -2
- package/src/deploy/vendored/nfpm.ts +1 -1
- package/src/dev/catalog-writes.ts +35 -0
- package/src/dev/entry-env.ts +2 -1
- package/src/dev/font-dir.ts +11 -0
- package/src/dev/headless.ts +40 -0
- package/src/dev/runner-deps.ts +20 -7
- package/src/dev/runner-main.ts +12 -3
- package/src/dev/runner.ts +37 -7
- package/src/dev/supervisor.ts +183 -32
- package/src/dev/vite-dev-server.ts +20 -2
- package/src/dev/watch-ignore.ts +16 -0
- package/src/i18n/catalogs.ts +21 -8
- package/src/i18n/source-messages.ts +1446 -29
- package/src/internal/agent-rules.ts +7 -2
- package/src/internal/banner.ts +27 -6
- package/src/internal/build-manifest.ts +25 -1
- package/src/internal/build-output.ts +171 -0
- package/src/internal/cache-root.ts +12 -0
- package/src/internal/compile-cache-store.ts +50 -0
- package/src/internal/compile-cache.ts +20 -0
- package/src/internal/deploy-out-dir.ts +8 -0
- package/src/internal/docs-elements.ts +10 -4
- package/src/internal/entry-arg.ts +8 -1
- package/src/internal/errors.ts +1 -1
- package/src/internal/font-path.ts +15 -0
- package/src/internal/font-staging.ts +131 -0
- package/src/internal/icon-staging.ts +58 -0
- package/src/internal/import-scan.ts +206 -0
- package/src/internal/module-hash.ts +22 -0
- package/src/internal/output-directory.ts +699 -0
- package/src/internal/parent-process.ts +110 -0
- package/src/internal/prepare-project.ts +11 -5
- package/src/internal/react-compiler-cache.ts +246 -0
- package/src/internal/source-imports.ts +57 -12
- package/src/internal/staging-file.ts +42 -0
- package/src/internal/xdg-banner.ts +13 -0
- package/src/internal/xdg-data-dirs.ts +1 -1
- package/src/mcp/client.ts +2 -2
- package/src/settings/schema.ts +4 -10
- package/src/vite-plugins/asset-extensions.ts +2 -0
- package/src/vite-plugins/asset-imports.ts +23 -5
- package/src/vite-plugins/asset-specifier.ts +17 -0
- package/src/vite-plugins/build-manifest.ts +7 -1
- package/src/vite-plugins/built-url.ts +6 -2
- package/src/vite-plugins/css.ts +16 -5
- package/src/vite-plugins/ensure-store.ts +2 -2
- package/src/vite-plugins/fast-refresh/refresh-filter.ts +10 -1
- package/src/vite-plugins/fast-refresh/swc-refresh.ts +33 -14
- package/src/vite-plugins/font-name.ts +582 -0
- package/src/vite-plugins/font-worker-env.ts +25 -0
- package/src/vite-plugins/font.ts +180 -0
- package/src/vite-plugins/i18n.ts +122 -11
- package/src/vite-plugins/icon-worker-env.ts +36 -0
- package/src/vite-plugins/icons.ts +4 -10
- package/src/vite-plugins/index.ts +34 -9
- package/src/vite-plugins/native.ts +0 -5
- package/src/vite-plugins/react-compiler.ts +83 -19
- package/src/vite-plugins/resource-shared.ts +4 -0
- package/src/vite-plugins/resources.ts +11 -5
- package/src/vite-plugins/self-contained.ts +184 -185
- package/src/vite-plugins/settings-worker-env.ts +4 -4
- package/src/vite-plugins/settings.ts +36 -16
- package/src/vite-plugins/store-links.ts +10 -5
- package/src/vite-plugins/undeclared-library.ts +19 -15
- package/src/vite-plugins/worker.ts +31 -15
- package/src/vitest-plugin.ts +12 -8
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { parseSync as parseBabelSync, traverse, types } from "@babel/core";
|
|
1
2
|
import { isPathInside, isPathWithin, toPosixPath } from "@gtkx/utils";
|
|
2
3
|
import { runExtractor } from "i18next-cli";
|
|
3
4
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
4
5
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
|
+
import { parseSync, Visitor } from "vite";
|
|
5
7
|
import { runCliTool } from "../internal/run-cli-tool.js";
|
|
8
|
+
import { sourceLanguage } from "../internal/source-imports.js";
|
|
6
9
|
import { replaceCatalogTemplate } from "./catalog-template.js";
|
|
7
10
|
import { metadataTemplateFiles } from "./metadata-templates.js";
|
|
8
11
|
import { clearI18nResources, i18nToolkitConfig } from "./types.js";
|
|
@@ -10,6 +13,94 @@ const CONTEXT_SEPARATOR = "\u{4}";
|
|
|
10
13
|
const DEFAULT_NAMESPACE = "translation";
|
|
11
14
|
const POTFILES_FILENAME = "POTFILES.in";
|
|
12
15
|
const SYNTHETIC_FILENAME = "messages.js";
|
|
16
|
+
const UNSUPPORTED_PLURAL_OPTION = /^defaultValue_(few|many|two|zero)$/u;
|
|
17
|
+
const STATIC_SOURCE_OPTION_NAMES = new Set([
|
|
18
|
+
"context",
|
|
19
|
+
"defaultValue",
|
|
20
|
+
"defaultValue_one",
|
|
21
|
+
"defaultValue_other",
|
|
22
|
+
"keyPrefix",
|
|
23
|
+
]);
|
|
24
|
+
const NESTED_CONTEXT = /["']?context["']?\s*:\s*(?:"([^"]*)"|'([^']*)')/u;
|
|
25
|
+
const NESTED_COUNT = /["']?count["']?\s*:/u;
|
|
26
|
+
const NESTED_STRUCTURE_TOKEN = /"[^"]*"|'[^']*'|[()]/gu;
|
|
27
|
+
const TRANSLATION_MODULES = new Set(["@gtkx/i18n", "i18next"]);
|
|
28
|
+
const TRANS_ELEMENTS = new Set(["Trans", "TransWithoutContext"]);
|
|
29
|
+
const STATIC_KEY_WRAPPER_TYPES = new Set([
|
|
30
|
+
"ParenthesizedExpression",
|
|
31
|
+
"TSAsExpression",
|
|
32
|
+
"TSSatisfiesExpression",
|
|
33
|
+
"TSTypeAssertion",
|
|
34
|
+
"TSNonNullExpression",
|
|
35
|
+
]);
|
|
36
|
+
class SourceExtractionError extends Error {
|
|
37
|
+
}
|
|
38
|
+
const sourceErrorMessage = (error) => {
|
|
39
|
+
if (!(error instanceof Error)) {
|
|
40
|
+
return String(error);
|
|
41
|
+
}
|
|
42
|
+
if ("code" in error &&
|
|
43
|
+
error.code === "BABEL_PARSE_ERROR") {
|
|
44
|
+
const separator = error.message.indexOf(": ");
|
|
45
|
+
if (separator !== -1) {
|
|
46
|
+
return error.message.slice(separator + 2);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return error.message;
|
|
50
|
+
};
|
|
51
|
+
const projectSourcePath = (root, path) => {
|
|
52
|
+
const absolute = isAbsolute(path) ? resolve(path) : resolve(root, path);
|
|
53
|
+
return toPosixPath(isPathInside(root, absolute) ? relative(root, absolute) : path);
|
|
54
|
+
};
|
|
55
|
+
const sourceExtractionError = (root, path, point, error) => {
|
|
56
|
+
if (error instanceof SourceExtractionError) {
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
const file = projectSourcePath(root, path);
|
|
60
|
+
const location = point === null
|
|
61
|
+
? file
|
|
62
|
+
: `${file}:${String(point.line)}:${String(point.column + 1)}`;
|
|
63
|
+
return new SourceExtractionError(`${location}: ${sourceErrorMessage(error)}`, { cause: error });
|
|
64
|
+
};
|
|
65
|
+
const locatablePoint = (node) => {
|
|
66
|
+
const location = node.loc?.start;
|
|
67
|
+
return location === undefined ? null : { column: location.column, line: location.line };
|
|
68
|
+
};
|
|
69
|
+
const isSourcePoint = (value) => typeof value === "object" &&
|
|
70
|
+
value !== null &&
|
|
71
|
+
"column" in value &&
|
|
72
|
+
typeof value.column === "number" &&
|
|
73
|
+
"line" in value &&
|
|
74
|
+
typeof value.line === "number";
|
|
75
|
+
const errorSourcePoint = (error) => {
|
|
76
|
+
if (typeof error !== "object" || error === null) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if ("loc" in error && isSourcePoint(error.loc)) {
|
|
80
|
+
return error.loc;
|
|
81
|
+
}
|
|
82
|
+
return "location" in error && isSourcePoint(error.location) ? error.location : null;
|
|
83
|
+
};
|
|
84
|
+
const atSourceNode = (root, path, node, operation) => {
|
|
85
|
+
try {
|
|
86
|
+
return operation();
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw sourceExtractionError(root, path, locatablePoint(node), error);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const atExtractedLocation = (root, locations, operation) => {
|
|
93
|
+
const location = locations.find((candidate) => candidate.line !== undefined && candidate.column !== undefined);
|
|
94
|
+
if (location?.line === undefined || location.column === undefined) {
|
|
95
|
+
return operation();
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
return operation();
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw sourceExtractionError(root, location.file, { column: location.column, line: location.line }, error);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
13
104
|
const quietLogger = () => {
|
|
14
105
|
const reports = [];
|
|
15
106
|
return {
|
|
@@ -98,10 +189,10 @@ const expandedPlural = (entry) => {
|
|
|
98
189
|
},
|
|
99
190
|
};
|
|
100
191
|
};
|
|
101
|
-
const groupedPlurals = (entries) => {
|
|
192
|
+
const groupedPlurals = (root, entries) => {
|
|
102
193
|
const groups = new Map();
|
|
103
194
|
for (const entry of entries) {
|
|
104
|
-
const { baseKey, variant } = expandedPlural(entry);
|
|
195
|
+
const { baseKey, variant } = atExtractedLocation(root, entry.locations ?? [], () => expandedPlural(entry));
|
|
105
196
|
const namespace = namespaceFor(entry);
|
|
106
197
|
const key = `${namespace}\0${baseKey}`;
|
|
107
198
|
const group = groups.get(key) ?? { baseKey, namespace, variants: [] };
|
|
@@ -140,17 +231,19 @@ const pluralMessage = ({ baseKey, namespace, variants }) => {
|
|
|
140
231
|
sourceKey: msgid,
|
|
141
232
|
};
|
|
142
233
|
};
|
|
143
|
-
const pluralMessages = (entries) => groupedPlurals(entries).map((group) => pluralMessage(group));
|
|
234
|
+
const pluralMessages = (root, entries) => groupedPlurals(root, entries).map((group) => atExtractedLocation(root, group.variants.flatMap((variant) => variant.locations), () => pluralMessage(group)));
|
|
144
235
|
const assertCardinal = (entry) => {
|
|
145
236
|
if (entry.isOrdinal === true) {
|
|
146
237
|
throw new Error("GNU gettext catalogs do not support i18next ordinal plurals");
|
|
147
238
|
}
|
|
148
239
|
};
|
|
149
|
-
const sourceMessages = (entries) => {
|
|
240
|
+
const sourceMessages = (root, entries) => {
|
|
150
241
|
const points = [];
|
|
151
242
|
const plurals = [];
|
|
152
243
|
for (const entry of entries) {
|
|
153
|
-
|
|
244
|
+
atExtractedLocation(root, entry.locations ?? [], () => {
|
|
245
|
+
assertCardinal(entry);
|
|
246
|
+
});
|
|
154
247
|
if (entry.isExpandedPlural === true) {
|
|
155
248
|
plurals.push(entry);
|
|
156
249
|
continue;
|
|
@@ -160,7 +253,10 @@ const sourceMessages = (entries) => {
|
|
|
160
253
|
}
|
|
161
254
|
points.push(entry);
|
|
162
255
|
}
|
|
163
|
-
return [
|
|
256
|
+
return [
|
|
257
|
+
...points.map((entry) => atExtractedLocation(root, entry.locations ?? [], () => pointMessage(entry))),
|
|
258
|
+
...pluralMessages(root, plurals),
|
|
259
|
+
];
|
|
164
260
|
};
|
|
165
261
|
const compareMessages = (left, right) => left.namespace.localeCompare(right.namespace) ||
|
|
166
262
|
(left.context ?? "").localeCompare(right.context ?? "") ||
|
|
@@ -185,16 +281,885 @@ const normalizedSourceFiles = (root, paths) => {
|
|
|
185
281
|
.filter((path) => isPathWithin(root, path));
|
|
186
282
|
return new Set(files).values().toArray().toSorted((left, right) => left.localeCompare(right));
|
|
187
283
|
};
|
|
284
|
+
const isStaticKeyWrapper = (key) => STATIC_KEY_WRAPPER_TYPES.has(key.type);
|
|
285
|
+
const unwrapStaticWrapper = (node) => isStaticKeyWrapper(node) ? unwrapStaticWrapper(node.expression) : node;
|
|
286
|
+
const isStaticTranslationKey = (key) => {
|
|
287
|
+
if (key === undefined || key === null) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
if (key.type === "Literal") {
|
|
291
|
+
return typeof key.value === "string";
|
|
292
|
+
}
|
|
293
|
+
if (key.type === "TemplateLiteral") {
|
|
294
|
+
return key.expressions.length === 0;
|
|
295
|
+
}
|
|
296
|
+
if (key.type === "ParenthesizedExpression") {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (isStaticKeyWrapper(key)) {
|
|
300
|
+
return isStaticTranslationKey(key.expression);
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
};
|
|
304
|
+
const assertStaticTranslationKey = (key) => {
|
|
305
|
+
if (!isStaticTranslationKey(key)) {
|
|
306
|
+
throw new Error("Translation keys must be string literals");
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const propertyName = (property) => {
|
|
310
|
+
if (!property.computed && property.key.type === "Identifier") {
|
|
311
|
+
return property.key.name;
|
|
312
|
+
}
|
|
313
|
+
return property.key.type === "Literal" && typeof property.key.value === "string"
|
|
314
|
+
? property.key.value
|
|
315
|
+
: null;
|
|
316
|
+
};
|
|
317
|
+
const assertSupportedOptionProperty = (property) => {
|
|
318
|
+
if (property.type === "SpreadElement") {
|
|
319
|
+
throw new Error("Translation extraction requires explicit option properties");
|
|
320
|
+
}
|
|
321
|
+
const name = propertyName(property);
|
|
322
|
+
if (name === null) {
|
|
323
|
+
throw new Error("Translation extraction requires static option property names");
|
|
324
|
+
}
|
|
325
|
+
if (UNSUPPORTED_PLURAL_OPTION.test(name)) {
|
|
326
|
+
throw new Error("GNU gettext accepts one singular and one plural source string");
|
|
327
|
+
}
|
|
328
|
+
if (STATIC_SOURCE_OPTION_NAMES.has(name)) {
|
|
329
|
+
assertStaticTranslationKey(property.value);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
const assertSupportedOptionObject = (options) => {
|
|
333
|
+
if (options === null || options === undefined) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (isStaticKeyWrapper(options) && unwrapStaticWrapper(options).type === "ObjectExpression") {
|
|
337
|
+
throw new Error("Translation option objects cannot be wrapped in another expression");
|
|
338
|
+
}
|
|
339
|
+
if (options.type !== "ObjectExpression") {
|
|
340
|
+
throw new Error("Translation option objects must be inline object literals");
|
|
341
|
+
}
|
|
342
|
+
for (const property of options.properties) {
|
|
343
|
+
assertSupportedOptionProperty(property);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
const namedImportedBinding = (path, source) => {
|
|
347
|
+
if (!path.isImportSpecifier() || path.node.importKind === "type") {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const imported = path.node.imported;
|
|
351
|
+
return {
|
|
352
|
+
imported: types.isIdentifier(imported) ? imported.name : imported.value,
|
|
353
|
+
local: path.node.local.name,
|
|
354
|
+
source,
|
|
355
|
+
style: "named",
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
const defaultImportedBinding = (path, source) => path.isImportDefaultSpecifier()
|
|
359
|
+
? { imported: "default", local: path.node.local.name, source, style: "default" }
|
|
360
|
+
: null;
|
|
361
|
+
const namespaceImportedBinding = (path, source) => path.isImportNamespaceSpecifier()
|
|
362
|
+
? { imported: "*", local: path.node.local.name, source, style: "namespace" }
|
|
363
|
+
: null;
|
|
364
|
+
const importedBinding = (binding) => {
|
|
365
|
+
if (binding === undefined) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const path = binding.path;
|
|
369
|
+
const declaration = path.parentPath;
|
|
370
|
+
if (!declaration.isImportDeclaration() || declaration.node.importKind === "type") {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const source = declaration.node.source.value;
|
|
374
|
+
return namedImportedBinding(path, source) ??
|
|
375
|
+
defaultImportedBinding(path, source) ??
|
|
376
|
+
namespaceImportedBinding(path, source);
|
|
377
|
+
};
|
|
378
|
+
const babelPropertyName = (property) => {
|
|
379
|
+
const key = property.key;
|
|
380
|
+
if (!property.computed && types.isIdentifier(key)) {
|
|
381
|
+
return key.name;
|
|
382
|
+
}
|
|
383
|
+
return types.isStringLiteral(key) ? key.value : null;
|
|
384
|
+
};
|
|
385
|
+
const isBoundIdentifier = (node, name) => {
|
|
386
|
+
if (types.isIdentifier(node)) {
|
|
387
|
+
return node.name === name;
|
|
388
|
+
}
|
|
389
|
+
if (types.isAssignmentPattern(node)) {
|
|
390
|
+
return types.isIdentifier(node.left) && node.left.name === name;
|
|
391
|
+
}
|
|
392
|
+
return false;
|
|
393
|
+
};
|
|
394
|
+
const isHookPatternBinding = (pattern, name) => {
|
|
395
|
+
if (types.isObjectPattern(pattern)) {
|
|
396
|
+
return pattern.properties.some((property) => types.isObjectProperty(property) &&
|
|
397
|
+
babelPropertyName(property) === "t" &&
|
|
398
|
+
isBoundIdentifier(property.value, name));
|
|
399
|
+
}
|
|
400
|
+
if (types.isArrayPattern(pattern)) {
|
|
401
|
+
return isBoundIdentifier(pattern.elements[0] ?? null, name);
|
|
402
|
+
}
|
|
403
|
+
return false;
|
|
404
|
+
};
|
|
405
|
+
const importedTranslationHook = (scope, call) => {
|
|
406
|
+
if (!types.isIdentifier(call.callee)) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
const imported = importedBinding(scope.getBinding(call.callee.name));
|
|
410
|
+
return imported?.imported === "useTranslation" && TRANSLATION_MODULES.has(imported.source)
|
|
411
|
+
? imported
|
|
412
|
+
: null;
|
|
413
|
+
};
|
|
414
|
+
const translationHookBinding = (binding) => {
|
|
415
|
+
const path = binding.path;
|
|
416
|
+
if (!path.isVariableDeclarator()) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
const pattern = path.node.id;
|
|
420
|
+
const initializer = path.node.init;
|
|
421
|
+
if (!isHookPatternBinding(pattern, binding.identifier.name) ||
|
|
422
|
+
!types.isCallExpression(initializer)) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
const imported = importedTranslationHook(path.scope, initializer);
|
|
426
|
+
if (imported === null) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
return { call: initializer, isCanonical: imported.local === "useTranslation" };
|
|
430
|
+
};
|
|
431
|
+
const importedTranslationFunctionKind = (imported) => {
|
|
432
|
+
if (imported?.imported !== "t" || !TRANSLATION_MODULES.has(imported.source)) {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
return imported.local === "t" ? "canonical" : "alias";
|
|
436
|
+
};
|
|
437
|
+
const hookTranslationFunctionKind = (binding) => {
|
|
438
|
+
if (binding === undefined) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
const hook = translationHookBinding(binding);
|
|
442
|
+
if (hook === null) {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
return binding.identifier.name === "t" && hook.isCanonical ? "canonical" : "alias";
|
|
446
|
+
};
|
|
447
|
+
const directTranslationFunctionKind = (scope, name) => {
|
|
448
|
+
const binding = scope.getBinding(name);
|
|
449
|
+
return importedTranslationFunctionKind(importedBinding(binding)) ?? hookTranslationFunctionKind(binding);
|
|
450
|
+
};
|
|
451
|
+
const babelMemberName = (member) => {
|
|
452
|
+
const property = member.property;
|
|
453
|
+
if (member.computed) {
|
|
454
|
+
return types.isStringLiteral(property) ? property.value : null;
|
|
455
|
+
}
|
|
456
|
+
return types.isIdentifier(property) ? property.name : null;
|
|
457
|
+
};
|
|
458
|
+
const isImportedTranslationObject = (scope, object) => {
|
|
459
|
+
if (!types.isIdentifier(object)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
const imported = importedBinding(scope.getBinding(object.name));
|
|
463
|
+
return imported !== null &&
|
|
464
|
+
TRANSLATION_MODULES.has(imported.source) &&
|
|
465
|
+
(imported.style === "namespace" || (imported.source === "i18next" && imported.imported === "default"));
|
|
466
|
+
};
|
|
467
|
+
const constantVariableDeclarator = (binding) => {
|
|
468
|
+
const path = binding.path;
|
|
469
|
+
const declaration = path.parentPath;
|
|
470
|
+
if (!path.isVariableDeclarator() ||
|
|
471
|
+
!declaration.isVariableDeclaration() ||
|
|
472
|
+
declaration.node.kind !== "const") {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
return path;
|
|
476
|
+
};
|
|
477
|
+
const isTranslationHookResultBinding = (binding) => {
|
|
478
|
+
if (binding === undefined) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
const path = constantVariableDeclarator(binding);
|
|
482
|
+
const initializer = path?.node.init;
|
|
483
|
+
return path !== null &&
|
|
484
|
+
types.isIdentifier(path.node.id) &&
|
|
485
|
+
types.isCallExpression(initializer) &&
|
|
486
|
+
importedTranslationHook(path.scope, initializer) !== null;
|
|
487
|
+
};
|
|
488
|
+
const isHookTranslationMember = (scope, member) => {
|
|
489
|
+
if (babelMemberName(member) !== "t") {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
const object = member.object;
|
|
493
|
+
if (types.isCallExpression(object)) {
|
|
494
|
+
return importedTranslationHook(scope, object) !== null;
|
|
495
|
+
}
|
|
496
|
+
return types.isIdentifier(object) && isTranslationHookResultBinding(scope.getBinding(object.name));
|
|
497
|
+
};
|
|
498
|
+
const isTranslationMember = (scope, member) => babelMemberName(member) === "t" &&
|
|
499
|
+
(isImportedTranslationObject(scope, member.object) || isHookTranslationMember(scope, member));
|
|
500
|
+
const isDirectTranslationFunction = (scope, node) => types.isIdentifier(node) && directTranslationFunctionKind(scope, node.name) !== null;
|
|
501
|
+
const isTranslationFunctionValue = (scope, node) => {
|
|
502
|
+
if (isDirectTranslationFunction(scope, node)) {
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
return (types.isMemberExpression(node) || types.isOptionalMemberExpression(node)) &&
|
|
506
|
+
isTranslationMember(scope, node);
|
|
507
|
+
};
|
|
508
|
+
const isTranslationBindCall = (scope, node) => {
|
|
509
|
+
if (!types.isCallExpression(node) || !types.isMemberExpression(node.callee)) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
return babelMemberName(node.callee) === "bind" &&
|
|
513
|
+
isTranslationFunctionValue(scope, node.callee.object);
|
|
514
|
+
};
|
|
515
|
+
const isTranslationObjectPatternAlias = (path, binding) => {
|
|
516
|
+
const pattern = path.node.id;
|
|
517
|
+
const initializer = path.node.init;
|
|
518
|
+
if (!types.isObjectPattern(pattern) ||
|
|
519
|
+
!isHookPatternBinding(pattern, binding.identifier.name) ||
|
|
520
|
+
!types.isIdentifier(initializer)) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
return isImportedTranslationObject(path.scope, initializer) ||
|
|
524
|
+
isTranslationHookResultBinding(path.scope.getBinding(initializer.name));
|
|
525
|
+
};
|
|
526
|
+
const isTranslationAliasBinding = (binding) => {
|
|
527
|
+
if (binding === undefined) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
const path = constantVariableDeclarator(binding);
|
|
531
|
+
if (path === null) {
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
if (isTranslationObjectPatternAlias(path, binding)) {
|
|
535
|
+
return true;
|
|
536
|
+
}
|
|
537
|
+
const initializer = path.node.init;
|
|
538
|
+
return types.isIdentifier(path.node.id) &&
|
|
539
|
+
initializer !== null &&
|
|
540
|
+
initializer !== undefined &&
|
|
541
|
+
(isTranslationFunctionValue(path.scope, initializer) || isTranslationBindCall(path.scope, initializer));
|
|
542
|
+
};
|
|
543
|
+
const translationFunctionKind = (scope, name) => {
|
|
544
|
+
const direct = directTranslationFunctionKind(scope, name);
|
|
545
|
+
if (direct !== null) {
|
|
546
|
+
return direct;
|
|
547
|
+
}
|
|
548
|
+
return isTranslationAliasBinding(scope.getBinding(name)) ? "alias" : null;
|
|
549
|
+
};
|
|
550
|
+
const translationElementKind = (path, name) => {
|
|
551
|
+
const imported = importedBinding(path.scope.getBinding(name));
|
|
552
|
+
if (imported?.source !== "@gtkx/i18n" || !TRANS_ELEMENTS.has(imported.imported)) {
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
return imported.local === imported.imported ? "canonical" : "alias";
|
|
556
|
+
};
|
|
557
|
+
const nodeStart = (path) => {
|
|
558
|
+
const start = path.node.start;
|
|
559
|
+
if (start === null || start === undefined) {
|
|
560
|
+
throw new Error("Translation extraction could not locate a source expression");
|
|
561
|
+
}
|
|
562
|
+
return start;
|
|
563
|
+
};
|
|
564
|
+
const registerSourceMask = (node, references) => {
|
|
565
|
+
const { start, end } = node;
|
|
566
|
+
if (start === null || start === undefined || end === null || end === undefined) {
|
|
567
|
+
throw new Error("Translation extraction could not locate a source expression");
|
|
568
|
+
}
|
|
569
|
+
references.masks.push({ start, end });
|
|
570
|
+
};
|
|
571
|
+
const sourceLocationKey = (line, column) => `${String(line)}:${String(column)}`;
|
|
572
|
+
const sourcePoint = (node) => {
|
|
573
|
+
return locatablePoint(node);
|
|
574
|
+
};
|
|
575
|
+
const registerSourceLocation = (node, references) => {
|
|
576
|
+
const point = sourcePoint(node);
|
|
577
|
+
if (point !== null) {
|
|
578
|
+
references.locations.set(sourceLocationKey(point.line, point.column), point);
|
|
579
|
+
}
|
|
580
|
+
return point;
|
|
581
|
+
};
|
|
582
|
+
const babelStaticKey = (node) => {
|
|
583
|
+
if (node === null || node === undefined) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
if (types.isStringLiteral(node)) {
|
|
587
|
+
return node.value;
|
|
588
|
+
}
|
|
589
|
+
if (types.isTemplateLiteral(node) && node.expressions.length === 0) {
|
|
590
|
+
return node.quasis[0]?.value.cooked ?? null;
|
|
591
|
+
}
|
|
592
|
+
if (types.isParenthesizedExpression(node) ||
|
|
593
|
+
types.isTSAsExpression(node) ||
|
|
594
|
+
types.isTSSatisfiesExpression(node) ||
|
|
595
|
+
types.isTSTypeAssertion(node) ||
|
|
596
|
+
types.isTSNonNullExpression(node)) {
|
|
597
|
+
return babelStaticKey(node.expression);
|
|
598
|
+
}
|
|
599
|
+
return null;
|
|
600
|
+
};
|
|
601
|
+
const babelObjectExpression = (node) => {
|
|
602
|
+
if (node === null || node === undefined) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
if (types.isObjectExpression(node)) {
|
|
606
|
+
return node;
|
|
607
|
+
}
|
|
608
|
+
if (types.isParenthesizedExpression(node) ||
|
|
609
|
+
types.isTSAsExpression(node) ||
|
|
610
|
+
types.isTSSatisfiesExpression(node) ||
|
|
611
|
+
types.isTSTypeAssertion(node) ||
|
|
612
|
+
types.isTSNonNullExpression(node)) {
|
|
613
|
+
return babelObjectExpression(node.expression);
|
|
614
|
+
}
|
|
615
|
+
return null;
|
|
616
|
+
};
|
|
617
|
+
const babelNamedProperty = (object, name) => {
|
|
618
|
+
if (object === null) {
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
for (const property of object.properties) {
|
|
622
|
+
if (types.isObjectProperty(property) && babelPropertyName(property) === name) {
|
|
623
|
+
return property;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return null;
|
|
627
|
+
};
|
|
628
|
+
const babelStringProperty = (object, name) => {
|
|
629
|
+
const property = babelNamedProperty(object, name);
|
|
630
|
+
if (property === null) {
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
const value = babelStaticKey(property.value);
|
|
634
|
+
if (value === null) {
|
|
635
|
+
throw new Error(`Translation ${name} values must be string literals`);
|
|
636
|
+
}
|
|
637
|
+
return value;
|
|
638
|
+
};
|
|
639
|
+
const callOptions = (call) => babelObjectExpression(call.arguments[1]) ?? babelObjectExpression(call.arguments[2]);
|
|
640
|
+
const hookKeyPrefix = (callee) => {
|
|
641
|
+
const binding = callee.scope.getBinding(callee.node.name);
|
|
642
|
+
const hook = binding === undefined ? null : translationHookBinding(binding);
|
|
643
|
+
return babelStringProperty(hook === null ? null : babelObjectExpression(hook.call.arguments[1]), "keyPrefix") ?? "";
|
|
644
|
+
};
|
|
645
|
+
const prefixedTranslationKey = (prefix, key) => {
|
|
646
|
+
if (prefix.length === 0) {
|
|
647
|
+
return key;
|
|
648
|
+
}
|
|
649
|
+
return prefix.endsWith(".") ? `${prefix}${key}` : `${prefix}.${key}`;
|
|
650
|
+
};
|
|
651
|
+
const extractedEntryKey = (call, keyPrefix) => {
|
|
652
|
+
const key = babelStaticKey(call.arguments[0]);
|
|
653
|
+
if (key === null) {
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
const options = callOptions(call);
|
|
657
|
+
const callPrefix = babelStringProperty(options, "keyPrefix");
|
|
658
|
+
if (callPrefix === "" && keyPrefix.length > 0) {
|
|
659
|
+
throw new Error("An empty call keyPrefix cannot override a hook keyPrefix during extraction");
|
|
660
|
+
}
|
|
661
|
+
const selectedPrefix = callPrefix ?? keyPrefix;
|
|
662
|
+
const prefixed = prefixedTranslationKey(selectedPrefix, key);
|
|
663
|
+
const context = babelStringProperty(options, "context");
|
|
664
|
+
return context === null ? prefixed : `${prefixed}${CONTEXT_SEPARATOR}${context}`;
|
|
665
|
+
};
|
|
666
|
+
const registerEntryLocation = (key, point, references) => {
|
|
667
|
+
if (key === null || point === null) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const locations = references.entryLocations.get(key) ?? [];
|
|
671
|
+
locations.push(point);
|
|
672
|
+
references.entryLocations.set(key, locations);
|
|
673
|
+
};
|
|
674
|
+
const registerCallReference = (callPath, references, keyPrefix) => {
|
|
675
|
+
references.calls.add(nodeStart(callPath));
|
|
676
|
+
const firstArgument = callPath.node.arguments[0];
|
|
677
|
+
const point = registerSourceLocation(firstArgument ?? callPath.node, references);
|
|
678
|
+
if (point !== null) {
|
|
679
|
+
references.sourcePoints.set(nodeStart(callPath), point);
|
|
680
|
+
}
|
|
681
|
+
registerEntryLocation(extractedEntryKey(callPath.node, keyPrefix), point, references);
|
|
682
|
+
};
|
|
683
|
+
const parserPlugins = (lang) => [
|
|
684
|
+
"decorators",
|
|
685
|
+
...(lang === "ts" || lang === "tsx" ? ["typescript"] : []),
|
|
686
|
+
...(lang === "jsx" || lang === "tsx" ? ["jsx"] : []),
|
|
687
|
+
];
|
|
688
|
+
const parseTranslationReferences = (root, path, source, lang) => {
|
|
689
|
+
try {
|
|
690
|
+
return parseBabelSync(source, {
|
|
691
|
+
ast: true,
|
|
692
|
+
babelrc: false,
|
|
693
|
+
configFile: false,
|
|
694
|
+
filename: projectSourcePath(root, path),
|
|
695
|
+
parserOpts: { createParenthesizedExpressions: true, plugins: parserPlugins(lang) },
|
|
696
|
+
sourceType: "module",
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
throw sourceExtractionError(root, path, errorSourcePoint(error), error);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
const registerIdentifierTranslationCall = (callPath, callee, references) => {
|
|
704
|
+
if (!callee.isIdentifier()) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const kind = translationFunctionKind(callee.scope, callee.node.name);
|
|
708
|
+
if (kind === "alias") {
|
|
709
|
+
throw new Error("Translation calls must use the imported name t");
|
|
710
|
+
}
|
|
711
|
+
if (kind === "canonical") {
|
|
712
|
+
registerCallReference(callPath, references, hookKeyPrefix(callee));
|
|
713
|
+
}
|
|
714
|
+
else if (callee.node.name === "t") {
|
|
715
|
+
registerSourceMask(callee.node, references);
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
const registerTranslationCall = (callPath, references) => {
|
|
719
|
+
assertSupportedWrappedCallee(callPath);
|
|
720
|
+
const callee = callPath.get("callee");
|
|
721
|
+
if (callee.isIdentifier()) {
|
|
722
|
+
registerIdentifierTranslationCall(callPath, callee, references);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (callee.isMemberExpression() && isTranslationMember(callee.scope, callee.node)) {
|
|
726
|
+
throw new Error("Translation calls must use the named t export");
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
const unwrapTranslationCallee = (node) => {
|
|
730
|
+
if (types.isParenthesizedExpression(node) ||
|
|
731
|
+
types.isTSAsExpression(node) ||
|
|
732
|
+
types.isTSSatisfiesExpression(node) ||
|
|
733
|
+
types.isTSTypeAssertion(node) ||
|
|
734
|
+
types.isTSNonNullExpression(node)) {
|
|
735
|
+
return unwrapTranslationCallee(node.expression);
|
|
736
|
+
}
|
|
737
|
+
return node;
|
|
738
|
+
};
|
|
739
|
+
const isTranslationCallee = (scope, node) => {
|
|
740
|
+
if (types.isIdentifier(node)) {
|
|
741
|
+
return translationFunctionKind(scope, node.name) !== null;
|
|
742
|
+
}
|
|
743
|
+
return (types.isMemberExpression(node) || types.isOptionalMemberExpression(node)) &&
|
|
744
|
+
isTranslationMember(scope, node);
|
|
745
|
+
};
|
|
746
|
+
const assertSupportedWrappedCallee = (callPath) => {
|
|
747
|
+
const callee = callPath.node.callee;
|
|
748
|
+
const unwrapped = unwrapTranslationCallee(callee);
|
|
749
|
+
if (unwrapped !== callee && isTranslationCallee(callPath.scope, unwrapped)) {
|
|
750
|
+
throw new Error("Translation call expressions cannot wrap their callee");
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
const assertSupportedOptionalCall = (callPath) => {
|
|
754
|
+
const callee = unwrapTranslationCallee(callPath.node.callee);
|
|
755
|
+
if (isTranslationCallee(callPath.scope, callee)) {
|
|
756
|
+
throw new Error("Translation calls cannot use optional chaining");
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
const assertUnsupportedTranslationTag = (tagPath) => {
|
|
760
|
+
const tag = unwrapTranslationCallee(tagPath.node.tag);
|
|
761
|
+
if (isTranslationCallee(tagPath.scope, tag)) {
|
|
762
|
+
throw new Error("Translation calls cannot use tagged-template syntax");
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
const registerUnrecognizedElementMasks = (elementPath, name, references) => {
|
|
766
|
+
registerSourceMask(name.node, references);
|
|
767
|
+
const parent = elementPath.parentPath.node;
|
|
768
|
+
const closingName = types.isJSXElement(parent) ? parent.closingElement?.name : null;
|
|
769
|
+
if (types.isJSXIdentifier(closingName)) {
|
|
770
|
+
registerSourceMask(closingName, references);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
const registerElementReference = (elementPath, references) => {
|
|
774
|
+
const start = nodeStart(elementPath);
|
|
775
|
+
const point = registerSourceLocation(elementPath.node, references);
|
|
776
|
+
references.elements.add(start);
|
|
777
|
+
if (point !== null) {
|
|
778
|
+
references.sourcePoints.set(start, point);
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
const registerTranslationElement = (elementPath, references) => {
|
|
782
|
+
const name = elementPath.get("name");
|
|
783
|
+
if (!name.isJSXIdentifier()) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const kind = translationElementKind(name, name.node.name);
|
|
787
|
+
if (kind === "alias") {
|
|
788
|
+
throw new Error("Translation components must use their imported names");
|
|
789
|
+
}
|
|
790
|
+
if (kind === "canonical") {
|
|
791
|
+
registerElementReference(elementPath, references);
|
|
792
|
+
}
|
|
793
|
+
else if (TRANS_ELEMENTS.has(name.node.name)) {
|
|
794
|
+
registerUnrecognizedElementMasks(elementPath, name, references);
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
const maskUnrecognizedTranslations = (source, references) => {
|
|
798
|
+
let masked = source;
|
|
799
|
+
const masks = references.masks.toSorted((left, right) => right.start - left.start);
|
|
800
|
+
for (const { start, end } of masks) {
|
|
801
|
+
masked = `${masked.slice(0, start)}${"_".repeat(end - start)}${masked.slice(end)}`;
|
|
802
|
+
}
|
|
803
|
+
return masked;
|
|
804
|
+
};
|
|
805
|
+
const translationReferences = (root, path, source, lang) => {
|
|
806
|
+
const parsed = parseTranslationReferences(root, path, source, lang);
|
|
807
|
+
if (parsed === null) {
|
|
808
|
+
throw new Error(`Translation extraction could not parse ${path}`);
|
|
809
|
+
}
|
|
810
|
+
const references = {
|
|
811
|
+
calls: new Set(),
|
|
812
|
+
elements: new Set(),
|
|
813
|
+
entryLocations: new Map(),
|
|
814
|
+
locations: new Map(),
|
|
815
|
+
masks: [],
|
|
816
|
+
sourcePoints: new Map(),
|
|
817
|
+
};
|
|
818
|
+
traverse(parsed, {
|
|
819
|
+
CallExpression(callPath) {
|
|
820
|
+
atSourceNode(root, path, callPath.node, () => {
|
|
821
|
+
registerTranslationCall(callPath, references);
|
|
822
|
+
});
|
|
823
|
+
},
|
|
824
|
+
JSXOpeningElement(elementPath) {
|
|
825
|
+
atSourceNode(root, path, elementPath.node, () => {
|
|
826
|
+
registerTranslationElement(elementPath, references);
|
|
827
|
+
});
|
|
828
|
+
},
|
|
829
|
+
OptionalCallExpression(callPath) {
|
|
830
|
+
atSourceNode(root, path, callPath.node, () => {
|
|
831
|
+
assertSupportedOptionalCall(callPath);
|
|
832
|
+
});
|
|
833
|
+
},
|
|
834
|
+
TaggedTemplateExpression(tagPath) {
|
|
835
|
+
atSourceNode(root, path, tagPath.node, () => {
|
|
836
|
+
assertUnsupportedTranslationTag(tagPath);
|
|
837
|
+
});
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
return references;
|
|
841
|
+
};
|
|
842
|
+
const assertSupportedTranslationCall = (node, references) => {
|
|
843
|
+
if (!references.calls.has(node.start)) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
assertStaticTranslationKey(node.arguments[0]);
|
|
847
|
+
assertSupportedTranslationOptions(node.arguments[1], node.arguments[2]);
|
|
848
|
+
};
|
|
849
|
+
const assertSupportedTranslationOptions = (second, third) => {
|
|
850
|
+
if (third !== undefined && third !== null) {
|
|
851
|
+
assertStaticTranslationKey(second);
|
|
852
|
+
assertSupportedOptionObject(third);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (second === undefined || second === null || isStaticTranslationKey(second)) {
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
assertSupportedOptionObject(second);
|
|
859
|
+
};
|
|
860
|
+
const isNamedJsxAttribute = (attribute, name) => attribute.name.type === "JSXIdentifier" && attribute.name.name === name;
|
|
861
|
+
const assertSupportedTransKey = (attribute) => {
|
|
862
|
+
if (!isNamedJsxAttribute(attribute, "i18nKey")) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const key = attribute.value?.type === "JSXExpressionContainer"
|
|
866
|
+
? attribute.value.expression
|
|
867
|
+
: attribute.value;
|
|
868
|
+
assertStaticTranslationKey(key);
|
|
869
|
+
};
|
|
870
|
+
const assertSupportedTransStringAttribute = (attribute, name) => {
|
|
871
|
+
if (!isNamedJsxAttribute(attribute, name)) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const value = attribute.value?.type === "JSXExpressionContainer"
|
|
875
|
+
? attribute.value.expression
|
|
876
|
+
: attribute.value;
|
|
877
|
+
assertStaticTranslationKey(value);
|
|
878
|
+
};
|
|
879
|
+
const assertSupportedTransOptions = (attribute) => {
|
|
880
|
+
if (isNamedJsxAttribute(attribute, "tOptions") && attribute.value?.type === "JSXExpressionContainer") {
|
|
881
|
+
assertSupportedOptionObject(attribute.value.expression);
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
const assertSupportedTransAttribute = (attribute) => {
|
|
885
|
+
if (attribute.type === "JSXSpreadAttribute") {
|
|
886
|
+
throw new Error("Translation extraction requires explicit component properties");
|
|
887
|
+
}
|
|
888
|
+
assertSupportedTransKey(attribute);
|
|
889
|
+
assertSupportedTransStringAttribute(attribute, "context");
|
|
890
|
+
assertSupportedTransStringAttribute(attribute, "defaults");
|
|
891
|
+
assertSupportedTransOptions(attribute);
|
|
892
|
+
};
|
|
893
|
+
const assertSupportedTransElement = (node, references) => {
|
|
894
|
+
if (!references.elements.has(node.start)) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
for (const attribute of node.attributes) {
|
|
898
|
+
assertSupportedTransAttribute(attribute);
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
const assertSupportedTranslationSyntax = (root, path, source) => {
|
|
902
|
+
const lang = sourceLanguage(path);
|
|
903
|
+
if (lang === undefined) {
|
|
904
|
+
return {
|
|
905
|
+
calls: new Set(),
|
|
906
|
+
elements: new Set(),
|
|
907
|
+
entryLocations: new Map(),
|
|
908
|
+
locations: new Map(),
|
|
909
|
+
masks: [],
|
|
910
|
+
sourcePoints: new Map(),
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
let parsed;
|
|
914
|
+
try {
|
|
915
|
+
parsed = parseSync(projectSourcePath(root, path), source, { lang });
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
throw sourceExtractionError(root, path, errorSourcePoint(error), error);
|
|
919
|
+
}
|
|
920
|
+
const references = translationReferences(root, path, source, lang);
|
|
921
|
+
new Visitor({
|
|
922
|
+
CallExpression(node) {
|
|
923
|
+
try {
|
|
924
|
+
assertSupportedTranslationCall(node, references);
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
|
|
928
|
+
}
|
|
929
|
+
},
|
|
930
|
+
JSXOpeningElement(node) {
|
|
931
|
+
try {
|
|
932
|
+
assertSupportedTransElement(node, references);
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
throw sourceExtractionError(root, path, references.sourcePoints.get(node.start) ?? null, error);
|
|
936
|
+
}
|
|
937
|
+
},
|
|
938
|
+
}).visit(parsed.program);
|
|
939
|
+
return references;
|
|
940
|
+
};
|
|
941
|
+
const extractedLocationFile = (root, file) => resolve(root, file);
|
|
942
|
+
const isRecognizedLocation = (root, references, location) => {
|
|
943
|
+
if (location.line === undefined || location.column === undefined) {
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
const sourceReferences = references.get(extractedLocationFile(root, location.file));
|
|
947
|
+
return sourceReferences?.locations.has(sourceLocationKey(location.line, location.column)) === true;
|
|
948
|
+
};
|
|
949
|
+
const recognizedKeyLocations = (references, extractedKey) => {
|
|
950
|
+
const locations = [];
|
|
951
|
+
for (const [file, sourceReferences] of references) {
|
|
952
|
+
const points = sourceReferences.entryLocations.get(extractedKey) ?? [];
|
|
953
|
+
for (const point of points) {
|
|
954
|
+
locations.push({ file, column: point.column, line: point.line });
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return locations;
|
|
958
|
+
};
|
|
959
|
+
const recognizedEntry = (root, references, entry) => {
|
|
960
|
+
const extractedLocations = entry.locations ?? [];
|
|
961
|
+
const locations = extractedLocations.length === 0
|
|
962
|
+
? recognizedKeyLocations(references, entry.key)
|
|
963
|
+
: extractedLocations.filter((location) => isRecognizedLocation(root, references, location));
|
|
964
|
+
return locations.length === 0 ? null : { ...entry, locations };
|
|
965
|
+
};
|
|
966
|
+
const quotedNestedReferenceParts = (content, quote) => {
|
|
967
|
+
const end = content.indexOf(quote, 1);
|
|
968
|
+
return end === -1
|
|
969
|
+
? null
|
|
970
|
+
: { base: content.slice(1, end), options: content.slice(end + 1) };
|
|
971
|
+
};
|
|
972
|
+
const nestedReferenceParts = (value) => {
|
|
973
|
+
const content = value.trim();
|
|
974
|
+
const quote = content[0];
|
|
975
|
+
if (quote === "\"" || quote === "'") {
|
|
976
|
+
return quotedNestedReferenceParts(content, quote);
|
|
977
|
+
}
|
|
978
|
+
const separator = content.indexOf(",");
|
|
979
|
+
const base = (separator === -1 ? content : content.slice(0, separator)).trim();
|
|
980
|
+
return base.length === 0
|
|
981
|
+
? null
|
|
982
|
+
: { base, options: separator === -1 ? "" : content.slice(separator + 1) };
|
|
983
|
+
};
|
|
984
|
+
const nestedReferenceContext = (options) => {
|
|
985
|
+
const match = NESTED_CONTEXT.exec(options);
|
|
986
|
+
const context = match?.[1] ?? match?.[2] ?? null;
|
|
987
|
+
return context === null || context.length === 0 ? null : context;
|
|
988
|
+
};
|
|
989
|
+
const adjustedParenthesisDepth = (character, depth) => {
|
|
990
|
+
if (character === "(") {
|
|
991
|
+
return depth + 1;
|
|
992
|
+
}
|
|
993
|
+
return character === ")" ? depth - 1 : depth;
|
|
994
|
+
};
|
|
995
|
+
const nestedReferenceEnd = (text, start) => {
|
|
996
|
+
let depth = 0;
|
|
997
|
+
const tokens = text.slice(start).matchAll(NESTED_STRUCTURE_TOKEN);
|
|
998
|
+
for (const token of tokens) {
|
|
999
|
+
const character = token[0];
|
|
1000
|
+
if (character === ")" && depth === 0) {
|
|
1001
|
+
return start + token.index;
|
|
1002
|
+
}
|
|
1003
|
+
depth = adjustedParenthesisDepth(character, depth);
|
|
1004
|
+
}
|
|
1005
|
+
return -1;
|
|
1006
|
+
};
|
|
1007
|
+
const nestedReferenceContents = (text) => {
|
|
1008
|
+
const contents = [];
|
|
1009
|
+
let offset = 0;
|
|
1010
|
+
while (offset < text.length) {
|
|
1011
|
+
const prefix = text.indexOf("$t(", offset);
|
|
1012
|
+
if (prefix === -1) {
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
const start = prefix + 3;
|
|
1016
|
+
const end = nestedReferenceEnd(text, start);
|
|
1017
|
+
if (end === -1) {
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
contents.push(text.slice(start, end));
|
|
1021
|
+
offset = end + 1;
|
|
1022
|
+
}
|
|
1023
|
+
return contents;
|
|
1024
|
+
};
|
|
1025
|
+
const nestedPluralKeys = (base, context) => {
|
|
1026
|
+
const pluralBase = context === null ? base : `${base}${CONTEXT_SEPARATOR}${context}`;
|
|
1027
|
+
return [`${pluralBase}_one`, `${pluralBase}_other`];
|
|
1028
|
+
};
|
|
1029
|
+
const nestedReferenceKeys = (content) => {
|
|
1030
|
+
const parts = nestedReferenceParts(content);
|
|
1031
|
+
if (parts === null) {
|
|
1032
|
+
return [];
|
|
1033
|
+
}
|
|
1034
|
+
const context = nestedReferenceContext(parts.options);
|
|
1035
|
+
const contextual = context === null
|
|
1036
|
+
? []
|
|
1037
|
+
: [`${parts.base}_${context}`, `${parts.base}${CONTEXT_SEPARATOR}${context}`];
|
|
1038
|
+
return NESTED_COUNT.test(parts.options)
|
|
1039
|
+
? [parts.base, ...contextual, ...nestedPluralKeys(parts.base, context)]
|
|
1040
|
+
: [parts.base, ...contextual];
|
|
1041
|
+
};
|
|
1042
|
+
const nestedEntryKeys = (text) => {
|
|
1043
|
+
const keys = new Set();
|
|
1044
|
+
for (const content of nestedReferenceContents(text)) {
|
|
1045
|
+
for (const key of nestedReferenceKeys(content)) {
|
|
1046
|
+
keys.add(key);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
return keys;
|
|
1050
|
+
};
|
|
1051
|
+
const registerNestedKeyLocations = (root, references, key, locations) => {
|
|
1052
|
+
for (const location of locations) {
|
|
1053
|
+
if (location.line === undefined || location.column === undefined) {
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
const sourceReferences = references.get(resolve(root, location.file));
|
|
1057
|
+
if (sourceReferences !== undefined) {
|
|
1058
|
+
registerEntryLocation(key, { column: location.column, line: location.line }, sourceReferences);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
const registerNestedTextLocations = (root, references, text, locations) => {
|
|
1063
|
+
for (const key of nestedEntryKeys(text)) {
|
|
1064
|
+
registerNestedKeyLocations(root, references, key, locations);
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
const registerNestedEntryLocations = (root, references, entry, locations) => {
|
|
1068
|
+
registerNestedTextLocations(root, references, entry.key, locations);
|
|
1069
|
+
if (typeof entry.defaultValue === "string") {
|
|
1070
|
+
registerNestedTextLocations(root, references, entry.defaultValue, locations);
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
const didRegisterNestedLocationPass = (root, references, entries, processed) => {
|
|
1074
|
+
let didRegister = false;
|
|
1075
|
+
for (const [mapKey, entry] of entries) {
|
|
1076
|
+
if (processed.has(mapKey)) {
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
const recognized = recognizedEntry(root, references, entry);
|
|
1080
|
+
if (recognized !== null) {
|
|
1081
|
+
processed.add(mapKey);
|
|
1082
|
+
registerNestedEntryLocations(root, references, entry, recognized.locations ?? []);
|
|
1083
|
+
didRegister = true;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return didRegister;
|
|
1087
|
+
};
|
|
1088
|
+
const registerNestedLocations = (root, references, entries) => {
|
|
1089
|
+
const processed = new Set();
|
|
1090
|
+
let hasRegisteredLocations = true;
|
|
1091
|
+
while (hasRegisteredLocations) {
|
|
1092
|
+
hasRegisteredLocations = didRegisterNestedLocationPass(root, references, entries, processed);
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
const retainRecognizedEntries = (root, references, entries) => {
|
|
1096
|
+
for (const [mapKey, entry] of entries) {
|
|
1097
|
+
const recognized = recognizedEntry(root, references, entry);
|
|
1098
|
+
if (recognized === null) {
|
|
1099
|
+
entries.delete(mapKey);
|
|
1100
|
+
}
|
|
1101
|
+
else {
|
|
1102
|
+
entries.set(mapKey, recognized);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
};
|
|
1106
|
+
const fileSourcePointKey = (file, line, column) => `${file}\0${sourceLocationKey(line, column)}`;
|
|
1107
|
+
const registerExtractedSourcePoint = (root, points, location) => {
|
|
1108
|
+
if (location.line !== undefined && location.column !== undefined) {
|
|
1109
|
+
points.add(fileSourcePointKey(resolve(root, location.file), location.line, location.column));
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
const extractedSourcePoints = (root, entries) => {
|
|
1113
|
+
const points = new Set();
|
|
1114
|
+
for (const entry of entries.values()) {
|
|
1115
|
+
const locations = entry.locations ?? [];
|
|
1116
|
+
for (const location of locations) {
|
|
1117
|
+
registerExtractedSourcePoint(root, points, location);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return points;
|
|
1121
|
+
};
|
|
1122
|
+
const missingSourcePoint = (file, references, extracted) => {
|
|
1123
|
+
for (const [location, point] of references.locations) {
|
|
1124
|
+
if (!extracted.has(`${file}\0${location}`)) {
|
|
1125
|
+
return point;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
return null;
|
|
1129
|
+
};
|
|
1130
|
+
const assertAllReferencesExtracted = (root, references, entries) => {
|
|
1131
|
+
const extracted = extractedSourcePoints(root, entries);
|
|
1132
|
+
for (const [file, sourceReferences] of references) {
|
|
1133
|
+
const point = missingSourcePoint(file, sourceReferences, extracted);
|
|
1134
|
+
if (point !== null) {
|
|
1135
|
+
throw sourceExtractionError(root, file, point, new Error("A translation expression could not be extracted safely"));
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
188
1139
|
const findSourceMessages = async (root, sourceFiles) => {
|
|
189
1140
|
if (sourceFiles.length === 0) {
|
|
190
1141
|
clearI18nResources(root);
|
|
191
1142
|
return [];
|
|
192
1143
|
}
|
|
1144
|
+
const sources = new Map(sourceFiles.map((file) => [file, readFileSync(file, "utf8")]));
|
|
1145
|
+
const references = new Map();
|
|
1146
|
+
for (const [file, source] of sources) {
|
|
1147
|
+
references.set(file, assertSupportedTranslationSyntax(root, file, source));
|
|
1148
|
+
}
|
|
193
1149
|
let extracted;
|
|
194
1150
|
const { logger, reports } = quietLogger();
|
|
195
1151
|
const capture = {
|
|
196
1152
|
name: "gtkx-gettext",
|
|
1153
|
+
onLoad(code, path) {
|
|
1154
|
+
const sourceReferences = references.get(resolve(root, path));
|
|
1155
|
+
return sourceReferences === undefined
|
|
1156
|
+
? code
|
|
1157
|
+
: maskUnrecognizedTranslations(code, sourceReferences);
|
|
1158
|
+
},
|
|
197
1159
|
onEnd(keys) {
|
|
1160
|
+
registerNestedLocations(root, references, keys);
|
|
1161
|
+
retainRecognizedEntries(root, references, keys);
|
|
1162
|
+
assertAllReferencesExtracted(root, references, keys);
|
|
198
1163
|
extracted = keys;
|
|
199
1164
|
},
|
|
200
1165
|
};
|
|
@@ -207,8 +1172,7 @@ const findSourceMessages = async (root, sourceFiles) => {
|
|
|
207
1172
|
if (extracted === undefined || reports.length > 0 || result.hasErrors) {
|
|
208
1173
|
throw new Error(reports.join("\n") || "i18next extraction failed");
|
|
209
1174
|
}
|
|
210
|
-
|
|
211
|
-
return sourceMessages(extracted.values().toArray())
|
|
1175
|
+
return sourceMessages(root, extracted.values().toArray())
|
|
212
1176
|
.map((message) => inferLocations(message, sources))
|
|
213
1177
|
.toSorted(compareMessages);
|
|
214
1178
|
};
|
|
@@ -380,5 +1344,5 @@ const extractSourceCatalog = async (project, paths, shouldPreserveMetadataMessag
|
|
|
380
1344
|
writePotfiles(project, sourceFiles);
|
|
381
1345
|
extractCatalogTemplate({ project, messages, shouldPreserveMetadataMessages });
|
|
382
1346
|
};
|
|
383
|
-
export { extractSourceCatalog, extractSourceCatalogTo };
|
|
1347
|
+
export { extractSourceCatalog, extractSourceCatalogTo, SourceExtractionError };
|
|
384
1348
|
//# sourceMappingURL=source-messages.js.map
|