@intlayer/engine 9.5.10 → 9.5.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/installSkills/skills/bundle-optimization.md +123 -0
- package/dist/assets/installSkills/skills/compat.md +0 -4
- package/dist/assets/installSkills/skills/content.md +8 -2
- package/dist/assets/installSkills/skills/next-js.md +2 -2
- package/dist/assets/installSkills/skills/usage.md +1 -1
- package/dist/cjs/build.cjs +5 -0
- package/dist/cjs/cli.cjs +1 -0
- package/dist/cjs/docReview/alignBlocks.cjs +53 -36
- package/dist/cjs/docReview/alignBlocks.cjs.map +1 -1
- package/dist/cjs/docReview/rebuildDocument.cjs +3 -1
- package/dist/cjs/docReview/rebuildDocument.cjs.map +1 -1
- package/dist/cjs/docReview/segmentDocument.cjs +8 -5
- package/dist/cjs/docReview/segmentDocument.cjs.map +1 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs +4 -1
- package/dist/cjs/init/frameworkSetup/nextAppRouter/transforms.cjs.map +1 -1
- package/dist/cjs/init/index.cjs +2 -12
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/backendPackages.cjs +15 -0
- package/dist/cjs/init/utils/backendPackages.cjs.map +1 -0
- package/dist/cjs/init/utils/index.cjs +2 -3
- package/dist/cjs/installMCP/installMCP.cjs +1 -1
- package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
- package/dist/cjs/installSkills/index.cjs +2 -0
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs +9 -8
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs +3 -1
- package/dist/cjs/loadDictionaries/loadLocalDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +4 -6
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/log.cjs +1 -1
- package/dist/cjs/loadDictionaries/log.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs +19 -12
- package/dist/cjs/loadDictionaries/logTypeScriptErrors.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs +18 -0
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs.map +1 -0
- package/dist/cjs/prepareIntlayerServer.cjs +132 -0
- package/dist/cjs/prepareIntlayerServer.cjs.map +1 -0
- package/dist/cjs/scan/analyzeBundleContent.cjs +26 -12
- package/dist/cjs/scan/analyzeBundleContent.cjs.map +1 -1
- package/dist/cjs/scan/calculateScore.cjs +4 -1
- package/dist/cjs/scan/calculateScore.cjs.map +1 -1
- package/dist/cjs/scan/checks.cjs +394 -221
- package/dist/cjs/scan/checks.cjs.map +1 -1
- package/dist/cjs/scan/detection/checkDetails.cjs +56 -0
- package/dist/cjs/scan/detection/checkDetails.cjs.map +1 -0
- package/dist/cjs/scan/detection/classifyInternalLinks.cjs +47 -0
- package/dist/cjs/scan/detection/classifyInternalLinks.cjs.map +1 -0
- package/dist/cjs/scan/detection/detectRoutingStrategy.cjs +143 -0
- package/dist/cjs/scan/detection/detectRoutingStrategy.cjs.map +1 -0
- package/dist/cjs/scan/detection/detectTechnologies.cjs +89 -0
- package/dist/cjs/scan/detection/detectTechnologies.cjs.map +1 -0
- package/dist/cjs/scan/detection/index.cjs +36 -0
- package/dist/cjs/scan/detection/localeCode.cjs +118 -0
- package/dist/cjs/scan/detection/localeCode.cjs.map +1 -0
- package/dist/cjs/scan/detection/localizedPages.cjs +48 -0
- package/dist/cjs/scan/detection/localizedPages.cjs.map +1 -0
- package/dist/cjs/scan/detection/technologySignatures.cjs +564 -0
- package/dist/cjs/scan/detection/technologySignatures.cjs.map +1 -0
- package/dist/cjs/scan/detection/url.cjs +53 -0
- package/dist/cjs/scan/detection/url.cjs.map +1 -0
- package/dist/cjs/scan/fetchText.cjs +56 -0
- package/dist/cjs/scan/fetchText.cjs.map +1 -0
- package/dist/cjs/scan/index.cjs +59 -3
- package/dist/cjs/scan/parseHtml.cjs +55 -10
- package/dist/cjs/scan/parseHtml.cjs.map +1 -1
- package/dist/cjs/scan/robots.cjs +65 -0
- package/dist/cjs/scan/robots.cjs.map +1 -0
- package/dist/cjs/scan/runScanChecks.cjs +89 -0
- package/dist/cjs/scan/runScanChecks.cjs.map +1 -0
- package/dist/cjs/scan/scanWebsite.cjs +58 -52
- package/dist/cjs/scan/scanWebsite.cjs.map +1 -1
- package/dist/cjs/scan/sitemap.cjs +109 -0
- package/dist/cjs/scan/sitemap.cjs.map +1 -0
- package/dist/cjs/utils/chunkJSON.cjs +24 -9
- package/dist/cjs/utils/chunkJSON.cjs.map +1 -1
- package/dist/cjs/utils/getChunk.cjs +2 -2
- package/dist/cjs/utils/getChunk.cjs.map +1 -1
- package/dist/cjs/utils/getProcessChainCommands.cjs +117 -0
- package/dist/cjs/utils/getProcessChainCommands.cjs.map +1 -0
- package/dist/cjs/utils/index.cjs +2 -0
- package/dist/cjs/utils/runParallel/index.cjs +1 -1
- package/dist/cjs/utils/runParallel/index.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/pidTree.cjs +23 -11
- package/dist/cjs/utils/runParallel/pidTree.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/ps.cjs +8 -3
- package/dist/cjs/utils/runParallel/ps.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/runTask.cjs +2 -1
- package/dist/cjs/utils/runParallel/runTask.cjs.map +1 -1
- package/dist/cjs/utils/runParallel/wmic.cjs +8 -3
- package/dist/cjs/utils/runParallel/wmic.cjs.map +1 -1
- package/dist/cjs/utils/startContentWatcher.cjs +99 -0
- package/dist/cjs/utils/startContentWatcher.cjs.map +1 -0
- package/dist/cjs/watcher.cjs +2 -2
- package/dist/cjs/watcher.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs +7 -4
- package/dist/cjs/writeContentDeclaration/detectExportedComponentName.cjs.map +1 -1
- package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs +2 -2
- package/dist/cjs/writeContentDeclaration/writeMarkdownFile.cjs.map +1 -1
- package/dist/cjs/writeJsonIfChanged.cjs.map +1 -1
- package/dist/esm/build.mjs +2 -1
- package/dist/esm/cli.mjs +2 -2
- package/dist/esm/docReview/alignBlocks.mjs +53 -36
- package/dist/esm/docReview/alignBlocks.mjs.map +1 -1
- package/dist/esm/docReview/rebuildDocument.mjs +3 -1
- package/dist/esm/docReview/rebuildDocument.mjs.map +1 -1
- package/dist/esm/docReview/segmentDocument.mjs +8 -5
- package/dist/esm/docReview/segmentDocument.mjs.map +1 -1
- package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs +4 -1
- package/dist/esm/init/frameworkSetup/nextAppRouter/transforms.mjs.map +1 -1
- package/dist/esm/init/index.mjs +1 -11
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/backendPackages.mjs +14 -0
- package/dist/esm/init/utils/backendPackages.mjs.map +1 -0
- package/dist/esm/init/utils/index.mjs +2 -2
- package/dist/esm/installMCP/installMCP.mjs +1 -1
- package/dist/esm/installMCP/installMCP.mjs.map +1 -1
- package/dist/esm/installSkills/index.mjs +2 -0
- package/dist/esm/installSkills/index.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadDictionaries.mjs +9 -8
- package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadLocalDictionaries.mjs +3 -1
- package/dist/esm/loadDictionaries/loadLocalDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +3 -5
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/log.mjs +1 -1
- package/dist/esm/loadDictionaries/log.mjs.map +1 -1
- package/dist/esm/loadDictionaries/logTypeScriptErrors.mjs +19 -12
- package/dist/esm/loadDictionaries/logTypeScriptErrors.mjs.map +1 -1
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs +16 -0
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs.map +1 -0
- package/dist/esm/prepareIntlayerServer.mjs +128 -0
- package/dist/esm/prepareIntlayerServer.mjs.map +1 -0
- package/dist/esm/scan/analyzeBundleContent.mjs +26 -12
- package/dist/esm/scan/analyzeBundleContent.mjs.map +1 -1
- package/dist/esm/scan/calculateScore.mjs +4 -1
- package/dist/esm/scan/calculateScore.mjs.map +1 -1
- package/dist/esm/scan/checks.mjs +387 -220
- package/dist/esm/scan/checks.mjs.map +1 -1
- package/dist/esm/scan/detection/checkDetails.mjs +54 -0
- package/dist/esm/scan/detection/checkDetails.mjs.map +1 -0
- package/dist/esm/scan/detection/classifyInternalLinks.mjs +46 -0
- package/dist/esm/scan/detection/classifyInternalLinks.mjs.map +1 -0
- package/dist/esm/scan/detection/detectRoutingStrategy.mjs +141 -0
- package/dist/esm/scan/detection/detectRoutingStrategy.mjs.map +1 -0
- package/dist/esm/scan/detection/detectTechnologies.mjs +87 -0
- package/dist/esm/scan/detection/detectTechnologies.mjs.map +1 -0
- package/dist/esm/scan/detection/index.mjs +10 -0
- package/dist/esm/scan/detection/localeCode.mjs +108 -0
- package/dist/esm/scan/detection/localeCode.mjs.map +1 -0
- package/dist/esm/scan/detection/localizedPages.mjs +46 -0
- package/dist/esm/scan/detection/localizedPages.mjs.map +1 -0
- package/dist/esm/scan/detection/technologySignatures.mjs +563 -0
- package/dist/esm/scan/detection/technologySignatures.mjs.map +1 -0
- package/dist/esm/scan/detection/url.mjs +47 -0
- package/dist/esm/scan/detection/url.mjs.map +1 -0
- package/dist/esm/scan/fetchText.mjs +55 -0
- package/dist/esm/scan/fetchText.mjs.map +1 -0
- package/dist/esm/scan/index.mjs +15 -3
- package/dist/esm/scan/parseHtml.mjs +52 -11
- package/dist/esm/scan/parseHtml.mjs.map +1 -1
- package/dist/esm/scan/robots.mjs +63 -0
- package/dist/esm/scan/robots.mjs.map +1 -0
- package/dist/esm/scan/runScanChecks.mjs +88 -0
- package/dist/esm/scan/runScanChecks.mjs.map +1 -0
- package/dist/esm/scan/scanWebsite.mjs +59 -53
- package/dist/esm/scan/scanWebsite.mjs.map +1 -1
- package/dist/esm/scan/sitemap.mjs +105 -0
- package/dist/esm/scan/sitemap.mjs.map +1 -0
- package/dist/esm/utils/chunkJSON.mjs +24 -9
- package/dist/esm/utils/chunkJSON.mjs.map +1 -1
- package/dist/esm/utils/getChunk.mjs +2 -2
- package/dist/esm/utils/getChunk.mjs.map +1 -1
- package/dist/esm/utils/getProcessChainCommands.mjs +115 -0
- package/dist/esm/utils/getProcessChainCommands.mjs.map +1 -0
- package/dist/esm/utils/index.mjs +2 -1
- package/dist/esm/utils/runParallel/index.mjs +1 -1
- package/dist/esm/utils/runParallel/index.mjs.map +1 -1
- package/dist/esm/utils/runParallel/pidTree.mjs +23 -11
- package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
- package/dist/esm/utils/runParallel/ps.mjs +8 -3
- package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
- package/dist/esm/utils/runParallel/runTask.mjs +2 -1
- package/dist/esm/utils/runParallel/runTask.mjs.map +1 -1
- package/dist/esm/utils/runParallel/wmic.mjs +8 -3
- package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
- package/dist/esm/utils/startContentWatcher.mjs +98 -0
- package/dist/esm/utils/startContentWatcher.mjs.map +1 -0
- package/dist/esm/watcher.mjs +1 -1
- package/dist/esm/watcher.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/detectExportedComponentName.mjs +7 -4
- package/dist/esm/writeContentDeclaration/detectExportedComponentName.mjs.map +1 -1
- package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs +2 -2
- package/dist/esm/writeContentDeclaration/writeMarkdownFile.mjs.map +1 -1
- package/dist/esm/writeJsonIfChanged.mjs +1 -1
- package/dist/esm/writeJsonIfChanged.mjs.map +1 -1
- package/dist/types/build.d.ts +2 -1
- package/dist/types/cli.d.ts +2 -2
- package/dist/types/docReview/rebuildDocument.d.ts.map +1 -1
- package/dist/types/docReview/segmentDocument.d.ts.map +1 -1
- package/dist/types/init/frameworkSetup/nextAppRouter/transforms.d.ts.map +1 -1
- package/dist/types/init/index.d.ts +1 -1
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/backendPackages.d.ts +5 -0
- package/dist/types/init/utils/backendPackages.d.ts.map +1 -0
- package/dist/types/init/utils/index.d.ts +2 -2
- package/dist/types/installSkills/index.d.ts +1 -0
- package/dist/types/installSkills/index.d.ts.map +1 -1
- package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
- package/dist/types/loadDictionaries/logTypeScriptErrors.d.ts.map +1 -1
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts +14 -0
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts.map +1 -0
- package/dist/types/prepareIntlayerServer.d.ts +67 -0
- package/dist/types/prepareIntlayerServer.d.ts.map +1 -0
- package/dist/types/scan/analyzeBundleContent.d.ts.map +1 -1
- package/dist/types/scan/calculateScore.d.ts +4 -1
- package/dist/types/scan/calculateScore.d.ts.map +1 -1
- package/dist/types/scan/checks.d.ts +114 -21
- package/dist/types/scan/checks.d.ts.map +1 -1
- package/dist/types/scan/detection/checkDetails.d.ts +29 -0
- package/dist/types/scan/detection/checkDetails.d.ts.map +1 -0
- package/dist/types/scan/detection/classifyInternalLinks.d.ts +44 -0
- package/dist/types/scan/detection/classifyInternalLinks.d.ts.map +1 -0
- package/dist/types/scan/detection/detectRoutingStrategy.d.ts +60 -0
- package/dist/types/scan/detection/detectRoutingStrategy.d.ts.map +1 -0
- package/dist/types/scan/detection/detectTechnologies.d.ts +60 -0
- package/dist/types/scan/detection/detectTechnologies.d.ts.map +1 -0
- package/dist/types/scan/detection/index.d.ts +9 -0
- package/dist/types/scan/detection/localeCode.d.ts +49 -0
- package/dist/types/scan/detection/localeCode.d.ts.map +1 -0
- package/dist/types/scan/detection/localizedPages.d.ts +40 -0
- package/dist/types/scan/detection/localizedPages.d.ts.map +1 -0
- package/dist/types/scan/detection/technologySignatures.d.ts +48 -0
- package/dist/types/scan/detection/technologySignatures.d.ts.map +1 -0
- package/dist/types/scan/detection/url.d.ts +27 -0
- package/dist/types/scan/detection/url.d.ts.map +1 -0
- package/dist/types/scan/fetchText.d.ts +30 -0
- package/dist/types/scan/fetchText.d.ts.map +1 -0
- package/dist/types/scan/index.d.ts +16 -4
- package/dist/types/scan/parseHtml.d.ts +17 -0
- package/dist/types/scan/parseHtml.d.ts.map +1 -1
- package/dist/types/scan/robots.d.ts +23 -0
- package/dist/types/scan/robots.d.ts.map +1 -0
- package/dist/types/scan/runScanChecks.d.ts +43 -0
- package/dist/types/scan/runScanChecks.d.ts.map +1 -0
- package/dist/types/scan/scanWebsite.d.ts.map +1 -1
- package/dist/types/scan/sitemap.d.ts +49 -0
- package/dist/types/scan/sitemap.d.ts.map +1 -0
- package/dist/types/scan/types.d.ts +15 -0
- package/dist/types/scan/types.d.ts.map +1 -1
- package/dist/types/utils/chunkJSON.d.ts.map +1 -1
- package/dist/types/utils/getProcessChainCommands.d.ts +35 -0
- package/dist/types/utils/getProcessChainCommands.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +2 -1
- package/dist/types/utils/runParallel/pidTree.d.ts.map +1 -1
- package/dist/types/utils/startContentWatcher.d.ts +40 -0
- package/dist/types/utils/startContentWatcher.d.ts.map +1 -0
- package/dist/types/watcher.d.ts.map +1 -1
- package/dist/types/writeContentDeclaration/writeMarkdownFile.d.ts.map +1 -1
- package/package.json +15 -7
- package/dist/cjs/init/utils/devScript.cjs +0 -57
- package/dist/cjs/init/utils/devScript.cjs.map +0 -1
- package/dist/esm/init/utils/devScript.mjs +0 -55
- package/dist/esm/init/utils/devScript.mjs.map +0 -1
- package/dist/types/init/utils/devScript.d.ts +0 -48
- package/dist/types/init/utils/devScript.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["readAsset","path","fs","getMarkdownMetadata","v"],"sources":["../../../src/installSkills/index.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { readAsset } from 'utils:asset';\nimport { v } from '@intlayer/config/logger';\nimport { getMarkdownMetadata } from '@intlayer/core/markdown';\n\n/**\n * Metadata for each available documentation skill.\n */\nexport const SKILLS_METADATA = {\n Config: 'Intlayer configuration documentation',\n Content: 'Reference for all Intlayer content node types (t, enu, etc.)',\n Markdown:\n 'Markdown / rich text content: md(), MDX components, MarkdownProvider, SSR',\n Usage: 'How to use Intlayer in your project',\n CLI: 'Intlayer CLI commands and usage',\n Compiler:\n 'Intlayer Compiler setup and usage for automatic content extraction without .content files',\n BundleOptimization:\n 'Purge, minify and import modes; writing code the bundle optimizer can follow',\n RemoteContent: 'How to use Intlayer with Remote/CMS/Server-side content',\n DevTools: 'ESLint, LSP, VS Code & Chrome extensions, MCP server and CI/CD',\n Compat:\n 'Migrate from i18next, next-intl, react-intl, vue-i18n, Lingui… keeping their API',\n NextJS: 'Next.js-specific usage (Server & Client components)',\n React: 'React-specific syntax and hooks usage',\n Vue: 'Vue-specific composables and syntax',\n Svelte: 'Svelte-specific stores and syntax',\n Angular: 'Angular-specific syntax and Injectable Function usage',\n Preact: 'Preact-specific syntax and hooks usage',\n Solid: 'Solid-specific syntax and hooks usage',\n Astro: 'Astro-specific usage, middleware and islands',\n Lit: 'Lit-specific ReactiveController usage (useIntlayer, useLocale)',\n Vanilla: 'Framework-less JavaScript usage (vanilla-intlayer)',\n Remix: 'Remix 3 router middleware and request-scoped hooks',\n Backend:\n 'Server-side usage for Express, Fastify, Hono, NestJS, AdonisJS and Elysia',\n} as const;\n\nexport type Skill = keyof typeof SKILLS_METADATA;\n\nexport const SKILLS = Object.keys(SKILLS_METADATA) as Skill[];\n\n/** Skills preselected for every project, whatever its stack. */\nconst BASE_SKILLS: Skill[] = [\n 'Usage',\n 'Content',\n 'Config',\n 'CLI',\n 'Compiler',\n 'BundleOptimization',\n 'DevTools',\n];\n\n/**\n * Packages whose presence in `package.json` preselects a framework skill.\n * Both the framework itself and its Intlayer adapter are listed, so a skill is\n * suggested before and after the adapter is installed.\n */\nconst SKILL_TRIGGER_PACKAGES: Partial<Record<Skill, string[]>> = {\n NextJS: ['next', 'next-intlayer'],\n React: [\n 'react',\n 'react-intlayer',\n 'react-native-intlayer',\n 'react-scripts-intlayer',\n 'lynx-intlayer',\n ],\n Preact: ['preact', 'preact-intlayer'],\n Solid: ['solid-js', '@solidjs/start', 'solid-intlayer'],\n Vue: ['vue', 'nuxt', 'vue-intlayer', 'nuxt-intlayer'],\n Svelte: ['svelte', '@sveltejs/kit', 'svelte-intlayer'],\n Angular: ['@angular/core', '@analogjs/platform', 'angular-intlayer'],\n Astro: ['astro', 'astro-intlayer'],\n Lit: ['lit', 'lit-intlayer'],\n Vanilla: ['vanilla-intlayer'],\n Remix: ['remix', 'remix-intlayer'],\n Compat: [\n 'i18next',\n 'react-i18next',\n 'next-i18next',\n 'next-intl',\n 'use-intl',\n 'react-intl',\n 'vue-i18n',\n '@lingui/core',\n '@lingui/react',\n '@nuxtjs/i18n',\n '@ngx-translate/core',\n '@jsverse/transloco',\n 'svelte-i18n',\n 'next-translate',\n 'node-polyglot',\n 'i18n-js',\n '@intlayer/i18next',\n '@intlayer/react-i18next',\n '@intlayer/next-i18next',\n '@intlayer/next-intl',\n '@intlayer/use-intl',\n '@intlayer/react-intl',\n '@intlayer/vue-i18n',\n '@intlayer/lingui',\n '@intlayer/sync-json-plugin',\n '@intlayer/sync-po-plugin',\n ],\n Backend: [\n 'express',\n 'fastify',\n 'hono',\n 'elysia',\n '@nestjs/core',\n '@adonisjs/core',\n 'express-intlayer',\n 'fastify-intlayer',\n 'hono-intlayer',\n 'elysia-intlayer',\n 'adonis-intlayer',\n ],\n};\n\n/**\n * Resolves the skills to preselect from the project's installed packages.\n *\n * @param dependencies - Merged `dependencies` and `devDependencies` of `package.json`.\n * @returns The base skills plus every framework skill whose packages are installed.\n */\nexport const getInitialSkills = (\n dependencies: Record<string, string>\n): Skill[] => {\n const detectedSkills = SKILLS.filter((skill) =>\n SKILL_TRIGGER_PACKAGES[skill]?.some(\n (packageName) => packageName in dependencies\n )\n );\n\n return [...BASE_SKILLS, ...detectedSkills];\n};\n\nexport interface PlatformMetadata {\n label: string;\n dir: string;\n check?: () => boolean;\n}\n\n/**\n * Metadata and configuration for each supported platform.\n */\nexport const PLATFORMS_METADATA: Record<string, PlatformMetadata> = {\n Cursor: {\n label: 'Cursor',\n dir: '.cursor/skills',\n check: () =>\n process.env.CURSOR === 'true' || process.env.TERM_PROGRAM === 'cursor',\n },\n Windsurf: {\n label: 'Windsurf',\n dir: '.windsurf/skills',\n check: () =>\n process.env.WINDSURF === 'true' ||\n process.env.TERM_PROGRAM === 'windsurf',\n },\n Trae: {\n label: 'Trae',\n dir: '.trae/skills',\n check: () =>\n process.env.TRAE === 'true' || process.env.TERM_PROGRAM === 'trae',\n },\n TraeCN: {\n label: 'Trae CN',\n dir: '.trae/skills',\n check: () => process.env.TRAE_CN === 'true',\n },\n VSCode: {\n label: 'VS Code',\n dir: '.vscode/skills',\n check: () =>\n process.env.VSCODE === 'true' || process.env.TERM_PROGRAM === 'vscode',\n },\n OpenCode: {\n label: 'OpenCode',\n dir: '.opencode/skills',\n check: () => process.env.OPENCODE === 'true',\n },\n Claude: {\n label: 'Claude Code',\n dir: '.claude/skills',\n check: () => process.env.CLAUDE === 'true',\n },\n GitHub: {\n label: 'GitHub Copilot Workspace',\n dir: '.github/skills',\n check: () =>\n process.env.GITHUB_ACTIONS === 'true' || !!process.env.GITHUB_WORKSPACE,\n },\n Antigravity: {\n label: 'Antigravity',\n dir: '.agent/skills',\n },\n Augment: {\n label: 'Augment',\n dir: '.augment/skills',\n },\n OpenClaw: {\n label: 'OpenClaw',\n dir: 'skills',\n },\n Cline: {\n label: 'Cline',\n dir: '.cline/skills',\n },\n CodeBuddy: {\n label: 'CodeBuddy',\n dir: '.codebuddy/skills',\n },\n CommandCode: {\n label: 'Command Code',\n dir: '.commandcode/skills',\n },\n Continue: {\n label: 'Continue',\n dir: '.continue/skills',\n },\n Crush: {\n label: 'Crush',\n dir: '.crush/skills',\n },\n Droid: {\n label: 'Droid',\n dir: '.factory/skills',\n },\n Goose: {\n label: 'Goose',\n dir: '.goose/skills',\n },\n IFlow: {\n label: 'iFlow CLI',\n dir: '.iflow/skills',\n },\n Junie: {\n label: 'Junie',\n dir: '.junie/skills',\n },\n KiloCode: {\n label: 'Kilo Code',\n dir: '.kilocode/skills',\n },\n Kiro: {\n label: 'Kiro CLI',\n dir: '.kiro/skills',\n },\n Kode: {\n label: 'Kode',\n dir: '.kode/skills',\n },\n MCPJam: {\n label: 'MCPJam',\n dir: '.mcpjam/skills',\n },\n MistralVibe: {\n label: 'Mistral Vibe',\n dir: '.vibe/skills',\n },\n Mux: {\n label: 'Mux',\n dir: '.mux/skills',\n },\n OpenHands: {\n label: 'OpenHands',\n dir: '.openhands/skills',\n },\n Pi: {\n label: 'Pi',\n dir: '.pi/skills',\n },\n Qoder: {\n label: 'Qoder',\n dir: '.qoder/skills',\n },\n Qwen: {\n label: 'Qwen Code',\n dir: '.qwen/skills',\n },\n RooCode: {\n label: 'Roo Code',\n dir: '.roo/skills',\n },\n Zencoder: {\n label: 'Zencoder',\n dir: '.zencoder/skills',\n },\n Neovate: {\n label: 'Neovate',\n dir: '.neovate/skills',\n },\n Pochi: {\n label: 'Pochi',\n dir: '.pochi/skills',\n },\n Other: {\n label: 'Other',\n dir: 'skills',\n },\n} as const;\n\nexport type Platform = keyof typeof PLATFORMS_METADATA;\n\nexport const PLATFORMS = Object.keys(PLATFORMS_METADATA) as Platform[];\n\n/**\n * Maps specific skill keys to special filenames if they differ from standard snake_case.\n */\nconst SKILL_FILENAME_MAP: Partial<Record<Skill, string>> = {};\n\n/**\n * Helper to convert CamelCase to kebab-case for directory naming\n */\nconst camelToKebabCase = (str: string) =>\n str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();\n\n/**\n * Reads the raw markdown content for a specific skill from the assets folder.\n */\nconst getSkillContent = (skill: Skill): string => {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const fileName = `./skills/${baseName}.md`;\n\n try {\n return readAsset(fileName);\n } catch {\n console.warn(\n `Warning: Could not read asset for skill: ${skill} at ${fileName}`\n );\n return '';\n }\n};\n\n/**\n * Reads the licence content from the assets folder.\n */\nconst getLicenceContent = (): string => {\n try {\n return readAsset('./LICENCE.md');\n } catch {\n console.warn('Warning: Could not read LICENCE.md asset');\n return '';\n }\n};\n\nconst ALLOWED_FETCH_HOSTS = new Set(['intlayer.org']);\n\n/** Upper bound on the redirect chain a reference URL may take. */\nconst MAX_FETCH_REDIRECTS = 5;\n\n/**\n * Parses a URL and rejects it unless it is an HTTPS address on an allowed host.\n *\n * @param url - Absolute URL to validate.\n * @returns The parsed URL.\n * @throws When the protocol or host is not allowed.\n */\nconst parseAllowedUrl = (url: string | URL): URL => {\n const parsed = new URL(url);\n\n if (\n parsed.protocol !== 'https:' ||\n !ALLOWED_FETCH_HOSTS.has(parsed.hostname)\n ) {\n throw new Error(`Blocked fetch to disallowed host: ${parsed.hostname}`);\n }\n\n return parsed;\n};\n\n/**\n * Fetches the content of a URL using native fetch.\n *\n * Redirects are followed manually so every hop is re-checked against the host\n * allowlist — a redirect off `intlayer.org` is refused rather than silently\n * followed. Letting `fetch` refuse them outright (`redirect: 'error'`) instead\n * reported an unhelpful `TypeError: fetch failed` for a documentation URL that\n * merely moved.\n *\n * @param url - Absolute URL to read.\n * @returns The response body as text.\n */\nconst fetchUrlContent = async (url: string): Promise<string> => {\n let target = parseAllowedUrl(url);\n\n for (let hop = 0; hop <= MAX_FETCH_REDIRECTS; hop++) {\n const response = await fetch(target, { redirect: 'manual' });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n\n if (!location) {\n throw new Error(`Failed to fetch ${url}: redirect without a location`);\n }\n\n target = parseAllowedUrl(new URL(location, target));\n continue;\n }\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\n }\n\n return response.text();\n }\n\n throw new Error(`Failed to fetch ${url}: too many redirects`);\n};\n\n/**\n * Installs skills using the \"Agent Skills\" directory standard.\n * Standard: <PROJECT_ROOT>/<CONFIG_DIR>/skills/<SKILL_NAME>/SKILL.md\n */\nexport const installSkills = async (\n projectRoot: string,\n platform: Platform,\n skills: Skill[]\n): Promise<string> => {\n // Determine destination directory\n const relativeDir = PLATFORMS_METADATA[platform]?.dir ?? 'skills';\n const skillsBaseDir = path.join(projectRoot, relativeDir);\n\n // Ensure the base directory exists\n await fs.mkdir(skillsBaseDir, { recursive: true });\n\n const createdSkills: string[] = [];\n const licenceContent = getLicenceContent();\n\n for (const skill of skills) {\n const baseName = SKILL_FILENAME_MAP[skill] ?? camelToKebabCase(skill);\n const skillName = `intlayer-${baseName}`;\n const skillContent = getSkillContent(skill);\n\n if (!skillContent) continue;\n\n // Extract unique URLs\n const urls = Array.from(\n new Set(skillContent.match(/https:\\/\\/intlayer\\.org\\/[^\\s)]+\\.md/g) || [])\n );\n\n // Agent Standard: .../skills/<skill-name>/SKILL.md\n const skillDir = path.join(skillsBaseDir, skillName);\n const referenceDir = path.join(skillDir, 'references');\n\n // Ensure directories exist\n await fs.mkdir(referenceDir, { recursive: true });\n\n // Write License\n if (licenceContent) {\n await fs.writeFile(\n path.join(skillDir, 'LICENCE.md'),\n licenceContent,\n 'utf-8'\n );\n }\n\n let updatedSkillContent = skillContent;\n\n // Parallel download of references\n const downloadPromises = urls.map(async (url) => {\n try {\n const content = await fetchUrlContent(url);\n const metadata = getMarkdownMetadata<{ slugs?: string[] }>(content);\n\n let fileName = '';\n\n // Determine filename from slugs or URL path\n if (Array.isArray(metadata.slugs)) {\n fileName = metadata.slugs\n .filter((slug) => slug !== 'doc')\n .join('_')\n // Scoped package slugs (`@intlayer/babel`) must not create subfolders\n .replaceAll('/', '_');\n } else {\n const urlPath = new URL(url).pathname;\n fileName = urlPath\n .split('/')\n .filter((part) => part && part !== 'doc')\n .map((part) => part.replace('.md', '')) // Clean extension for joining\n .join('_');\n }\n\n // Ensure it ends with .md\n fileName = fileName ? `${fileName}.md` : 'index.md';\n const localRefPath = `references/${fileName}`;\n\n return {\n url,\n localRefPath,\n fileName,\n content,\n success: true,\n };\n } catch (error) {\n console.warn(\n `Warning: Failed to download ref ${url} for skill ${skill}`,\n error\n );\n return { url, success: false };\n }\n });\n\n const results = await Promise.all(downloadPromises);\n\n // Process results: Write files and update content string\n for (const res of results) {\n if (res.success && res.fileName && res.content && res.localRefPath) {\n // Write the reference file\n await fs.writeFile(\n path.join(referenceDir, res.fileName),\n res.content,\n 'utf-8'\n );\n\n // Update the main content to point to local file\n updatedSkillContent = updatedSkillContent.replaceAll(\n res.url,\n res.localRefPath\n );\n }\n }\n\n // Write the main SKILL.md\n const filePath = path.join(skillDir, 'SKILL.md');\n await fs.writeFile(filePath, updatedSkillContent, 'utf-8');\n createdSkills.push(`${skillName}/SKILL.md`);\n }\n\n if (createdSkills.length === 0) {\n return `No skill files were created. Check your asset paths.`;\n }\n\n return `${v} Created ${createdSkills.length} skills in ${skillsBaseDir}`;\n};\n"],"mappings":"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"}
|
|
@@ -81,6 +81,14 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
81
81
|
const { plugins } = configuration;
|
|
82
82
|
const loadDictionariesStartTime = Date.now();
|
|
83
83
|
(0, _intlayer_config_logger.getAppLogger)(configuration)("Dictionaries:", { isVerbose: true });
|
|
84
|
+
const hasRemoteDictionaries = Boolean(configuration.editor.clientId && configuration.editor.clientSecret);
|
|
85
|
+
if (hasRemoteDictionaries) logger.setExpectRemote(true);
|
|
86
|
+
const remoteDictionariesPromise = hasRemoteDictionaries ? require_loadDictionaries_loadRemoteDictionaries.loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {
|
|
87
|
+
onStartRemoteCheck: () => logger.startRemoteCheck(),
|
|
88
|
+
onStopRemoteCheck: () => logger.stopRemoteCheck(),
|
|
89
|
+
onError: (error) => logger.setRemoteError(error)
|
|
90
|
+
}).then((dictionaries) => require_filterInvalidDictionaries.filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => require_formatDictionary.formatDictionaries(dictionaries)) : Promise.resolve([]);
|
|
91
|
+
remoteDictionariesPromise.catch(() => void 0);
|
|
84
92
|
const pluginsWithLoadDictionaries = (await Promise.all(plugins ?? [])).filter((plugin) => plugin.loadDictionaries);
|
|
85
93
|
logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));
|
|
86
94
|
const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(async (plugin) => {
|
|
@@ -103,14 +111,7 @@ const loadDictionaries = async (contentDeclarationsPaths, configuration) => {
|
|
|
103
111
|
status: "built"
|
|
104
112
|
}));
|
|
105
113
|
setLoadDictionariesStatus(localDictionariesStatus);
|
|
106
|
-
const
|
|
107
|
-
if (hasRemoteDictionaries) logger.setExpectRemote(true);
|
|
108
|
-
let remoteDictionaries = [];
|
|
109
|
-
if (hasRemoteDictionaries) remoteDictionaries = await require_loadDictionaries_loadRemoteDictionaries.loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {
|
|
110
|
-
onStartRemoteCheck: () => logger.startRemoteCheck(),
|
|
111
|
-
onStopRemoteCheck: () => logger.stopRemoteCheck(),
|
|
112
|
-
onError: (e) => logger.setRemoteError(e)
|
|
113
|
-
}).then((dictionaries) => require_filterInvalidDictionaries.filterInvalidDictionaries(dictionaries, configuration)).then((dictionaries) => require_formatDictionary.formatDictionaries(dictionaries));
|
|
114
|
+
const remoteDictionaries = await remoteDictionariesPromise;
|
|
114
115
|
const remoteDictionariesTime = Date.now();
|
|
115
116
|
logger.finish();
|
|
116
117
|
printSummary(configuration);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","getAppLogger","colorize","colon","colorizeKey","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations","loadRemoteDictionaries"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error, plugin.name);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n let remoteDictionaries: Dictionary[] = [];\n\n if (hasRemoteDictionaries) {\n remoteDictionaries = await loadRemoteDictionaries(\n configuration,\n setLoadDictionariesStatus,\n {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (e) => logger.setRemoteError(e),\n }\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n }\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loadDictionaries.cjs","names":["DictionariesLogger","ANSIColors","getAppLogger","colorize","colon","colorizeKey","loadRemoteDictionaries","filterInvalidDictionaries","formatDictionaries","loadContentDeclarations"],"sources":["../../../src/loadDictionaries/loadDictionaries.ts"],"sourcesContent":["import * as ANSIColors from '@intlayer/config/colors';\nimport {\n colon,\n colorize,\n colorizeKey,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { filterInvalidDictionaries } from '../filterInvalidDictionaries';\nimport { formatDictionaries } from '../formatDictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\nimport { loadRemoteDictionaries } from './loadRemoteDictionaries';\nimport { DictionariesLogger } from './log';\n\nexport type DictionariesStatus = {\n dictionaryKey: string;\n type: 'local' | 'remote';\n status:\n | 'pending' // Key found but not fetched yet\n | 'fetching' // If dictionary fetch is in progress\n | 'fetched' // If dictionary fetch succeeded\n | 'error' // If dictionary fetch failed\n | 'imported' // If dictionary already fetched and still up to date\n | 'found' // If dictionary key is found but promise is not resolved yet (ex: fetching distant content)\n | 'building' // If dictionary is being built\n | 'built'; // If dictionary is built;\n error?: string;\n};\n\nlet loadDictionariesStatus: DictionariesStatus[] = [];\nconst logger = new DictionariesLogger();\n\nconst setLoadDictionariesStatus = (statuses: DictionariesStatus[]) => {\n const updated: DictionariesStatus[] = [...loadDictionariesStatus];\n\n for (const incoming of statuses) {\n const index = updated.findIndex(\n (s) =>\n s.dictionaryKey === incoming.dictionaryKey && s.type === incoming.type\n );\n if (index >= 0) {\n updated[index] = incoming;\n } else {\n updated.push(incoming);\n }\n }\n\n loadDictionariesStatus = updated;\n logger.update(statuses);\n\n return updated;\n};\n\ntype StatusRecord = {\n local?: DictionariesStatus['status'];\n remote?: DictionariesStatus['status'];\n};\n\nconst iconFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return '✔';\n case 'error':\n return '✖';\n default:\n return '⏲';\n }\n};\n\nconst colorFor = (status: DictionariesStatus['status']) => {\n switch (status) {\n case 'built':\n case 'imported':\n case 'fetched':\n return ANSIColors.GREEN;\n case 'error':\n return ANSIColors.RED;\n default:\n return ANSIColors.BLUE;\n }\n};\n\nconst printSummary = (configuration: IntlayerConfig) => {\n if (configuration.log.mode !== 'verbose') return;\n\n const appLogger = getAppLogger(configuration);\n\n // Aggregate by dictionary key\n const byKey = new Map<string, StatusRecord>();\n for (const status of loadDictionariesStatus) {\n const rec = byKey.get(status.dictionaryKey) ?? {};\n if (status.type === 'local') rec.local = status.status;\n if (status.type === 'remote') rec.remote = status.status;\n byKey.set(status.dictionaryKey, rec);\n }\n\n const keys = Array.from(byKey.keys()).sort((a, b) => a.localeCompare(b));\n\n // Compute the max visible length of the local label to align distant labels\n let maxLocalLabelLen = 0;\n for (const key of keys) {\n const rec = byKey.get(key)!;\n if (rec.local) {\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n if (visibleLocal.length > maxLocalLabelLen) {\n maxLocalLabelLen = visibleLocal.length;\n }\n }\n }\n\n for (const key of keys) {\n const rec = byKey.get(key)!;\n const labels: string[] = [];\n\n if (rec.local) {\n const inner = colorize(\n `${iconFor(rec.local)} ${rec.local}`,\n colorFor(rec.local)\n );\n const coloredLocal =\n `${ANSIColors.GREY}[` +\n colorize('local: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`;\n\n // Pad to align distant label across rows\n const visibleLocal = `[local: ${iconFor(rec.local)} ${rec.local}]`;\n const pad = Math.max(0, maxLocalLabelLen - visibleLocal.length);\n labels.push(coloredLocal + ' '.repeat(pad));\n } else {\n // If no local label, insert spaces to keep distant aligned\n labels.push(' '.repeat(maxLocalLabelLen));\n }\n\n if (rec.remote) {\n const inner = colorize(\n `${iconFor(rec.remote)} ${rec.remote}`,\n colorFor(rec.remote)\n );\n labels.push(\n `${ANSIColors.GREY}[` +\n colorize('distant: ', ANSIColors.GREY) +\n inner +\n `${ANSIColors.GREY}]${ANSIColors.RESET}`\n );\n }\n\n appLogger(\n ` - ${colon(colorizeKey(key), { colSize: keys })} ${labels.join(' ')}`\n );\n }\n};\n\nexport const loadDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<{\n localDictionaries: Dictionary[];\n remoteDictionaries: Dictionary[];\n pluginDictionaries: Dictionary[];\n time: {\n localDictionaries: number;\n remoteDictionaries: number;\n pluginDictionaries: number;\n };\n}> => {\n const { plugins } = configuration;\n const loadDictionariesStartTime = Date.now();\n const appLogger = getAppLogger(configuration);\n\n appLogger('Dictionaries:', { isVerbose: true });\n\n const hasRemoteDictionaries = Boolean(\n configuration.editor.clientId && configuration.editor.clientSecret\n );\n\n if (hasRemoteDictionaries) {\n // We expect to fetch remote dictionaries soon; suppress a transient local-only render\n logger.setExpectRemote(true);\n }\n\n // Started first so the CMS round trips (OAuth2 token, update timestamps)\n // overlap plugin and local loading instead of running after them.\n const remoteDictionariesPromise: Promise<Dictionary[]> = hasRemoteDictionaries\n ? loadRemoteDictionaries(configuration, setLoadDictionariesStatus, {\n onStartRemoteCheck: () => logger.startRemoteCheck(),\n onStopRemoteCheck: () => logger.stopRemoteCheck(),\n onError: (error) => logger.setRemoteError(error),\n })\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries))\n : Promise.resolve([]);\n\n // Awaited later; this keeps an early rejection from being reported as unhandled\n remoteDictionariesPromise.catch(() => undefined);\n\n // Load additional dictionaries via plugins (e.g., ICU JSON ingestion)\n const resolvedPlugins = await Promise.all(plugins ?? []);\n\n const pluginsWithLoadDictionaries = resolvedPlugins.filter(\n (plugin) => plugin.loadDictionaries\n );\n\n logger.setPluginNames(pluginsWithLoadDictionaries.map(({ name }) => name));\n\n const loadPluginDictionariesPromise = pluginsWithLoadDictionaries.map(\n async (plugin) => {\n try {\n const res = await plugin.loadDictionaries?.({\n configuration,\n });\n\n return (res as Dictionary[] | undefined) ?? [];\n } catch (error) {\n logger.setPluginError(error as Error, plugin.name);\n\n return [];\n }\n }\n );\n\n const pluginDictionaries: Dictionary[] = await Promise.all(\n loadPluginDictionariesPromise as Promise<Dictionary[]>[]\n )\n .then((dictionaries) => dictionaries.flat())\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n logger.setPluginTotal(pluginDictionaries.length);\n logger.setPluginDone(pluginDictionaries.length);\n\n const pluginDictionariesTime = Date.now();\n\n const files = Array.isArray(contentDeclarationsPaths)\n ? contentDeclarationsPaths\n : [contentDeclarationsPaths];\n\n const localDictionaries: Dictionary[] = await loadContentDeclarations(\n files,\n configuration,\n setLoadDictionariesStatus\n )\n .then((dictionaries) =>\n filterInvalidDictionaries(dictionaries, configuration)\n )\n .then((dictionaries) => formatDictionaries(dictionaries));\n\n const localDictionariesTime = Date.now();\n\n const localDictionariesStatus = localDictionaries.map(\n (dictionary) =>\n ({\n dictionaryKey: dictionary.key,\n type: 'local',\n status: 'built',\n }) as const\n );\n\n setLoadDictionariesStatus(localDictionariesStatus);\n\n const remoteDictionaries: Dictionary[] = await remoteDictionariesPromise;\n\n const remoteDictionariesTime = Date.now();\n\n // Stop spinner and show final progress line(s)\n logger.finish();\n\n printSummary(configuration);\n\n return {\n localDictionaries,\n remoteDictionaries,\n pluginDictionaries,\n time: {\n localDictionaries: localDictionariesTime - pluginDictionariesTime,\n remoteDictionaries: remoteDictionariesTime - localDictionariesTime,\n pluginDictionaries: pluginDictionariesTime - loadDictionariesStartTime,\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -13,8 +13,10 @@ const loadLocalDictionaries = async (contentDeclarationsPaths, configuration) =>
|
|
|
13
13
|
for await (const contentDeclarationPath of contentDeclarationsPaths) {
|
|
14
14
|
const dictionary = await require_loadDictionaries_loadContentDeclaration.loadContentDeclarations([contentDeclarationPath], configuration);
|
|
15
15
|
const relativeFilePath = (0, node_path.relative)(baseDir, contentDeclarationPath);
|
|
16
|
+
const firstDict = dictionary[0];
|
|
17
|
+
if (!firstDict) continue;
|
|
16
18
|
const dictionaryWithPath = {
|
|
17
|
-
...
|
|
19
|
+
...firstDict,
|
|
18
20
|
filePath: relativeFilePath
|
|
19
21
|
};
|
|
20
22
|
result.push(dictionaryWithPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadLocalDictionaries.cjs","names":["mkdir","resolve","loadContentDeclarations","relative"],"sources":["../../../src/loadDictionaries/loadLocalDictionaries.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\n\nexport const loadLocalDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<Dictionary[]> => {\n const { system } = configuration;\n const { dictionariesDir, baseDir } = system;\n\n if (typeof contentDeclarationsPaths === 'string') {\n contentDeclarationsPaths = [contentDeclarationsPaths];\n }\n\n // Create the dictionaries folder if it doesn't exist\n await mkdir(resolve(dictionariesDir), { recursive: true });\n\n const result: Dictionary[] = [];\n\n for await (const contentDeclarationPath of contentDeclarationsPaths) {\n const dictionary = await loadContentDeclarations(\n [contentDeclarationPath],\n configuration\n );\n\n const relativeFilePath = relative(baseDir, contentDeclarationPath);\n\n const dictionaryWithPath: Dictionary = {\n ...
|
|
1
|
+
{"version":3,"file":"loadLocalDictionaries.cjs","names":["mkdir","resolve","loadContentDeclarations","relative"],"sources":["../../../src/loadDictionaries/loadLocalDictionaries.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { loadContentDeclarations } from './loadContentDeclaration';\n\nexport const loadLocalDictionaries = async (\n contentDeclarationsPaths: string[] | string,\n configuration: IntlayerConfig\n): Promise<Dictionary[]> => {\n const { system } = configuration;\n const { dictionariesDir, baseDir } = system;\n\n if (typeof contentDeclarationsPaths === 'string') {\n contentDeclarationsPaths = [contentDeclarationsPaths];\n }\n\n // Create the dictionaries folder if it doesn't exist\n await mkdir(resolve(dictionariesDir), { recursive: true });\n\n const result: Dictionary[] = [];\n\n for await (const contentDeclarationPath of contentDeclarationsPaths) {\n const dictionary = await loadContentDeclarations(\n [contentDeclarationPath],\n configuration\n );\n\n const relativeFilePath = relative(baseDir, contentDeclarationPath);\n\n const firstDict = dictionary[0];\n if (!firstDict) continue;\n\n const dictionaryWithPath: Dictionary = {\n ...firstDict,\n filePath: relativeFilePath,\n };\n\n result.push(dictionaryWithPath);\n }\n\n return result;\n};\n"],"mappings":";;;;;;AAMA,MAAa,wBAAwB,OACnC,0BACA,kBAC0B;CAC1B,MAAM,EAAE,WAAW;CACnB,MAAM,EAAE,iBAAiB,YAAY;CAErC,IAAI,OAAO,6BAA6B,UACtC,2BAA2B,CAAC,wBAAwB;CAItD,UAAMA,4BAAMC,mBAAQ,eAAe,GAAG,EAAE,WAAW,KAAK,CAAC;CAEzD,MAAM,SAAuB,CAAC;CAE9B,WAAW,MAAM,0BAA0B,0BAA0B;EACnE,MAAM,aAAa,MAAMC,wEACvB,CAAC,sBAAsB,GACvB,aACF;EAEA,MAAM,uBAAmBC,oBAAS,SAAS,sBAAsB;EAEjE,MAAM,YAAY,WAAW;EAC7B,IAAI,CAAC,WAAW;EAEhB,MAAM,qBAAiC;GACrC,GAAG;GACH,UAAU;EACZ;EAEA,OAAO,KAAK,kBAAkB;CAChC;CAEA,OAAO;AACT"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_utils_sortAlphabetically = require('../utils/sortAlphabetically.cjs');
|
|
3
|
-
const require_fetchDistantDictionaries = require('../fetchDistantDictionaries.cjs');
|
|
4
3
|
let _intlayer_config_node = require("@intlayer/config/node");
|
|
5
|
-
let _intlayer_api = require("@intlayer/api");
|
|
6
|
-
let _intlayer_api_dictionary = require("@intlayer/api/dictionary");
|
|
7
4
|
let _intlayer_dictionaries_entry_remote = require("@intlayer/dictionaries-entry/remote");
|
|
8
5
|
|
|
9
6
|
//#region src/loadDictionaries/loadRemoteDictionaries.ts
|
|
@@ -18,7 +15,8 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
18
15
|
if (!Boolean(editor.clientId && editor.clientSecret)) return [];
|
|
19
16
|
try {
|
|
20
17
|
options?.onStartRemoteCheck?.();
|
|
21
|
-
const
|
|
18
|
+
const { createRemoteDictionaryClient, fetchDistantDictionaries } = await Promise.resolve().then(() => require("./remoteDictionaryClient.cjs"));
|
|
19
|
+
const distantDictionaryUpdateTimeStamp = (await createRemoteDictionaryClient(configuration).getDictionariesUpdateTimestamp()).data;
|
|
22
20
|
if (!distantDictionaryUpdateTimeStamp) throw new Error("No distant dictionaries found");
|
|
23
21
|
const dictionariesIdToFetch = Object.entries(distantDictionaryUpdateTimeStamp).filter(([dictionaryId, data]) => {
|
|
24
22
|
if (!data.updatedAt) return true;
|
|
@@ -30,7 +28,7 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
30
28
|
return data.updatedAt > localUpdatedAt;
|
|
31
29
|
});
|
|
32
30
|
const cachedDictionaries = Object.values(remoteDictionariesRecord).flat().filter((dictionary) => {
|
|
33
|
-
const remoteUpdatedAt = distantDictionaryUpdateTimeStamp[dictionary.id]
|
|
31
|
+
const remoteUpdatedAt = dictionary.id ? distantDictionaryUpdateTimeStamp[dictionary.id]?.updatedAt : void 0;
|
|
34
32
|
const localUpdatedAtRaw = dictionary.updatedAt;
|
|
35
33
|
const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
|
|
36
34
|
return typeof localUpdatedAt === "number" && typeof remoteUpdatedAt === "number" && localUpdatedAt >= remoteUpdatedAt;
|
|
@@ -46,7 +44,7 @@ const loadRemoteDictionaries = async (configuration = (0, _intlayer_config_node.
|
|
|
46
44
|
type: "remote",
|
|
47
45
|
status: "pending"
|
|
48
46
|
})));
|
|
49
|
-
const distantDictionariesData = await
|
|
47
|
+
const distantDictionariesData = await fetchDistantDictionaries({ dictionaryKeys: orderedDistantDictionaryKeys }, onStatusUpdate);
|
|
50
48
|
const distantDictionaries = formatDistantDictionaries(distantDictionariesData);
|
|
51
49
|
const fetchedDictionaryIds = new Set(distantDictionaries.map((dictionary) => dictionary.id));
|
|
52
50
|
return [...cachedDictionaries.filter((dictionary) => !fetchedDictionaryIds.has(dictionary.id)), ...distantDictionaries];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["getConfiguration","getRemoteDictionaries","
|
|
1
|
+
{"version":3,"file":"loadRemoteDictionaries.cjs","names":["getConfiguration","getRemoteDictionaries","sortAlphabetically"],"sources":["../../../src/loadDictionaries/loadRemoteDictionaries.ts"],"sourcesContent":["// @ts-ignore @intlayer/backend is not build yet\nimport type { DictionaryAPI } from '@intlayer/backend';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { getRemoteDictionaries } from '@intlayer/dictionaries-entry/remote';\nimport type {\n Dictionary,\n DictionaryId,\n DictionaryKey,\n} from '@intlayer/types/dictionary';\nimport { sortAlphabetically } from '../utils/sortAlphabetically';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport const formatDistantDictionaries = (\n dictionaries: (DictionaryAPI | Dictionary)[]\n): Dictionary[] =>\n dictionaries.map((dict) => ({\n ...dict,\n localId: `${dict.key}::remote::${dict.id}`,\n location: 'remote' as const,\n }));\n\nexport const loadRemoteDictionaries = async (\n configuration = getConfiguration(),\n onStatusUpdate?: (status: DictionariesStatus[]) => void,\n options?: {\n onStartRemoteCheck?: () => void;\n onStopRemoteCheck?: () => void;\n onError?: (error: Error) => void;\n }\n): Promise<Dictionary[]> => {\n const { editor } = configuration;\n const remoteDictionariesRecord = getRemoteDictionaries(configuration);\n\n const hasRemoteDictionaries = Boolean(editor.clientId && editor.clientSecret);\n\n if (!hasRemoteDictionaries) return [];\n\n try {\n options?.onStartRemoteCheck?.();\n\n // Lazy: the CMS client is only needed when remote credentials are set\n const { createRemoteDictionaryClient, fetchDistantDictionaries } =\n await import('./remoteDictionaryClient');\n\n const dictionary = createRemoteDictionaryClient(configuration);\n\n // Get the list of dictionary keys\n const getDictionariesKeysResult =\n await dictionary.getDictionariesUpdateTimestamp();\n\n const distantDictionaryUpdateTimeStamp: Record<\n DictionaryId,\n { key: DictionaryKey; updatedAt: number }\n > | null = getDictionariesKeysResult.data;\n\n if (!distantDictionaryUpdateTimeStamp) {\n throw new Error('No distant dictionaries found');\n }\n\n const dictionariesIdToFetch = Object.entries(\n distantDictionaryUpdateTimeStamp\n ).filter(([dictionaryId, data]) => {\n // If remote doesn't provide updatedAt, fetch to be safe\n if (!data.updatedAt) return true;\n\n // If no local cache exists, fetch\n const local: Dictionary | undefined = remoteDictionariesRecord[\n data.key\n ]?.find((dictionary) => dictionary.id === dictionaryId);\n if (!local) return true;\n\n const localUpdatedAtRaw = (local as any)?.updatedAt as\n | number\n | string\n | undefined;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // If local timestamp missing or older than remote, fetch\n if (typeof localUpdatedAt !== 'number') return true;\n\n return data.updatedAt > localUpdatedAt;\n });\n\n const flatRemoteDictionariesRecord: DictionaryAPI[] = Object.values(\n remoteDictionariesRecord\n ).flat();\n\n const cachedDictionaries: Dictionary[] =\n flatRemoteDictionariesRecord.filter((dictionary) => {\n const remoteUpdatedAt = dictionary.id\n ? distantDictionaryUpdateTimeStamp[dictionary.id]?.updatedAt\n : undefined;\n\n const localUpdatedAtRaw = dictionary.updatedAt;\n\n const localUpdatedAt =\n typeof localUpdatedAtRaw === 'number'\n ? localUpdatedAtRaw\n : localUpdatedAtRaw\n ? new Date(localUpdatedAtRaw).getTime()\n : undefined;\n\n // Consider as cached/imported when local exists and is up-to-date or newer\n return (\n typeof localUpdatedAt === 'number' &&\n typeof remoteUpdatedAt === 'number' &&\n localUpdatedAt >= remoteUpdatedAt\n );\n });\n\n // Report cached as already imported\n if (cachedDictionaries.length > 0) {\n onStatusUpdate?.(\n cachedDictionaries.map((dictionary) => ({\n dictionaryKey: dictionary.key,\n type: 'remote',\n status: 'imported',\n }))\n );\n }\n\n // Several qualified dictionaries can share a key, so keys are deduplicated:\n // one request per key already returns all of its siblings.\n const orderedDistantDictionaryKeys = [\n ...new Set(dictionariesIdToFetch.map(([, data]) => data.key)),\n ].sort(sortAlphabetically);\n\n // Report pending for keys to be fetched so totals are visible immediately\n if (orderedDistantDictionaryKeys.length > 0) {\n onStatusUpdate?.(\n orderedDistantDictionaryKeys.map((key) => ({\n dictionaryKey: key,\n type: 'remote',\n status: 'pending',\n }))\n );\n }\n\n const distantDictionariesData = await fetchDistantDictionaries(\n {\n dictionaryKeys: orderedDistantDictionaryKeys,\n },\n onStatusUpdate\n );\n\n const distantDictionaries: Dictionary[] = formatDistantDictionaries(\n distantDictionariesData\n );\n\n // Fetching by key also returns the up-to-date siblings of a stale\n // dictionary, so drop the cached copies the remote just sent back.\n const fetchedDictionaryIds = new Set(\n distantDictionaries.map((dictionary) => dictionary.id)\n );\n\n const notRefetchedCachedDictionaries = cachedDictionaries.filter(\n (dictionary) => !fetchedDictionaryIds.has(dictionary.id)\n );\n\n return [...notRefetchedCachedDictionaries, ...distantDictionaries];\n } catch (error) {\n options?.onError?.(error as Error);\n return [];\n } finally {\n options?.onStopRemoteCheck?.();\n }\n};\n"],"mappings":";;;;;;AAYA,MAAa,6BACX,iBAEA,aAAa,KAAK,UAAU;CAC1B,GAAG;CACH,SAAS,GAAG,KAAK,IAAI,YAAY,KAAK;CACtC,UAAU;AACZ,EAAE;AAEJ,MAAa,yBAAyB,OACpC,oBAAgBA,wCAAiB,GACjC,gBACA,YAK0B;CAC1B,MAAM,EAAE,WAAW;CACnB,MAAM,+BAA2BC,2DAAsB,aAAa;CAIpE,IAAI,CAF0B,QAAQ,OAAO,YAAY,OAAO,YAEvC,GAAG,OAAO,CAAC;CAEpC,IAAI;EACF,SAAS,qBAAqB;EAG9B,MAAM,EAAE,8BAA8B,6BACpC,2CAAM;EAQR,MAAM,oCAGK,MATQ,6BAA6B,aAI/B,CAAC,CAAC,+BAA+B,EAKd,CAAC;EAErC,IAAI,CAAC,kCACH,MAAM,IAAI,MAAM,+BAA+B;EAGjD,MAAM,wBAAwB,OAAO,QACnC,gCACF,CAAC,CAAC,QAAQ,CAAC,cAAc,UAAU;GAEjC,IAAI,CAAC,KAAK,WAAW,OAAO;GAG5B,MAAM,QAAgC,yBACpC,KAAK,IACN,EAAE,MAAM,eAAe,WAAW,OAAO,YAAY;GACtD,IAAI,CAAC,OAAO,OAAO;GAEnB,MAAM,oBAAqB,OAAe;GAK1C,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,IAAI,OAAO,mBAAmB,UAAU,OAAO;GAE/C,OAAO,KAAK,YAAY;EAC1B,CAAC;EAMD,MAAM,qBAJgD,OAAO,OAC3D,wBACF,CAAC,CAAC,KAG2B,CAAC,CAAC,QAAQ,eAAe;GAClD,MAAM,kBAAkB,WAAW,KAC/B,iCAAiC,WAAW,GAAG,EAAE,YACjD;GAEJ,MAAM,oBAAoB,WAAW;GAErC,MAAM,iBACJ,OAAO,sBAAsB,WACzB,oBACA,oBACE,IAAI,KAAK,iBAAiB,CAAC,CAAC,QAAQ,IACpC;GAGR,OACE,OAAO,mBAAmB,YAC1B,OAAO,oBAAoB,YAC3B,kBAAkB;EAEtB,CAAC;EAGH,IAAI,mBAAmB,SAAS,GAC9B,iBACE,mBAAmB,KAAK,gBAAgB;GACtC,eAAe,WAAW;GAC1B,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAKF,MAAM,+BAA+B,CACnC,GAAG,IAAI,IAAI,sBAAsB,KAAK,GAAG,UAAU,KAAK,GAAG,CAAC,CAC9D,CAAC,CAAC,KAAKC,mDAAkB;EAGzB,IAAI,6BAA6B,SAAS,GACxC,iBACE,6BAA6B,KAAK,SAAS;GACzC,eAAe;GACf,MAAM;GACN,QAAQ;EACV,EAAE,CACJ;EAGF,MAAM,0BAA0B,MAAM,yBACpC,EACE,gBAAgB,6BAClB,GACA,cACF;EAEA,MAAM,sBAAoC,0BACxC,uBACF;EAIA,MAAM,uBAAuB,IAAI,IAC/B,oBAAoB,KAAK,eAAe,WAAW,EAAE,CACvD;EAMA,OAAO,CAAC,GAJ+B,mBAAmB,QACvD,eAAe,CAAC,qBAAqB,IAAI,WAAW,EAAE,CAGjB,GAAG,GAAG,mBAAmB;CACnE,SAAS,OAAO;EACd,SAAS,UAAU,KAAc;EACjC,OAAO,CAAC;CACV,UAAU;EACR,SAAS,oBAAoB;CAC/B;AACF"}
|
|
@@ -109,7 +109,7 @@ var DictionariesLogger = class {
|
|
|
109
109
|
}
|
|
110
110
|
render() {
|
|
111
111
|
const { localTotal, localDone, remoteTotal, remoteDone, pluginTotal, pluginDone } = this.computeProgress();
|
|
112
|
-
const frame = this.spinnerFrames[this.spinnerIndex];
|
|
112
|
+
const frame = this.spinnerFrames[this.spinnerIndex] ?? "";
|
|
113
113
|
const clock = (0, _intlayer_config_logger.colorize)(frame, _intlayer_config_colors.BLUE);
|
|
114
114
|
const lines = [];
|
|
115
115
|
const isLocalDone = localDone === localTotal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.cjs","names":["spinnerFrames","getPrefix","log","extractErrorMessage","colorize","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginNames: string[] = [];\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n /**\n * Register the names of the plugins providing dictionaries.\n * They are displayed next to the plugin progress counters, e.g.\n * `Plugin content: 6/6 (sync-json, load-po)`.\n *\n * @param names - Names of the plugins exposing a `loadDictionaries` hook\n */\n setPluginNames(names: string[]) {\n if (this.isFinished) return;\n // Guard against plugins declared without a name at runtime\n this.pluginNames = names.filter((name) => Boolean(name));\n this.render();\n }\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n /**\n * Flag the plugin line as errored.\n *\n * @param error - Error thrown while loading the plugin dictionaries\n * @param pluginName - Name of the plugin that threw, prefixed to the message\n */\n setPluginError(error?: Error, pluginName?: string) {\n if (this.isFinished) return;\n const errorMessage = extractErrorMessage(error);\n this.pluginError = pluginName\n ? `${pluginName}: ${errorMessage}`\n : errorMessage;\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex];\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts, suffixed by the plugin names\n if (pluginTotal > 0 || this.pluginError) {\n const pluginNamesSuffix =\n this.pluginNames.length > 0\n ? colorize(` (${this.pluginNames.join(', ')})`, ANSIColors.GREY)\n : '';\n\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"log.cjs","names":["spinnerFrames","getPrefix","log","extractErrorMessage","colorize","ANSIColors","v","x"],"sources":["../../../src/loadDictionaries/log.ts"],"sourcesContent":["import { log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport {\n colorize,\n getPrefix,\n spinnerFrames,\n v,\n x,\n} from '@intlayer/config/logger';\nimport { extractErrorMessage } from '@intlayer/config/utils';\nimport type { DictionariesStatus } from './loadDictionaries';\n\nexport class DictionariesLogger {\n private statuses: DictionariesStatus[] = [];\n private spinnerTimer: NodeJS.Timeout | null = null;\n private spinnerIndex = 0;\n private renderedLines = 0;\n private readonly spinnerFrames = spinnerFrames;\n private isFinished = false;\n private readonly prefix: string;\n private lastRenderedState: string = '';\n private remoteCheckInProgress = false;\n private expectRemote = false;\n private remoteError: string | undefined;\n private pluginTotal = 0;\n private pluginDone = 0;\n private pluginNames: string[] = [];\n private pluginError: string | undefined;\n\n constructor() {\n this.prefix = getPrefix(log?.prefix) ?? '';\n }\n\n setExpectRemote(expect: boolean) {\n this.expectRemote = expect;\n }\n\n startRemoteCheck() {\n if (this.isFinished) return;\n this.remoteCheckInProgress = true;\n this.startSpinner();\n this.render();\n }\n\n stopRemoteCheck() {\n this.remoteCheckInProgress = false;\n }\n\n update(newStatuses: DictionariesStatus[]) {\n if (this.isFinished) return;\n for (const status of newStatuses) {\n const index = this.statuses.findIndex(\n (s) =>\n s.dictionaryKey === status.dictionaryKey && s.type === status.type\n );\n if (index >= 0) {\n this.statuses[index] = status;\n } else {\n this.statuses.push(status);\n }\n }\n\n // If we expect remote fetch later, avoid rendering a local-only line first\n const { remoteTotal } = this.computeProgress();\n if (this.expectRemote && !this.remoteCheckInProgress && remoteTotal === 0) {\n // Do not start spinner or render yet; wait until remote check starts\n return;\n }\n\n this.startSpinner();\n this.render();\n }\n\n finish() {\n this.isFinished = true;\n this.stopSpinner();\n // Render final state and keep it visible\n this.render();\n }\n\n private startSpinner() {\n if (this.spinnerTimer || this.isFinished) return;\n this.spinnerTimer = setInterval(() => {\n this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;\n this.render();\n }, 100);\n }\n\n private stopSpinner() {\n if (!this.spinnerTimer) return;\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n\n public setRemoteError = (error?: Error) => {\n this.remoteError = extractErrorMessage(error);\n // Avoid rendering a transient remote-only line while the remote check flag is still true\n // Ensure local + remote are rendered together after a failure\n this.stopRemoteCheck();\n this.render();\n };\n\n /**\n * Register the names of the plugins providing dictionaries.\n * They are displayed next to the plugin progress counters, e.g.\n * `Plugin content: 6/6 (sync-json, load-po)`.\n *\n * @param names - Names of the plugins exposing a `loadDictionaries` hook\n */\n setPluginNames(names: string[]) {\n if (this.isFinished) return;\n // Guard against plugins declared without a name at runtime\n this.pluginNames = names.filter((name) => Boolean(name));\n this.render();\n }\n\n setPluginTotal(total: number) {\n if (this.isFinished) return;\n this.pluginTotal = total;\n if (total > 0) {\n this.startSpinner();\n }\n this.render();\n }\n\n setPluginDone(done: number) {\n if (this.isFinished) return;\n this.pluginDone = done;\n this.render();\n }\n\n /**\n * Flag the plugin line as errored.\n *\n * @param error - Error thrown while loading the plugin dictionaries\n * @param pluginName - Name of the plugin that threw, prefixed to the message\n */\n setPluginError(error?: Error, pluginName?: string) {\n if (this.isFinished) return;\n const errorMessage = extractErrorMessage(error);\n this.pluginError = pluginName\n ? `${pluginName}: ${errorMessage}`\n : errorMessage;\n this.render();\n }\n\n private render() {\n const {\n localTotal,\n localDone,\n remoteTotal,\n remoteDone,\n pluginTotal,\n pluginDone,\n } = this.computeProgress();\n\n const frame = this.spinnerFrames[this.spinnerIndex] ?? '';\n const clock = colorize(frame, ANSIColors.BLUE);\n const lines: string[] = [];\n\n const isLocalDone = localDone === localTotal;\n const isRemoteDone = remoteDone === remoteTotal;\n const isPluginDone = pluginDone === pluginTotal;\n\n const suppressLocalWhileCheckingRemote =\n this.expectRemote && this.remoteCheckInProgress && remoteTotal === 0;\n\n if (!suppressLocalWhileCheckingRemote) {\n if (isLocalDone) {\n lines.push(\n `${this.prefix} ${v} Local content: ${colorize(`${localDone}`, ANSIColors.GREEN)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Local content: ${colorize(`${localDone}`, ANSIColors.BLUE)}${colorize(`/${localTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Single remote line: show error, check, or progress counts\n if (remoteTotal > 0 || this.remoteCheckInProgress || this.remoteError) {\n if (this.remoteError) {\n lines.push(\n `${this.prefix} ${x} Remote content: ${colorize(\n this.remoteError,\n ANSIColors.RED\n )}`\n );\n } else if (remoteTotal === 0) {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize('Check server', ANSIColors.BLUE)}`\n );\n } else if (isRemoteDone) {\n lines.push(\n `${this.prefix} ${v} Remote content: ${colorize(`${remoteDone}`, ANSIColors.GREEN)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Remote content: ${colorize(`${remoteDone}`, ANSIColors.BLUE)}${colorize(`/${remoteTotal}`, ANSIColors.GREY)}`\n );\n }\n }\n\n // Plugin line: show error or progress counts, suffixed by the plugin names\n if (pluginTotal > 0 || this.pluginError) {\n const pluginNamesSuffix =\n this.pluginNames.length > 0\n ? colorize(` (${this.pluginNames.join(', ')})`, ANSIColors.GREY)\n : '';\n\n if (this.pluginError) {\n lines.push(\n `${this.prefix} ${x} Plugin content: ${colorize(\n this.pluginError,\n ANSIColors.RED\n )}`\n );\n } else if (isPluginDone) {\n lines.push(\n `${this.prefix} ${v} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.GREEN)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n } else {\n lines.push(\n `${this.prefix} ${clock} Plugin content: ${colorize(`${pluginDone}`, ANSIColors.BLUE)}${colorize(`/${pluginTotal}`, ANSIColors.GREY)}${pluginNamesSuffix}`\n );\n }\n }\n\n // Check if the state has changed to avoid duplicate rendering\n const currentState = lines.join('\\n');\n if (currentState === this.lastRenderedState) {\n return;\n }\n this.lastRenderedState = currentState;\n\n if (this.renderedLines > 0) {\n process.stdout.write(`\\x1b[${this.renderedLines}F`);\n }\n\n const totalLinesToClear = Math.max(this.renderedLines, lines.length);\n for (let i = 0; i < totalLinesToClear; i++) {\n process.stdout.write('\\x1b[2K');\n const line = lines[i];\n if (line !== undefined) {\n process.stdout.write(line);\n }\n process.stdout.write('\\n');\n }\n\n this.renderedLines = lines.length;\n }\n\n private computeProgress() {\n const localKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'local')\n .map((s) => s.dictionaryKey)\n );\n\n const localDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'local' && (s.status === 'built' || s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n const remoteKeys = new Set(\n this.statuses\n .filter((s) => s.type === 'remote')\n .map((s) => s.dictionaryKey)\n );\n\n const remoteDoneKeys = new Set(\n this.statuses\n .filter(\n (s) =>\n s.type === 'remote' &&\n (s.status === 'fetched' ||\n s.status === 'imported' ||\n s.status === 'error')\n )\n .map((s) => s.dictionaryKey)\n );\n\n return {\n localTotal: localKeys.size,\n localDone: localDoneKeys.size,\n remoteTotal: remoteKeys.size,\n remoteDone: remoteDoneKeys.size,\n pluginTotal: this.pluginTotal,\n pluginDone: this.pluginDone,\n } as const;\n }\n}\n"],"mappings":"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"}
|
|
@@ -58,16 +58,19 @@ const flattenNativeDiagnosticMessage = (diagnostic, depth = 0) => [`${" ".repea
|
|
|
58
58
|
* export only exposes the version. It spawns the bundled `tsgo` binary, which
|
|
59
59
|
* resolves the closest tsconfig of each file.
|
|
60
60
|
*/
|
|
61
|
-
const collectNativeTypeScriptErrors = (NativeAPI, filePaths, baseDir) => {
|
|
61
|
+
const collectNativeTypeScriptErrors = async (NativeAPI, filePaths, baseDir) => {
|
|
62
62
|
const api = new NativeAPI({ cwd: baseDir });
|
|
63
63
|
try {
|
|
64
|
-
const snapshot = api.updateSnapshot({ openFiles: filePaths });
|
|
64
|
+
const snapshot = await api.updateSnapshot({ openFiles: filePaths });
|
|
65
65
|
try {
|
|
66
|
-
return filePaths.
|
|
67
|
-
const program = snapshot.getDefaultProjectForFile(filePath)?.program;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
return (await Promise.all(filePaths.map(async (filePath) => {
|
|
67
|
+
const program = (await snapshot.getDefaultProjectForFile(filePath))?.program;
|
|
68
|
+
if (!program) return [];
|
|
69
|
+
const sourceFile = await program.getSourceFile(filePath);
|
|
70
|
+
if (!sourceFile) return [];
|
|
71
|
+
const syntacticDiagnostics = await program.getSyntacticDiagnostics(filePath);
|
|
72
|
+
const semanticDiagnostics = await program.getSemanticDiagnostics(filePath);
|
|
73
|
+
return [...syntacticDiagnostics, ...semanticDiagnostics].map((diagnostic) => {
|
|
71
74
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(diagnostic.pos);
|
|
72
75
|
return {
|
|
73
76
|
fileName: diagnostic.fileName ?? filePath,
|
|
@@ -76,12 +79,12 @@ const collectNativeTypeScriptErrors = (NativeAPI, filePaths, baseDir) => {
|
|
|
76
79
|
message: flattenNativeDiagnosticMessage(diagnostic)
|
|
77
80
|
};
|
|
78
81
|
});
|
|
79
|
-
});
|
|
82
|
+
}))).flat();
|
|
80
83
|
} finally {
|
|
81
|
-
snapshot.dispose();
|
|
84
|
+
await snapshot.dispose();
|
|
82
85
|
}
|
|
83
86
|
} finally {
|
|
84
|
-
api.close();
|
|
87
|
+
await api.close();
|
|
85
88
|
}
|
|
86
89
|
};
|
|
87
90
|
/**
|
|
@@ -99,9 +102,13 @@ const collectTypeScriptErrors = async (filePaths, baseDir) => {
|
|
|
99
102
|
if (classicTypeScript?.createProgram) return collectClassicTypeScriptErrors(classicTypeScript, filePaths, baseDir);
|
|
100
103
|
let nativeModule;
|
|
101
104
|
try {
|
|
102
|
-
nativeModule = await import("typescript/unstable/
|
|
105
|
+
nativeModule = await import("typescript/unstable/async");
|
|
103
106
|
} catch {
|
|
104
|
-
|
|
107
|
+
try {
|
|
108
|
+
nativeModule = await import("typescript/unstable/sync");
|
|
109
|
+
} catch {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
105
112
|
}
|
|
106
113
|
return collectNativeTypeScriptErrors(nativeModule.API, filePaths, baseDir);
|
|
107
114
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logTypeScriptErrors.cjs","names":["dirname","getAppLogger","extname","resolve"],"sources":["../../../src/loadDictionaries/logTypeScriptErrors.ts"],"sourcesContent":["import { dirname, extname, resolve } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type {\n API as NativeTypeScriptAPI,\n Diagnostic as NativeTypeScriptDiagnostic,\n} from 'typescript/unstable/sync';\n\n/** Diagnostic of the classic (TS <= 6) compiler API. */\ninterface ClassicTypeScriptDiagnostic {\n file?: {\n fileName: string;\n getLineAndCharacterOfPosition: (position: number) => {\n line: number;\n character: number;\n };\n };\n start?: number;\n messageText: string | { messageText: string };\n}\n\n/** Subset of the classic (TS <= 6) compiler API used here. */\ninterface ClassicTypeScriptCompiler {\n findConfigFile: (\n searchPath: string,\n fileExists: (path: string) => boolean,\n configName?: string\n ) => string | undefined;\n sys: {\n fileExists: (path: string) => boolean;\n readFile: (path: string, encoding?: string) => string | undefined;\n };\n parseConfigFileTextToJson: (\n fileName: string,\n jsonText: string\n ) => { config?: Record<string, unknown>; error?: unknown };\n parseJsonConfigFileContent: (\n json: unknown,\n host: unknown,\n basePath: string\n ) => {\n options: Record<string, unknown>;\n };\n createProgram: (\n rootNames: readonly string[],\n options: Record<string, unknown>\n ) => {\n getSourceFile: (fileName: string) => unknown;\n };\n getPreEmitDiagnostics: (\n program: unknown,\n sourceFile?: unknown\n ) => readonly ClassicTypeScriptDiagnostic[];\n flattenDiagnosticMessageText: (\n diagnostic: string | { messageText: string },\n newLine: string\n ) => string;\n}\n\n/** Root module of `typescript`, possibly wrapped in a CJS `default`. */\ntype ClassicTypeScriptModule = Partial<ClassicTypeScriptCompiler> & {\n default?: Partial<ClassicTypeScriptCompiler>;\n};\n\n/** Engine-agnostic diagnostic, with 0-based line and character. */\ninterface TypeScriptError {\n fileName: string;\n line: number;\n character: number;\n message: string;\n}\n\nconst CHECKABLE_EXTENSIONS = [\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.cjs',\n '.mjs',\n '.json',\n];\n\n/**\n * Checks files with the classic compiler API (`typescript` <= 6), which is\n * exposed from the package root.\n */\nconst collectClassicTypeScriptErrors = (\n typescript: ClassicTypeScriptCompiler,\n filePaths: string[],\n baseDir: string\n): TypeScriptError[] => {\n const configFileName = typescript.findConfigFile(\n baseDir,\n typescript.sys.fileExists,\n 'tsconfig.json'\n );\n\n let compilerOptions: Record<string, unknown> = {\n noEmit: true,\n allowJs: true,\n resolveJsonModule: true,\n };\n\n const configFileText = configFileName\n ? typescript.sys.readFile(configFileName)\n : undefined;\n\n if (configFileName && configFileText) {\n const configJson = typescript.parseConfigFileTextToJson(\n configFileName,\n configFileText\n );\n\n if (!configJson.error) {\n const parsedConfig = typescript.parseJsonConfigFileContent(\n configJson.config,\n typescript.sys,\n dirname(configFileName)\n );\n\n const { incremental, tsBuildInfoFile, ...restOptions } =\n parsedConfig.options;\n\n compilerOptions = { ...compilerOptions, ...restOptions, noEmit: true };\n }\n }\n\n const program = typescript.createProgram(filePaths, compilerOptions);\n\n return filePaths.flatMap((filePath) => {\n const sourceFile = program.getSourceFile(filePath);\n\n if (!sourceFile) return [];\n\n return typescript\n .getPreEmitDiagnostics(program, sourceFile)\n .flatMap((diagnostic) => {\n if (!diagnostic.file || diagnostic.start === undefined) return [];\n\n const { line, character } =\n diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n\n return {\n fileName: diagnostic.file.fileName,\n line,\n character,\n message: typescript.flattenDiagnosticMessageText(\n diagnostic.messageText,\n '\\n'\n ),\n };\n });\n });\n};\n\n/** Flattens a native diagnostic message chain, indenting nested messages. */\nconst flattenNativeDiagnosticMessage = (\n diagnostic: NativeTypeScriptDiagnostic,\n depth = 0\n): string =>\n [\n `${' '.repeat(depth)}${diagnostic.text}`,\n ...(diagnostic.messageChain ?? []).map((chainedDiagnostic) =>\n flattenNativeDiagnosticMessage(chainedDiagnostic, depth + 1)\n ),\n ].join('\\n');\n\n/**\n * Checks files with the native API (`typescript` >= 7, Go port), whose root\n * export only exposes the version. It spawns the bundled `tsgo` binary, which\n * resolves the closest tsconfig of each file.\n */\nconst collectNativeTypeScriptErrors = (\n NativeAPI: typeof NativeTypeScriptAPI,\n filePaths: string[],\n baseDir: string\n): TypeScriptError[] => {\n const api = new NativeAPI({ cwd: baseDir });\n\n try {\n const snapshot = api.updateSnapshot({ openFiles: filePaths });\n\n try {\n return filePaths.flatMap((filePath) => {\n const program = snapshot.getDefaultProjectForFile(filePath)?.program;\n const sourceFile = program?.getSourceFile(filePath);\n\n if (!program || !sourceFile) return [];\n\n return [\n ...program.getSyntacticDiagnostics(filePath),\n ...program.getSemanticDiagnostics(filePath),\n ].map((diagnostic) => {\n const { line, character } = sourceFile.getLineAndCharacterOfPosition(\n diagnostic.pos\n );\n\n return {\n fileName: diagnostic.fileName ?? filePath,\n line,\n character,\n message: flattenNativeDiagnosticMessage(diagnostic),\n };\n });\n });\n } finally {\n snapshot.dispose();\n }\n } finally {\n api.close();\n }\n};\n\n/**\n * Resolves the installed TypeScript and returns its errors for the given\n * files, or `undefined` if TypeScript is not installed.\n */\nconst collectTypeScriptErrors = async (\n filePaths: string[],\n baseDir: string\n): Promise<TypeScriptError[] | undefined> => {\n let typescriptModule: ClassicTypeScriptModule;\n\n try {\n // Typed against the installed version, whose root may be version-only (>= 7)\n typescriptModule = (await import(\n 'typescript'\n )) as unknown as ClassicTypeScriptModule;\n } catch {\n return undefined;\n }\n\n const classicTypeScript = typescriptModule.createProgram\n ? typescriptModule\n : typescriptModule.default;\n\n if (classicTypeScript?.createProgram) {\n return collectClassicTypeScriptErrors(\n classicTypeScript as ClassicTypeScriptCompiler,\n filePaths,\n baseDir\n );\n }\n\n let nativeModule: { API: typeof NativeTypeScriptAPI };\n\n try {\n nativeModule = await import('typescript/unstable/sync');\n } catch {\n // Neither the classic nor the native API is available\n return undefined;\n }\n\n return collectNativeTypeScriptErrors(nativeModule.API, filePaths, baseDir);\n};\n\n/**\n * Type-checks content declaration files and logs errors as warnings.\n * Supports both the classic (`typescript` <= 6) and native (>= 7) compilers.\n */\nexport const logTypeScriptErrors = async (\n filePaths: string[],\n configuration: IntlayerConfig\n): Promise<void> => {\n const appLogger = getAppLogger(configuration);\n const baseDir = configuration.system?.baseDir ?? process.cwd();\n\n const filesToCheck = filePaths\n .filter((filePath) => CHECKABLE_EXTENSIONS.includes(extname(filePath)))\n .map((filePath) => resolve(baseDir, filePath));\n\n if (filesToCheck.length === 0) return;\n\n const typeScriptErrors = await collectTypeScriptErrors(filesToCheck, baseDir);\n\n typeScriptErrors?.forEach(({ fileName, line, character, message }) => {\n appLogger(\n `TS Error in ${fileName} (${line + 1},${character + 1}): ${message}`,\n { level: 'warn' }\n );\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logTypeScriptErrors.cjs","names":["dirname","getAppLogger","extname","resolve"],"sources":["../../../src/loadDictionaries/logTypeScriptErrors.ts"],"sourcesContent":["import { dirname, extname, resolve } from 'node:path';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type {\n API as NativeTypeScriptAPI,\n Diagnostic as NativeTypeScriptDiagnostic,\n} from 'typescript/unstable/async';\n\n/** Diagnostic of the classic (TS <= 6) compiler API. */\ninterface ClassicTypeScriptDiagnostic {\n file?: {\n fileName: string;\n getLineAndCharacterOfPosition: (position: number) => {\n line: number;\n character: number;\n };\n };\n start?: number;\n messageText: string | { messageText: string };\n}\n\n/** Subset of the classic (TS <= 6) compiler API used here. */\ninterface ClassicTypeScriptCompiler {\n findConfigFile: (\n searchPath: string,\n fileExists: (path: string) => boolean,\n configName?: string\n ) => string | undefined;\n sys: {\n fileExists: (path: string) => boolean;\n readFile: (path: string, encoding?: string) => string | undefined;\n };\n parseConfigFileTextToJson: (\n fileName: string,\n jsonText: string\n ) => { config?: Record<string, unknown>; error?: unknown };\n parseJsonConfigFileContent: (\n json: unknown,\n host: unknown,\n basePath: string\n ) => {\n options: Record<string, unknown>;\n };\n createProgram: (\n rootNames: readonly string[],\n options: Record<string, unknown>\n ) => {\n getSourceFile: (fileName: string) => unknown;\n };\n getPreEmitDiagnostics: (\n program: unknown,\n sourceFile?: unknown\n ) => readonly ClassicTypeScriptDiagnostic[];\n flattenDiagnosticMessageText: (\n diagnostic: string | { messageText: string },\n newLine: string\n ) => string;\n}\n\n/** Root module of `typescript`, possibly wrapped in a CJS `default`. */\ntype ClassicTypeScriptModule = Partial<ClassicTypeScriptCompiler> & {\n default?: Partial<ClassicTypeScriptCompiler>;\n};\n\n/** Engine-agnostic diagnostic, with 0-based line and character. */\ninterface TypeScriptError {\n fileName: string;\n line: number;\n character: number;\n message: string;\n}\n\nconst CHECKABLE_EXTENSIONS = [\n '.ts',\n '.tsx',\n '.js',\n '.jsx',\n '.cjs',\n '.mjs',\n '.json',\n];\n\n/**\n * Checks files with the classic compiler API (`typescript` <= 6), which is\n * exposed from the package root.\n */\nconst collectClassicTypeScriptErrors = (\n typescript: ClassicTypeScriptCompiler,\n filePaths: string[],\n baseDir: string\n): TypeScriptError[] => {\n const configFileName = typescript.findConfigFile(\n baseDir,\n typescript.sys.fileExists,\n 'tsconfig.json'\n );\n\n let compilerOptions: Record<string, unknown> = {\n noEmit: true,\n allowJs: true,\n resolveJsonModule: true,\n };\n\n const configFileText = configFileName\n ? typescript.sys.readFile(configFileName)\n : undefined;\n\n if (configFileName && configFileText) {\n const configJson = typescript.parseConfigFileTextToJson(\n configFileName,\n configFileText\n );\n\n if (!configJson.error) {\n const parsedConfig = typescript.parseJsonConfigFileContent(\n configJson.config,\n typescript.sys,\n dirname(configFileName)\n );\n\n const { incremental, tsBuildInfoFile, ...restOptions } =\n parsedConfig.options;\n\n compilerOptions = { ...compilerOptions, ...restOptions, noEmit: true };\n }\n }\n\n const program = typescript.createProgram(filePaths, compilerOptions);\n\n return filePaths.flatMap((filePath) => {\n const sourceFile = program.getSourceFile(filePath);\n\n if (!sourceFile) return [];\n\n return typescript\n .getPreEmitDiagnostics(program, sourceFile)\n .flatMap((diagnostic) => {\n if (!diagnostic.file || diagnostic.start === undefined) return [];\n\n const { line, character } =\n diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);\n\n return {\n fileName: diagnostic.file.fileName,\n line,\n character,\n message: typescript.flattenDiagnosticMessageText(\n diagnostic.messageText,\n '\\n'\n ),\n };\n });\n });\n};\n\n/** Flattens a native diagnostic message chain, indenting nested messages. */\nconst flattenNativeDiagnosticMessage = (\n diagnostic: NativeTypeScriptDiagnostic,\n depth = 0\n): string =>\n [\n `${' '.repeat(depth)}${diagnostic.text}`,\n ...(diagnostic.messageChain ?? []).map((chainedDiagnostic) =>\n flattenNativeDiagnosticMessage(chainedDiagnostic, depth + 1)\n ),\n ].join('\\n');\n\n/**\n * Checks files with the native API (`typescript` >= 7, Go port), whose root\n * export only exposes the version. It spawns the bundled `tsgo` binary, which\n * resolves the closest tsconfig of each file.\n */\nconst collectNativeTypeScriptErrors = async (\n NativeAPI: typeof NativeTypeScriptAPI,\n filePaths: string[],\n baseDir: string\n): Promise<TypeScriptError[]> => {\n const api = new NativeAPI({ cwd: baseDir });\n\n try {\n const snapshot = await api.updateSnapshot({ openFiles: filePaths });\n\n try {\n const results = await Promise.all(\n filePaths.map(async (filePath) => {\n const defaultProject =\n await snapshot.getDefaultProjectForFile(filePath);\n const program = defaultProject?.program;\n\n if (!program) return [];\n\n const sourceFile = await program.getSourceFile(filePath);\n\n if (!sourceFile) return [];\n\n const syntacticDiagnostics =\n await program.getSyntacticDiagnostics(filePath);\n const semanticDiagnostics =\n await program.getSemanticDiagnostics(filePath);\n\n return [...syntacticDiagnostics, ...semanticDiagnostics].map(\n (diagnostic) => {\n const { line, character } =\n sourceFile.getLineAndCharacterOfPosition(diagnostic.pos);\n\n return {\n fileName: diagnostic.fileName ?? filePath,\n line,\n character,\n message: flattenNativeDiagnosticMessage(diagnostic),\n };\n }\n );\n })\n );\n\n return results.flat();\n } finally {\n await snapshot.dispose();\n }\n } finally {\n await api.close();\n }\n};\n\n/**\n * Resolves the installed TypeScript and returns its errors for the given\n * files, or `undefined` if TypeScript is not installed.\n */\nconst collectTypeScriptErrors = async (\n filePaths: string[],\n baseDir: string\n): Promise<TypeScriptError[] | undefined> => {\n let typescriptModule: ClassicTypeScriptModule;\n\n try {\n // Typed against the installed version, whose root may be version-only (>= 7)\n typescriptModule = (await import(\n 'typescript'\n )) as unknown as ClassicTypeScriptModule;\n } catch {\n return undefined;\n }\n\n const classicTypeScript = typescriptModule.createProgram\n ? typescriptModule\n : typescriptModule.default;\n\n if (classicTypeScript?.createProgram) {\n return collectClassicTypeScriptErrors(\n classicTypeScript as ClassicTypeScriptCompiler,\n filePaths,\n baseDir\n );\n }\n\n let nativeModule: { API: typeof NativeTypeScriptAPI };\n\n try {\n nativeModule = await import('typescript/unstable/async');\n } catch {\n try {\n nativeModule = (await import('typescript/unstable/sync')) as unknown as {\n API: typeof NativeTypeScriptAPI;\n };\n } catch {\n // Neither the classic nor the native API is available\n return undefined;\n }\n }\n\n return collectNativeTypeScriptErrors(nativeModule.API, filePaths, baseDir);\n};\n\n/**\n * Type-checks content declaration files and logs errors as warnings.\n * Supports both the classic (`typescript` <= 6) and native (>= 7) compilers.\n */\nexport const logTypeScriptErrors = async (\n filePaths: string[],\n configuration: IntlayerConfig\n): Promise<void> => {\n const appLogger = getAppLogger(configuration);\n const baseDir = configuration.system?.baseDir ?? process.cwd();\n\n const filesToCheck = filePaths\n .filter((filePath) => CHECKABLE_EXTENSIONS.includes(extname(filePath)))\n .map((filePath) => resolve(baseDir, filePath));\n\n if (filesToCheck.length === 0) return;\n\n const typeScriptErrors = await collectTypeScriptErrors(filesToCheck, baseDir);\n\n typeScriptErrors?.forEach(({ fileName, line, character, message }) => {\n appLogger(\n `TS Error in ${fileName} (${line + 1},${character + 1}): ${message}`,\n { level: 'warn' }\n );\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_fetchDistantDictionaries = require('../fetchDistantDictionaries.cjs');
|
|
3
|
+
let _intlayer_api = require("@intlayer/api");
|
|
4
|
+
let _intlayer_api_dictionary = require("@intlayer/api/dictionary");
|
|
5
|
+
|
|
6
|
+
//#region src/loadDictionaries/remoteDictionaryClient.ts
|
|
7
|
+
/**
|
|
8
|
+
* Creates the CMS dictionary client.
|
|
9
|
+
*
|
|
10
|
+
* Kept in its own module so `loadRemoteDictionaries` can import it lazily:
|
|
11
|
+
* `@intlayer/api` is only loaded when remote credentials are configured.
|
|
12
|
+
*/
|
|
13
|
+
const createRemoteDictionaryClient = (configuration) => (0, _intlayer_api_dictionary.dictionaryEndpoint)((0, _intlayer_api.createIntlayerCMS)(configuration));
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.createRemoteDictionaryClient = createRemoteDictionaryClient;
|
|
17
|
+
exports.fetchDistantDictionaries = require_fetchDistantDictionaries.fetchDistantDictionaries;
|
|
18
|
+
//# sourceMappingURL=remoteDictionaryClient.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remoteDictionaryClient.cjs","names":["dictionaryEndpoint","createIntlayerCMS"],"sources":["../../../src/loadDictionaries/remoteDictionaryClient.ts"],"sourcesContent":["import { createIntlayerCMS } from '@intlayer/api';\nimport { dictionaryEndpoint } from '@intlayer/api/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\nexport { fetchDistantDictionaries } from '../fetchDistantDictionaries';\n\n/**\n * Creates the CMS dictionary client.\n *\n * Kept in its own module so `loadRemoteDictionaries` can import it lazily:\n * `@intlayer/api` is only loaded when remote credentials are configured.\n */\nexport const createRemoteDictionaryClient = (\n configuration: IntlayerConfig\n): ReturnType<typeof dictionaryEndpoint> =>\n dictionaryEndpoint(createIntlayerCMS(configuration));\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,gCACX,sBAEAA,iDAAmBC,iCAAkB,aAAa,CAAC"}
|