@warlock.js/core 5.24.0 → 5.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -1
- package/bin/warlock.js +0 -0
- package/esm/application/application.d.mts +21 -0
- package/esm/application/application.d.mts.map +1 -1
- package/esm/application/application.mjs +29 -1
- package/esm/application/application.mjs.map +1 -1
- package/esm/application/boot-signal.d.mts +2 -1
- package/esm/application/boot-signal.d.mts.map +1 -1
- package/esm/application/boot-signal.mjs.map +1 -1
- package/esm/application/index.d.mts +1 -0
- package/esm/application/index.mjs +1 -0
- package/esm/application/roles.d.mts +72 -0
- package/esm/application/roles.d.mts.map +1 -0
- package/esm/application/roles.mjs +124 -0
- package/esm/application/roles.mjs.map +1 -0
- package/esm/cli/commands/add.command.mjs.map +1 -1
- package/esm/cli/commands/create-database.command.mjs.map +1 -1
- package/esm/cli/commands/dev-server.command.mjs.map +1 -1
- package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/index.mjs +2 -0
- package/esm/cli/commands/doctor/checks/index.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs +170 -0
- package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/doctor-command.action.mjs +7 -2
- package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -1
- package/esm/cli/commands/doctor.command.mjs +5 -0
- package/esm/cli/commands/doctor.command.mjs.map +1 -1
- package/esm/cli/commands/drop-tables.command.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/module.generator.mjs +1 -12
- package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/path-resolver.mjs.map +1 -1
- package/esm/cli/commands/migrate.command.mjs.map +1 -1
- package/esm/cli/commands/routes.command.mjs.map +1 -1
- package/esm/cli/commands/seed.command.mjs.map +1 -1
- package/esm/cli/commands/start-production.command.mjs +54 -5
- package/esm/cli/commands/start-production.command.mjs.map +1 -1
- package/esm/cli/commands/storage-put.action.mjs.map +1 -1
- package/esm/cli/commands/storage-put.command.mjs.map +1 -1
- package/esm/cli/commands/typings-generator.command.mjs +20 -1
- package/esm/cli/commands/typings-generator.command.mjs.map +1 -1
- package/esm/cli/commands/update.command.mjs.map +1 -1
- package/esm/cli/commands-loader.mjs.map +1 -1
- package/esm/config/config-loader.d.mts.map +1 -1
- package/esm/config/config-loader.mjs +3 -1
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/connectors/connectors-manager.mjs.map +1 -1
- package/esm/connectors/database-connector.mjs.map +1 -1
- package/esm/connectors/herald-connector.mjs.map +1 -1
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +7 -0
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/logger-connector.mjs.map +1 -1
- package/esm/connectors/mail-connector.mjs.map +1 -1
- package/esm/connectors/types.d.mts +8 -0
- package/esm/connectors/types.d.mts.map +1 -1
- package/esm/connectors/types.mjs.map +1 -1
- package/esm/database/create-database-action.mjs.map +1 -1
- package/esm/database/drop-tables-action.mjs.map +1 -1
- package/esm/database/migrate-action.mjs +4 -3
- package/esm/database/migrate-action.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.mjs.map +1 -1
- package/esm/database/seed-command-action.mjs +2 -1
- package/esm/database/seed-command-action.mjs.map +1 -1
- package/esm/dev-server/dependency-graph.mjs.map +1 -1
- package/esm/dev-server/development-server.mjs +2 -0
- package/esm/dev-server/development-server.mjs.map +1 -1
- package/esm/dev-server/files-orchestrator.mjs.map +1 -1
- package/esm/dev-server/layer-executor.mjs.map +1 -1
- package/esm/dev-server/legacy-locales-warning.mjs +16 -0
- package/esm/dev-server/legacy-locales-warning.mjs.map +1 -0
- package/esm/dev-server/manifest-manager.mjs.map +1 -1
- package/esm/dev-server/module-loader.mjs +26 -5
- package/esm/dev-server/module-loader.mjs.map +1 -1
- package/esm/dev-server/register-installed-devtools.mjs +47 -0
- package/esm/dev-server/register-installed-devtools.mjs.map +1 -0
- package/esm/dev-server/run-connector-typings.mjs +28 -0
- package/esm/dev-server/run-connector-typings.mjs.map +1 -0
- package/esm/dev-server/special-file-patterns.mjs +5 -3
- package/esm/dev-server/special-file-patterns.mjs.map +1 -1
- package/esm/dev-server/special-files-collector.d.mts +2 -2
- package/esm/dev-server/special-files-collector.d.mts.map +1 -1
- package/esm/dev-server/special-files-collector.mjs +7 -4
- package/esm/dev-server/special-files-collector.mjs.map +1 -1
- package/esm/dev-server/translation-keys-sources.mjs +7 -3
- package/esm/dev-server/translation-keys-sources.mjs.map +1 -1
- package/esm/dev-server/type-generator.mjs +27 -4
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/encryption/password.mjs.map +1 -1
- package/esm/generations/add-command.action.mjs +3 -1
- package/esm/generations/add-command.action.mjs.map +1 -1
- package/esm/generations/features/access.feature.mjs +38 -18
- package/esm/generations/features/access.feature.mjs.map +1 -1
- package/esm/generations/features/ai-anthropic.feature.mjs.map +1 -1
- package/esm/generations/features/ai-bedrock.feature.mjs.map +1 -1
- package/esm/generations/features/ai-google.feature.mjs.map +1 -1
- package/esm/generations/features/ai-ollama.feature.mjs.map +1 -1
- package/esm/generations/features/ai-openai.feature.mjs.map +1 -1
- package/esm/generations/features/ai-panoptic.feature.mjs.map +1 -1
- package/esm/generations/features/ai-tools.feature.mjs.map +1 -1
- package/esm/generations/features/ai-workspace.feature.mjs.map +1 -1
- package/esm/generations/features/ai.feature.mjs.map +1 -1
- package/esm/generations/features/bull-board.feature.mjs +2 -2
- package/esm/generations/features/bull-board.feature.mjs.map +1 -1
- package/esm/generations/features/devtools.feature.mjs +23 -0
- package/esm/generations/features/devtools.feature.mjs.map +1 -0
- package/esm/generations/features/herald.feature.mjs.map +1 -1
- package/esm/generations/features/image.feature.mjs.map +1 -1
- package/esm/generations/features/index.mjs +2 -0
- package/esm/generations/features/index.mjs.map +1 -1
- package/esm/generations/features/mail.feature.mjs.map +1 -1
- package/esm/generations/features/mongodb.feature.mjs.map +1 -1
- package/esm/generations/features/notifications.feature.mjs.map +1 -1
- package/esm/generations/features/postgres.feature.mjs.map +1 -1
- package/esm/generations/features/react-email.feature.mjs.map +1 -1
- package/esm/generations/features/react.feature.mjs.map +1 -1
- package/esm/generations/features/redis.feature.mjs.map +1 -1
- package/esm/generations/features/s3.feature.mjs.map +1 -1
- package/esm/generations/features/scheduler.feature.mjs.map +1 -1
- package/esm/generations/features/ses.feature.mjs.map +1 -1
- package/esm/generations/features/socket.feature.mjs.map +1 -1
- package/esm/generations/features/test.feature.mjs +6 -2
- package/esm/generations/features/test.feature.mjs.map +1 -1
- package/esm/generations/features/types.mjs.map +1 -1
- package/esm/generations/features/web.feature.mjs.map +1 -1
- package/esm/http/build-rate-limit-options.d.mts +8 -2
- package/esm/http/build-rate-limit-options.d.mts.map +1 -1
- package/esm/http/build-rate-limit-options.mjs +1 -0
- package/esm/http/build-rate-limit-options.mjs.map +1 -1
- package/esm/http/database/RequestLog.mjs.map +1 -1
- package/esm/http/errors/errors.d.mts +1 -17
- package/esm/http/errors/errors.d.mts.map +1 -1
- package/esm/http/errors/errors.mjs +1 -20
- package/esm/http/errors/errors.mjs.map +1 -1
- package/esm/http/index.d.mts +4 -3
- package/esm/http/index.mjs +3 -2
- package/esm/http/middleware/inject-request-context.d.mts +1 -1
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +9 -1
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.d.mts.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs +5 -1
- package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
- package/esm/http/request.d.mts +7 -24
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +1 -22
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.d.mts +5 -5
- package/esm/http/response.d.mts.map +1 -1
- package/esm/http/response.mjs +4 -2
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/server-rebuilt.d.mts +20 -0
- package/esm/http/server-rebuilt.d.mts.map +1 -0
- package/esm/http/server-rebuilt.mjs +21 -0
- package/esm/http/server-rebuilt.mjs.map +1 -0
- package/esm/http/tracing/index.mjs +1 -1
- package/esm/http/tracing/tracing-dispatcher.d.mts +13 -6
- package/esm/http/tracing/tracing-dispatcher.d.mts.map +1 -1
- package/esm/http/tracing/tracing-dispatcher.mjs +46 -14
- package/esm/http/tracing/tracing-dispatcher.mjs.map +1 -1
- package/esm/http/tracing/tracing.type.d.mts +2 -1
- package/esm/http/tracing/tracing.type.d.mts.map +1 -1
- package/esm/http/types.d.mts +9 -0
- package/esm/http/types.d.mts.map +1 -1
- package/esm/image/image.mjs.map +1 -1
- package/esm/index.d.mts +8 -4
- package/esm/index.mjs +8 -3
- package/esm/loader/app-module-importer.d.mts +17 -0
- package/esm/loader/app-module-importer.d.mts.map +1 -0
- package/esm/loader/app-module-importer.mjs +20 -0
- package/esm/loader/app-module-importer.mjs.map +1 -0
- package/esm/localization/index.mjs +4 -0
- package/esm/localization/parse-locale-dictionary.d.mts +23 -0
- package/esm/localization/parse-locale-dictionary.d.mts.map +1 -0
- package/esm/localization/parse-locale-dictionary.mjs +215 -0
- package/esm/localization/parse-locale-dictionary.mjs.map +1 -0
- package/esm/localization/register-locale-dictionary.d.mts +12 -0
- package/esm/localization/register-locale-dictionary.d.mts.map +1 -0
- package/esm/localization/register-locale-dictionary.mjs +58 -0
- package/esm/localization/register-locale-dictionary.mjs.map +1 -0
- package/esm/logger/logger.mjs.map +1 -1
- package/esm/mail/events.d.mts +7 -0
- package/esm/mail/events.d.mts.map +1 -1
- package/esm/mail/events.mjs +7 -0
- package/esm/mail/events.mjs.map +1 -1
- package/esm/mail/send-mail.d.mts.map +1 -1
- package/esm/mail/send-mail.mjs +23 -2
- package/esm/mail/send-mail.mjs.map +1 -1
- package/esm/mail/types.d.mts +5 -1
- package/esm/mail/types.d.mts.map +1 -1
- package/esm/mail/types.mjs.map +1 -1
- package/esm/manifest/manifest-manager.mjs.map +1 -1
- package/esm/production/build-contributions.mjs +19 -3
- package/esm/production/build-contributions.mjs.map +1 -1
- package/esm/production/production-builder.mjs +39 -10
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/production-supervisor.mjs +6 -0
- package/esm/production/production-supervisor.mjs.map +1 -1
- package/esm/production/resolve-build-config.d.mts +1 -1
- package/esm/production/resolve-build-config.mjs +15 -0
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/production/route-registration-child.mjs +14 -2
- package/esm/production/route-registration-child.mjs.map +1 -1
- package/esm/production/route-registration-snapshot.mjs +9 -2
- package/esm/production/route-registration-snapshot.mjs.map +1 -1
- package/esm/resource/resource-field-builder.mjs +1 -1
- package/esm/resource/resource-field-builder.mjs.map +1 -1
- package/esm/resource/resource.d.mts +5 -0
- package/esm/resource/resource.d.mts.map +1 -1
- package/esm/resource/resource.mjs +17 -6
- package/esm/resource/resource.mjs.map +1 -1
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +1 -0
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +10 -1
- package/esm/router/types.d.mts.map +1 -1
- package/esm/tests/index.d.mts +3 -2
- package/esm/tests/index.mjs +3 -2
- package/esm/tests/start-http-development-server.d.mts +10 -0
- package/esm/tests/start-http-development-server.d.mts.map +1 -1
- package/esm/tests/start-http-development-server.mjs +16 -2
- package/esm/tests/start-http-development-server.mjs.map +1 -1
- package/esm/tests/vitest-setup.d.mts +16 -1
- package/esm/tests/vitest-setup.d.mts.map +1 -1
- package/esm/tests/vitest-setup.mjs +20 -2
- package/esm/tests/vitest-setup.mjs.map +1 -1
- package/esm/use-cases/use-case-events.mjs.map +1 -1
- package/esm/utils/is-test-file.mjs +15 -0
- package/esm/utils/is-test-file.mjs.map +1 -0
- package/esm/utils/normalized-path.d.mts +3 -1
- package/esm/utils/normalized-path.d.mts.map +1 -1
- package/esm/utils/normalized-path.mjs +4 -2
- package/esm/utils/normalized-path.mjs.map +1 -1
- package/esm/utils/paths.mjs.map +1 -1
- package/esm/validation/plugins/database-plugin.mjs.map +1 -1
- package/esm/validation/validateAll.mjs +57 -4
- package/esm/validation/validateAll.mjs.map +1 -1
- package/esm/warlock-config/default-configurations.mjs +1 -0
- package/esm/warlock-config/default-configurations.mjs.map +1 -1
- package/esm/warlock-config/types.d.mts +7 -0
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
- package/llms-full.txt +382 -214
- package/llms.txt +1 -1
- package/package.json +23 -19
- package/skills/README.md +1 -1
- package/skills/configure-app/SKILL.md +2 -0
- package/skills/create-controller/SKILL.md +4 -0
- package/skills/define-resource/SKILL.md +4 -0
- package/skills/request-tracing/SKILL.md +38 -15
- package/skills/run-app/SKILL.md +71 -34
- package/skills/send-mail/SKILL.md +55 -25
- package/skills/test-http/SKILL.md +28 -9
- package/skills/test-service/SKILL.md +61 -40
- package/skills/use-localization/SKILL.md +39 -26
- package/skills/warlock-conventions/SKILL.md +26 -18
- package/skills/write-cli-command/SKILL.md +50 -45
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-locales-warning.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/legacy-locales-warning.ts"],"sourcesContent":["import { log } from \"@warlock.js/logger\";\n\nlet warned = false;\n\n/** Warn once per dev-server process when legacy locale modules are loaded. */\nexport function warnForLegacyLocales(localeFiles: readonly string[]): void {\n const legacyFiles = localeFiles.filter((file) => /\\/utils\\/locales\\.(ts|tsx)$/.test(file));\n if (warned || legacyFiles.length === 0) return;\n\n warned = true;\n const count = legacyFiles.length;\n log.warn(\n \"localization\",\n \"legacy-locales\",\n `${count} legacy utils/locales.ts ${count === 1 ? \"file is\" : \"files are\"} auto-loaded. ` +\n \"Run `warlock doctor --fix` to migrate them; auto-loaded locales.ts is removed in v6.\",\n );\n}\n\n/** Test-only reset for the process-scoped warning guard. */\nexport function resetLegacyLocalesWarningForTests(): void {\n warned = false;\n}\n"],"mappings":";;;AAEA,IAAI,SAAS;;AAGb,SAAgB,qBAAqB,aAAsC;CACzE,MAAM,cAAc,YAAY,QAAQ,SAAS,8BAA8B,KAAK,IAAI,CAAC;CACzF,IAAI,UAAU,YAAY,WAAW,GAAG;CAExC,SAAS;CACT,MAAM,QAAQ,YAAY;CAC1B,IAAI,KACF,gBACA,kBACA,GAAG,MAAM,2BAA2B,UAAU,IAAI,YAAY,YAAY,qGAE5E;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-manager.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/manifest-manager.ts"],"sourcesContent":["import { atomicWriteAsync, fileExistsAsync, getJsonFileAsync } from \"@warlock.js/fs\";\
|
|
1
|
+
{"version":3,"file":"manifest-manager.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/manifest-manager.ts"],"sourcesContent":["import { atomicWriteAsync, fileExistsAsync, getJsonFileAsync } from \"@warlock.js/fs\";\nimport { FileManager } from \"./file-manager\";\nimport type { FileManifest } from \"./types\";\nimport { MANIFEST_PATH } from \"./flags\";\n\nconst MANIFEST_VERSION = \"1.0.0\";\n\n/**\n * Manifest structure with metadata and files\n */\nexport type Manifest = {\n version: string;\n lastBuildTime: number;\n projectHash?: string;\n stats: {\n totalFiles: number;\n totalDependencies: number;\n };\n files: Record<string, FileManifest>;\n};\n\nexport class ManifestManager {\n /**\n * Manifest data with metadata\n */\n private manifest: Manifest = {\n version: MANIFEST_VERSION,\n lastBuildTime: Date.now(),\n stats: {\n totalFiles: 0,\n totalDependencies: 0,\n },\n files: {},\n };\n\n /**\n * Constructor\n */\n public constructor(private readonly files: Map<string, FileManager>) {}\n\n /**\n * Initialize manifest manager\n * @returns true if manifest exists, false otherwise\n */\n public async init(): Promise<boolean> {\n if (await fileExistsAsync(MANIFEST_PATH)) {\n try {\n const loaded = await getJsonFileAsync<Manifest>(MANIFEST_PATH);\n\n // A torn write or a format change across upgrades is treated as absent.\n if (loaded?.version !== MANIFEST_VERSION || typeof loaded.files !== \"object\") {\n return false;\n }\n\n this.manifest = loaded;\n return true;\n } catch {\n return false;\n }\n }\n\n return false;\n }\n\n /**\n * Save manifest to disk\n */\n public async save(): Promise<void> {\n // Update stats before saving\n this.manifest.stats.totalFiles = Object.keys(this.manifest.files).length;\n this.manifest.stats.totalDependencies = this.calculateTotalDependencies();\n this.manifest.lastBuildTime = Date.now();\n\n await atomicWriteAsync(MANIFEST_PATH, JSON.stringify(this.manifest, null, 2));\n }\n\n /**\n * Get file manifest data\n */\n public getFile(filePath: string): FileManifest | undefined {\n return this.manifest.files[filePath];\n }\n\n /**\n * Check if file exists in manifest\n */\n public hasFile(filePath: string): boolean {\n return filePath in this.manifest.files;\n }\n\n /**\n * Set file manifest data\n */\n public setFile(filePath: string, fileManifest: FileManifest): void {\n this.manifest.files[filePath] = fileManifest;\n }\n\n /**\n * Remove file from manifest\n */\n public removeFile(filePath: string): void {\n delete this.manifest.files[filePath];\n }\n\n /**\n * Get all file paths in manifest\n */\n public getAllFilePaths(): string[] {\n return Object.keys(this.manifest.files);\n }\n\n /**\n * Get all file manifests\n */\n public getAllFiles(): Record<string, FileManifest> {\n return this.manifest.files;\n }\n\n /**\n * Get manifest metadata\n */\n public getMetadata() {\n return {\n version: this.manifest.version,\n lastBuildTime: this.manifest.lastBuildTime,\n projectHash: this.manifest.projectHash,\n stats: this.manifest.stats,\n };\n }\n\n /**\n * Calculate total dependencies across all files\n */\n private calculateTotalDependencies(): number {\n return Object.values(this.manifest.files).reduce(\n (total, file) => total + (file.dependencies?.length || 0),\n 0,\n );\n }\n\n /**\n * Clear all files from manifest\n */\n public clear(): void {\n this.manifest.files = {};\n this.manifest.stats = {\n totalFiles: 0,\n totalDependencies: 0,\n };\n }\n}\n"],"mappings":";;;;AAKA,MAAM,mBAAmB;AAgBzB,IAAa,kBAAb,MAA6B;;;;CAiB3B,AAAO,YAAY,AAAiB,OAAiC;EAAjC;kBAbP;GAC3B,SAAS;GACT,eAAe,KAAK,IAAI;GACxB,OAAO;IACL,YAAY;IACZ,mBAAmB;GACrB;GACA,OAAO,CAAC;EACV;CAKsE;;;;;CAMtE,MAAa,OAAyB;EACpC,IAAI,MAAM,gBAAgB,aAAa,GACrC,IAAI;GACF,MAAM,SAAS,MAAM,iBAA2B,aAAa;GAG7D,IAAI,QAAQ,YAAY,oBAAoB,OAAO,OAAO,UAAU,UAClE,OAAO;GAGT,KAAK,WAAW;GAChB,OAAO;EACT,QAAQ;GACN,OAAO;EACT;EAGF,OAAO;CACT;;;;CAKA,MAAa,OAAsB;EAEjC,KAAK,SAAS,MAAM,aAAa,OAAO,KAAK,KAAK,SAAS,KAAK,CAAC,CAAC;EAClE,KAAK,SAAS,MAAM,oBAAoB,KAAK,2BAA2B;EACxE,KAAK,SAAS,gBAAgB,KAAK,IAAI;EAEvC,MAAM,iBAAiB,eAAe,KAAK,UAAU,KAAK,UAAU,MAAM,CAAC,CAAC;CAC9E;;;;CAKA,AAAO,QAAQ,UAA4C;EACzD,OAAO,KAAK,SAAS,MAAM;CAC7B;;;;CAKA,AAAO,QAAQ,UAA2B;EACxC,OAAO,YAAY,KAAK,SAAS;CACnC;;;;CAKA,AAAO,QAAQ,UAAkB,cAAkC;EACjE,KAAK,SAAS,MAAM,YAAY;CAClC;;;;CAKA,AAAO,WAAW,UAAwB;EACxC,OAAO,KAAK,SAAS,MAAM;CAC7B;;;;CAKA,AAAO,kBAA4B;EACjC,OAAO,OAAO,KAAK,KAAK,SAAS,KAAK;CACxC;;;;CAKA,AAAO,cAA4C;EACjD,OAAO,KAAK,SAAS;CACvB;;;;CAKA,AAAO,cAAc;EACnB,OAAO;GACL,SAAS,KAAK,SAAS;GACvB,eAAe,KAAK,SAAS;GAC7B,aAAa,KAAK,SAAS;GAC3B,OAAO,KAAK,SAAS;EACvB;CACF;;;;CAKA,AAAQ,6BAAqC;EAC3C,OAAO,OAAO,OAAO,KAAK,SAAS,KAAK,CAAC,CAAC,QACvC,OAAO,SAAS,SAAS,KAAK,cAAc,UAAU,IACvD,CACF;CACF;;;;CAKA,AAAO,QAAc;EACnB,KAAK,SAAS,QAAQ,CAAC;EACvB,KAAK,SAAS,QAAQ;GACpB,YAAY;GACZ,mBAAmB;EACrB;CACF;AACF"}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { router } from "../router/router.mjs";
|
|
2
|
+
import { registerGroupedTranslationKeys, registerLocaleDictionary } from "../localization/register-locale-dictionary.mjs";
|
|
3
|
+
import "../localization/index.mjs";
|
|
2
4
|
import { devLogError, formatModuleNotFoundError } from "./dev-logger.mjs";
|
|
5
|
+
import { importAppModule } from "../loader/app-module-importer.mjs";
|
|
6
|
+
import { extractTranslationKeys } from "./extract-translation-keys.mjs";
|
|
7
|
+
import { warnForLegacyLocales } from "./legacy-locales-warning.mjs";
|
|
3
8
|
import { getDevelopmentModelModuleRegistry } from "./model-module-registry.mjs";
|
|
4
9
|
import { pathToFileURL } from "node:url";
|
|
10
|
+
import ts from "typescript";
|
|
5
11
|
|
|
6
12
|
//#region ../core/src/dev-server/module-loader.ts
|
|
7
13
|
/**
|
|
@@ -20,15 +26,18 @@ var ModuleLoadError = class extends Error {
|
|
|
20
26
|
}
|
|
21
27
|
};
|
|
22
28
|
/**
|
|
23
|
-
* The
|
|
29
|
+
* The "special" file kinds that the dev server eagerly imports at boot.
|
|
24
30
|
* Order matters: locales first (used by everything), events before main so
|
|
25
|
-
* listeners are registered when main runs, routes
|
|
31
|
+
* listeners are registered when main runs, routes after main so handlers are
|
|
32
|
+
* bound, worker last so scheduled jobs and queue definitions see routes
|
|
33
|
+
* already registered. Dev always loads worker files since dev runs every role.
|
|
26
34
|
*/
|
|
27
35
|
const SPECIAL_TYPES = [
|
|
28
36
|
"locale",
|
|
29
37
|
"event",
|
|
30
38
|
"main",
|
|
31
|
-
"route"
|
|
39
|
+
"route",
|
|
40
|
+
"worker"
|
|
32
41
|
];
|
|
33
42
|
/**
|
|
34
43
|
* Loads application modules through the ESM loader hook. The hook stamps
|
|
@@ -52,9 +61,10 @@ var ModuleLoader = class {
|
|
|
52
61
|
* try/catch that logs and aborts the boot — so a broken route module aborts
|
|
53
62
|
* boot loudly rather than booting into a surface that 404s.
|
|
54
63
|
*/
|
|
55
|
-
async loadAll() {
|
|
64
|
+
async loadAll(options = {}) {
|
|
56
65
|
const failures = [];
|
|
57
66
|
for (const type of SPECIAL_TYPES) for (const file of this.specialFilesCollector.getFilesByType(type)) try {
|
|
67
|
+
await options.onBeforeLoad?.(file);
|
|
58
68
|
await this.loadModule(file, type);
|
|
59
69
|
} catch (error) {
|
|
60
70
|
failures.push(error instanceof ModuleLoadError ? error : new ModuleLoadError(type, file, error));
|
|
@@ -67,11 +77,22 @@ var ModuleLoader = class {
|
|
|
67
77
|
*/
|
|
68
78
|
async loadModule(file, type) {
|
|
69
79
|
if (file.relativePath.endsWith(".env")) return void 0;
|
|
80
|
+
if (type === "locale" && /\/utils\/locales\.(ts|tsx)$/.test(file.relativePath)) warnForLegacyLocales(this.specialFilesCollector.getFilesByType("locale").map((locale) => locale.relativePath));
|
|
81
|
+
if (type === "locale" && file.relativePath.endsWith(".json")) {
|
|
82
|
+
const cleanup = registerLocaleDictionary({
|
|
83
|
+
sourceFile: file.relativePath,
|
|
84
|
+
source: file.source,
|
|
85
|
+
defaultNamespace: file.relativePath.split("/")[2]
|
|
86
|
+
});
|
|
87
|
+
file.addCleanup(cleanup);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (type === "locale") registerGroupedTranslationKeys(file.relativePath, extractTranslationKeys(ts.createSourceFile(file.relativePath, file.source, ts.ScriptTarget.Latest)));
|
|
70
91
|
globalThis.__currentModuleFile = file;
|
|
71
92
|
try {
|
|
72
93
|
const fileUrl = pathToFileURL(file.absolutePath).href;
|
|
73
94
|
const load = async () => {
|
|
74
|
-
const module = await
|
|
95
|
+
const module = await importAppModule(fileUrl);
|
|
75
96
|
this.loadedModules.set(file.absolutePath, module);
|
|
76
97
|
this.registerCleanup(file, module);
|
|
77
98
|
if (type === "model") getDevelopmentModelModuleRegistry().publish(file.absolutePath, fileUrl, module);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-loader.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/module-loader.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { router } from \"../router/router\";\nimport { devLogError, formatModuleNotFoundError } from \"./dev-logger\";\nimport type { CleanupFunction, FileManager } from \"./file-manager\";\nimport { getDevelopmentModelModuleRegistry } from \"./model-module-registry\";\nimport type { SpecialFileType, SpecialFilesCollector } from \"./special-files-collector\";\n\ndeclare global {\n var __currentModuleFile: FileManager | undefined;\n}\n\n/**\n * Thrown when a special file (route/event/main/locale) fails to import or\n * register. Carries the file that failed and the original cause so a broken\n * module surfaces with its origin instead of vanishing into a 404.\n */\nexport class ModuleLoadError extends Error {\n public constructor(\n public readonly type: string,\n public readonly file: FileManager,\n public readonly cause: unknown,\n ) {\n const reason = cause instanceof Error ? cause.message : String(cause);\n super(`Failed to load ${type}: ${file.relativePath} - ${reason}`);\n this.name = \"ModuleLoadError\";\n }\n}\n\n/**\n * The four \"special\" file kinds that the dev server eagerly imports at boot.\n * Order matters: locales first (used by everything), events before main so\n * listeners are registered when main runs, routes last so handlers are bound.\n */\nconst SPECIAL_TYPES: readonly SpecialFileType[] = [\"locale\", \"event\", \"main\", \"route\"] as const;\n\n/**\n * Loads application modules through the ESM loader hook. The hook stamps\n * `?v=N` on every import, so each reload is a fresh module without any\n * userland cache-busting plumbing.\n */\nexport class ModuleLoader {\n private readonly loadedModules = new Map<string, unknown>();\n\n public constructor(private readonly specialFilesCollector: SpecialFilesCollector) {\n // Web creates its Vite bridge after Core's development orchestration has\n // constructed ModuleLoader. Create the carrier now so a zero-model app can\n // subscribe before a model is added later through HMR.\n getDevelopmentModelModuleRegistry();\n }\n\n /**\n * Eagerly load every special file at boot, in the canonical order so\n * later phases (e.g. routes) see state earlier phases registered.\n *\n * A failing module no longer vanishes silently: each failure is collected\n * (so one broken file doesn't hide the others) and, once every file has been\n * attempted, an aggregate error is thrown. The boot callers\n * (`DevelopmentServer.start`, the HTTP test bootstrap) already wrap this in a\n * try/catch that logs and aborts the boot — so a broken route module aborts\n * boot loudly rather than booting into a surface that 404s.\n */\n public async loadAll(): Promise<void> {\n const failures: ModuleLoadError[] = [];\n\n for (const type of SPECIAL_TYPES) {\n for (const file of this.specialFilesCollector.getFilesByType(type)) {\n try {\n await this.loadModule(file, type);\n } catch (error) {\n failures.push(\n error instanceof ModuleLoadError ? error : new ModuleLoadError(type, file, error),\n );\n }\n }\n }\n\n if (failures.length > 0) {\n throw new AggregateError(\n failures,\n `${failures.length} module(s) failed to load during boot:\\n` +\n failures.map((failure) => ` - ${failure.message}`).join(\"\\n\"),\n );\n }\n }\n\n /**\n * Import a file through the loader hook. For routes, scopes the import in\n * `router.withSourceFile()` so the added routes carry their origin.\n */\n public async loadModule<T = unknown>(file: FileManager, type: string): Promise<T | undefined> {\n if (file.relativePath.endsWith(\".env\")) return undefined;\n\n globalThis.__currentModuleFile = file;\n\n try {\n const fileUrl = pathToFileURL(file.absolutePath).href;\n\n const load = async () => {\n const module = (await import(fileUrl)) as Record<string, unknown>;\n this.loadedModules.set(file.absolutePath, module);\n this.registerCleanup(file, module);\n if (type === \"model\") {\n getDevelopmentModelModuleRegistry().publish(file.absolutePath, fileUrl, module);\n }\n return module as T;\n };\n\n return type === \"route\" ? await router.withSourceFile(file.relativePath, load) : await load();\n } catch (error: any) {\n if (error.code === \"ERR_MODULE_NOT_FOUND\") {\n devLogError(formatModuleNotFoundError(error));\n } else {\n // Pass the error through so devLogError prints the stack. With dev\n // source maps enabled, frames remap to the original `.ts` line/col\n // (e.g. the actual call site of an undefined symbol) instead of\n // vanishing — a one-line \"x is not defined\" is undebuggable.\n devLogError(\n `Failed to load ${type}: ${file.relativePath} - ${error?.message || error}`,\n error,\n );\n }\n\n // RETHROW after logging. Previously this returned undefined, so a route\n // file that threw on import or registration disappeared with no boot\n // error — the whole surface 404'd silently. Boot callers abort on the\n // throw; the HMR batch-reload handler catches it, keeps the server\n // alive, and shows it loudly.\n throw error instanceof ModuleLoadError ? error : new ModuleLoadError(type, file, error);\n } finally {\n globalThis.__currentModuleFile = undefined;\n }\n }\n\n /**\n * Reload a previously-loaded special file. The version-bump that makes the\n * import fresh is done by the caller (layer-executor) before invoking this.\n * Routes are removed from the registry first so re-registration is clean.\n */\n public async reloadModule(file: FileManager): Promise<void> {\n const moduleType = this.specialFilesCollector.getFileType(file.relativePath);\n if (!moduleType) return;\n\n this.runCleanup(file);\n\n if (moduleType === \"route\") {\n router.removeRoutesBySourceFile(file.relativePath);\n }\n\n this.loadedModules.delete(file.absolutePath);\n await this.loadModule(file, moduleType);\n }\n\n /**\n * Run every cleanup hook the file registered (or `$cleanup` on its exports)\n * and reset the list. Called once per HMR reload.\n */\n public runCleanup(file: FileManager): void {\n for (const hook of file.cleanup) {\n try {\n if (typeof hook === \"function\") {\n hook();\n } else if (\n hook &&\n typeof (hook as { unsubscribe?: () => void }).unsubscribe === \"function\"\n ) {\n (hook as { unsubscribe: () => void }).unsubscribe();\n }\n } catch {\n // Cleanup errors shouldn't break HMR.\n }\n }\n file.resetCleanup();\n }\n\n /**\n * Clean up after a file whose source was deleted from disk.\n */\n public cleanupDeletedModule(file: FileManager): void {\n this.loadedModules.delete(file.absolutePath);\n\n if (file.type === \"model\") {\n getDevelopmentModelModuleRegistry().remove(file.absolutePath);\n }\n\n if (file.type === \"route\") {\n router.removeRoutesBySourceFile(file.relativePath);\n }\n\n this.runCleanup(file);\n }\n\n /**\n * Scan a freshly-loaded module for cleanup handlers and register them on\n * the FileManager so they run before the next reload. Priority: explicit\n * `export function cleanup()` → `.$cleanup` on any exported value.\n */\n private registerCleanup(file: FileManager, module: Record<string, unknown>): void {\n if (typeof module.cleanup === \"function\") {\n file.addCleanup(module.cleanup as CleanupFunction);\n return;\n }\n\n const cleanups: CleanupFunction[] = [];\n\n for (const exportedValue of Object.values(module)) {\n const cleanup = (exportedValue as { $cleanup?: unknown })?.$cleanup;\n if (typeof cleanup === \"function\") {\n cleanups.push(cleanup.bind(exportedValue) as CleanupFunction);\n }\n }\n\n if (cleanups.length > 0) {\n file.addCleanup(cleanups);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module-loader.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/module-loader.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport ts from \"typescript\";\nimport { importAppModule } from \"../loader/app-module-importer\";\nimport { registerGroupedTranslationKeys, registerLocaleDictionary } from \"../localization\";\nimport { router } from \"../router/router\";\nimport { devLogError, formatModuleNotFoundError } from \"./dev-logger\";\nimport { extractTranslationKeys } from \"./extract-translation-keys\";\nimport type { CleanupFunction, FileManager } from \"./file-manager\";\nimport { warnForLegacyLocales } from \"./legacy-locales-warning\";\nimport { getDevelopmentModelModuleRegistry } from \"./model-module-registry\";\nimport type { SpecialFileType, SpecialFilesCollector } from \"./special-files-collector\";\n\ndeclare global {\n var __currentModuleFile: FileManager | undefined;\n}\n\n/**\n * Thrown when a special file (route/event/main/locale) fails to import or\n * register. Carries the file that failed and the original cause so a broken\n * module surfaces with its origin instead of vanishing into a 404.\n */\nexport class ModuleLoadError extends Error {\n public constructor(\n public readonly type: string,\n public readonly file: FileManager,\n public readonly cause: unknown,\n ) {\n const reason = cause instanceof Error ? cause.message : String(cause);\n super(`Failed to load ${type}: ${file.relativePath} - ${reason}`);\n this.name = \"ModuleLoadError\";\n }\n}\n\n/**\n * The \"special\" file kinds that the dev server eagerly imports at boot.\n * Order matters: locales first (used by everything), events before main so\n * listeners are registered when main runs, routes after main so handlers are\n * bound, worker last so scheduled jobs and queue definitions see routes\n * already registered. Dev always loads worker files since dev runs every role.\n */\nconst SPECIAL_TYPES: readonly SpecialFileType[] = [\n \"locale\",\n \"event\",\n \"main\",\n \"route\",\n \"worker\",\n] as const;\n\n/**\n * Loads application modules through the ESM loader hook. The hook stamps\n * `?v=N` on every import, so each reload is a fresh module without any\n * userland cache-busting plumbing.\n */\nexport class ModuleLoader {\n private readonly loadedModules = new Map<string, unknown>();\n\n public constructor(private readonly specialFilesCollector: SpecialFilesCollector) {\n // Web creates its Vite bridge after Core's development orchestration has\n // constructed ModuleLoader. Create the carrier now so a zero-model app can\n // subscribe before a model is added later through HMR.\n getDevelopmentModelModuleRegistry();\n }\n\n /**\n * Eagerly load every special file at boot, in the canonical order so\n * later phases (e.g. routes) see state earlier phases registered.\n *\n * A failing module no longer vanishes silently: each failure is collected\n * (so one broken file doesn't hide the others) and, once every file has been\n * attempted, an aggregate error is thrown. The boot callers\n * (`DevelopmentServer.start`, the HTTP test bootstrap) already wrap this in a\n * try/catch that logs and aborts the boot — so a broken route module aborts\n * boot loudly rather than booting into a surface that 404s.\n */\n public async loadAll(\n options: { onBeforeLoad?: (file: FileManager) => void | Promise<void> } = {},\n ): Promise<void> {\n const failures: ModuleLoadError[] = [];\n\n for (const type of SPECIAL_TYPES) {\n for (const file of this.specialFilesCollector.getFilesByType(type)) {\n try {\n await options.onBeforeLoad?.(file);\n await this.loadModule(file, type);\n } catch (error) {\n failures.push(\n error instanceof ModuleLoadError ? error : new ModuleLoadError(type, file, error),\n );\n }\n }\n }\n\n if (failures.length > 0) {\n throw new AggregateError(\n failures,\n `${failures.length} module(s) failed to load during boot:\\n` +\n failures.map((failure) => ` - ${failure.message}`).join(\"\\n\"),\n );\n }\n }\n\n /**\n * Import a file through the loader hook. For routes, scopes the import in\n * `router.withSourceFile()` so the added routes carry their origin.\n */\n public async loadModule<T = unknown>(file: FileManager, type: string): Promise<T | undefined> {\n if (file.relativePath.endsWith(\".env\")) return undefined;\n\n if (type === \"locale\" && /\\/utils\\/locales\\.(ts|tsx)$/.test(file.relativePath)) {\n warnForLegacyLocales(\n this.specialFilesCollector.getFilesByType(\"locale\").map((locale) => locale.relativePath),\n );\n }\n\n if (type === \"locale\" && file.relativePath.endsWith(\".json\")) {\n const cleanup = registerLocaleDictionary({\n sourceFile: file.relativePath,\n source: file.source,\n defaultNamespace: file.relativePath.split(\"/\")[2]!,\n });\n file.addCleanup(cleanup);\n return undefined;\n }\n\n if (type === \"locale\") {\n registerGroupedTranslationKeys(\n file.relativePath,\n extractTranslationKeys(\n ts.createSourceFile(file.relativePath, file.source, ts.ScriptTarget.Latest),\n ),\n );\n }\n\n globalThis.__currentModuleFile = file;\n\n try {\n const fileUrl = pathToFileURL(file.absolutePath).href;\n\n const load = async () => {\n const module = (await importAppModule(fileUrl)) as Record<string, unknown>;\n this.loadedModules.set(file.absolutePath, module);\n this.registerCleanup(file, module);\n if (type === \"model\") {\n getDevelopmentModelModuleRegistry().publish(file.absolutePath, fileUrl, module);\n }\n return module as T;\n };\n\n return type === \"route\" ? await router.withSourceFile(file.relativePath, load) : await load();\n } catch (error: any) {\n if (error.code === \"ERR_MODULE_NOT_FOUND\") {\n devLogError(formatModuleNotFoundError(error));\n } else {\n // Pass the error through so devLogError prints the stack. With dev\n // source maps enabled, frames remap to the original `.ts` line/col\n // (e.g. the actual call site of an undefined symbol) instead of\n // vanishing — a one-line \"x is not defined\" is undebuggable.\n devLogError(\n `Failed to load ${type}: ${file.relativePath} - ${error?.message || error}`,\n error,\n );\n }\n\n // RETHROW after logging. Previously this returned undefined, so a route\n // file that threw on import or registration disappeared with no boot\n // error — the whole surface 404'd silently. Boot callers abort on the\n // throw; the HMR batch-reload handler catches it, keeps the server\n // alive, and shows it loudly.\n throw error instanceof ModuleLoadError ? error : new ModuleLoadError(type, file, error);\n } finally {\n globalThis.__currentModuleFile = undefined;\n }\n }\n\n /**\n * Reload a previously-loaded special file. The version-bump that makes the\n * import fresh is done by the caller (layer-executor) before invoking this.\n * Routes are removed from the registry first so re-registration is clean.\n */\n public async reloadModule(file: FileManager): Promise<void> {\n const moduleType = this.specialFilesCollector.getFileType(file.relativePath);\n if (!moduleType) return;\n\n this.runCleanup(file);\n\n if (moduleType === \"route\") {\n router.removeRoutesBySourceFile(file.relativePath);\n }\n\n this.loadedModules.delete(file.absolutePath);\n await this.loadModule(file, moduleType);\n }\n\n /**\n * Run every cleanup hook the file registered (or `$cleanup` on its exports)\n * and reset the list. Called once per HMR reload.\n */\n public runCleanup(file: FileManager): void {\n for (const hook of file.cleanup) {\n try {\n if (typeof hook === \"function\") {\n hook();\n } else if (\n hook &&\n typeof (hook as { unsubscribe?: () => void }).unsubscribe === \"function\"\n ) {\n (hook as { unsubscribe: () => void }).unsubscribe();\n }\n } catch {\n // Cleanup errors shouldn't break HMR.\n }\n }\n file.resetCleanup();\n }\n\n /**\n * Clean up after a file whose source was deleted from disk.\n */\n public cleanupDeletedModule(file: FileManager): void {\n this.loadedModules.delete(file.absolutePath);\n\n if (file.type === \"model\") {\n getDevelopmentModelModuleRegistry().remove(file.absolutePath);\n }\n\n if (file.type === \"route\") {\n router.removeRoutesBySourceFile(file.relativePath);\n }\n\n this.runCleanup(file);\n }\n\n /**\n * Scan a freshly-loaded module for cleanup handlers and register them on\n * the FileManager so they run before the next reload. Priority: explicit\n * `export function cleanup()` → `.$cleanup` on any exported value.\n */\n private registerCleanup(file: FileManager, module: Record<string, unknown>): void {\n if (typeof module.cleanup === \"function\") {\n file.addCleanup(module.cleanup as CleanupFunction);\n return;\n }\n\n const cleanups: CleanupFunction[] = [];\n\n for (const exportedValue of Object.values(module)) {\n const cleanup = (exportedValue as { $cleanup?: unknown })?.$cleanup;\n if (typeof cleanup === \"function\") {\n cleanups.push(cleanup.bind(exportedValue) as CleanupFunction);\n }\n }\n\n if (cleanups.length > 0) {\n file.addCleanup(cleanups);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { connectorsManager } from "../connectors/connectors-manager.mjs";
|
|
2
|
+
import { devLogWarn } from "./dev-logger.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../core/src/dev-server/register-installed-devtools.ts
|
|
5
|
+
const DEVTOOLS_PACKAGE = "@warlock.js/devtools";
|
|
6
|
+
/**
|
|
7
|
+
* Register `@warlock.js/devtools` when the app has it installed.
|
|
8
|
+
*
|
|
9
|
+
* Called by `warlock dev` only, before the late connector phase, so the app
|
|
10
|
+
* never names devtools in `warlock.config.ts`. That matters because devtools
|
|
11
|
+
* is a DEV dependency: a production install omits it, and a config import of
|
|
12
|
+
* it would fail to resolve there. The production entry never calls this.
|
|
13
|
+
*
|
|
14
|
+
* Skipped when a connector named `devtools` is already registered (an app
|
|
15
|
+
* that wires it by hand keeps control). A missing package is the normal case
|
|
16
|
+
* and stays silent; any other load failure is reported and ignored, because
|
|
17
|
+
* a dev tool must never stop the app from booting.
|
|
18
|
+
*/
|
|
19
|
+
async function registerInstalledDevtools(load = () => import(DEVTOOLS_PACKAGE)) {
|
|
20
|
+
if (connectorsManager.has("devtools")) return false;
|
|
21
|
+
let devtools;
|
|
22
|
+
try {
|
|
23
|
+
devtools = await load();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (!isMissingPackage(error)) devLogWarn(`${DEVTOOLS_PACKAGE} is installed but failed to load: ${describe(error)}`);
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (typeof devtools.devtoolsConnector !== "function") {
|
|
29
|
+
devLogWarn(`${DEVTOOLS_PACKAGE} does not export devtoolsConnector(); it was not started`);
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
connectorsManager.register(devtools.devtoolsConnector());
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/** True when the error says the devtools package itself is not installed. */
|
|
36
|
+
function isMissingPackage(error) {
|
|
37
|
+
const code = error?.code;
|
|
38
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") return false;
|
|
39
|
+
return describe(error).includes(`'${DEVTOOLS_PACKAGE}'`) || describe(error).includes(`"${DEVTOOLS_PACKAGE}"`);
|
|
40
|
+
}
|
|
41
|
+
function describe(error) {
|
|
42
|
+
return error instanceof Error ? error.message : String(error);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { registerInstalledDevtools };
|
|
47
|
+
//# sourceMappingURL=register-installed-devtools.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-installed-devtools.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/register-installed-devtools.ts"],"sourcesContent":["import { connectorsManager } from \"../connectors/connectors-manager\";\nimport type { Connector } from \"../connectors/types\";\nimport { devLogWarn } from \"./dev-logger\";\n\nconst DEVTOOLS_PACKAGE = \"@warlock.js/devtools\";\n\ntype DevtoolsModule = {\n devtoolsConnector?: () => Connector;\n};\n\n/**\n * Register `@warlock.js/devtools` when the app has it installed.\n *\n * Called by `warlock dev` only, before the late connector phase, so the app\n * never names devtools in `warlock.config.ts`. That matters because devtools\n * is a DEV dependency: a production install omits it, and a config import of\n * it would fail to resolve there. The production entry never calls this.\n *\n * Skipped when a connector named `devtools` is already registered (an app\n * that wires it by hand keeps control). A missing package is the normal case\n * and stays silent; any other load failure is reported and ignored, because\n * a dev tool must never stop the app from booting.\n */\nexport async function registerInstalledDevtools(\n load: () => Promise<DevtoolsModule> = () => import(DEVTOOLS_PACKAGE),\n): Promise<boolean> {\n if (connectorsManager.has(\"devtools\")) {\n return false;\n }\n\n let devtools: DevtoolsModule;\n\n try {\n devtools = await load();\n } catch (error) {\n if (!isMissingPackage(error)) {\n devLogWarn(`${DEVTOOLS_PACKAGE} is installed but failed to load: ${describe(error)}`);\n }\n\n return false;\n }\n\n if (typeof devtools.devtoolsConnector !== \"function\") {\n devLogWarn(`${DEVTOOLS_PACKAGE} does not export devtoolsConnector(); it was not started`);\n\n return false;\n }\n\n connectorsManager.register(devtools.devtoolsConnector());\n\n return true;\n}\n\n/** True when the error says the devtools package itself is not installed. */\nfunction isMissingPackage(error: unknown): boolean {\n const code = (error as { code?: unknown } | undefined)?.code;\n\n if (code !== \"ERR_MODULE_NOT_FOUND\" && code !== \"MODULE_NOT_FOUND\") {\n return false;\n }\n\n // A missing module INSIDE an installed devtools is a broken install, not an\n // absent package — only the package's own name counts as \"not installed\".\n return (\n describe(error).includes(`'${DEVTOOLS_PACKAGE}'`) ||\n describe(error).includes(`\"${DEVTOOLS_PACKAGE}\"`)\n );\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":";;;;AAIA,MAAM,mBAAmB;;;;;;;;;;;;;;AAmBzB,eAAsB,0BACpB,aAA4C,OAAO,mBACjC;CAClB,IAAI,kBAAkB,IAAI,UAAU,GAClC,OAAO;CAGT,IAAI;CAEJ,IAAI;EACF,WAAW,MAAM,KAAK;CACxB,SAAS,OAAO;EACd,IAAI,CAAC,iBAAiB,KAAK,GACzB,WAAW,GAAG,iBAAiB,oCAAoC,SAAS,KAAK,GAAG;EAGtF,OAAO;CACT;CAEA,IAAI,OAAO,SAAS,sBAAsB,YAAY;EACpD,WAAW,GAAG,iBAAiB,yDAAyD;EAExF,OAAO;CACT;CAEA,kBAAkB,SAAS,SAAS,kBAAkB,CAAC;CAEvD,OAAO;AACT;;AAGA,SAAS,iBAAiB,OAAyB;CACjD,MAAM,OAAQ,OAA0C;CAExD,IAAI,SAAS,0BAA0B,SAAS,oBAC9C,OAAO;CAKT,OACE,SAAS,KAAK,CAAC,CAAC,SAAS,IAAI,iBAAiB,EAAE,KAChD,SAAS,KAAK,CAAC,CAAC,SAAS,IAAI,iBAAiB,EAAE;AAEpD;AAEA,SAAS,SAAS,OAAwB;CACxC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { warlockPath } from "../utils/paths.mjs";
|
|
2
|
+
import "../utils/index.mjs";
|
|
3
|
+
import { runTypingsContributions } from "../production/build-contributions.mjs";
|
|
4
|
+
|
|
5
|
+
//#region ../core/src/dev-server/run-connector-typings.ts
|
|
6
|
+
/**
|
|
7
|
+
* Let connectors write their own typings during `warlock generate.typings`.
|
|
8
|
+
*
|
|
9
|
+
* Core cannot import web, so this drains the `typings` hook of each connector's
|
|
10
|
+
* `build` contribution — the seam `warlock build` reads. The named API snapshot
|
|
11
|
+
* (a child process) is collected only when a hook exists AND the web connector
|
|
12
|
+
* is configured, exactly as the builder does; an API-only app pays nothing and
|
|
13
|
+
* cannot fail here.
|
|
14
|
+
*/
|
|
15
|
+
async function runConnectorTypings({ connectors, appRoot, options, collectRoutes }) {
|
|
16
|
+
if (!connectors.some((connector) => Boolean(connector.build?.typings))) return;
|
|
17
|
+
const namedApiRoutes = connectors.some((connector) => connector.name === "web") ? await collectRoutes() : void 0;
|
|
18
|
+
await runTypingsContributions(connectors, {
|
|
19
|
+
productionDir: warlockPath("production"),
|
|
20
|
+
appRoot,
|
|
21
|
+
options: options(),
|
|
22
|
+
namedApiRoutes
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { runConnectorTypings };
|
|
28
|
+
//# sourceMappingURL=run-connector-typings.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-connector-typings.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/run-connector-typings.ts"],"sourcesContent":["import type { Connector } from \"../connectors/types\";\nimport { runTypingsContributions } from \"../production/build-contributions\";\nimport type { NamedApiRoute } from \"../router/types\";\nimport { warlockPath } from \"../utils\";\nimport type { ResolvedBuildConfig } from \"../production/resolve-build-config\";\n\nexport type ConnectorTypingsInput = {\n connectors: readonly Connector[];\n appRoot: string;\n /** Resolved lazily: an app with no typings hook never needs a loaded build config. */\n options(): ResolvedBuildConfig;\n /** Fresh registration-only named API route snapshot (a child process in production). */\n collectRoutes(): Promise<readonly NamedApiRoute[]>;\n};\n\n/**\n * Let connectors write their own typings during `warlock generate.typings`.\n *\n * Core cannot import web, so this drains the `typings` hook of each connector's\n * `build` contribution — the seam `warlock build` reads. The named API snapshot\n * (a child process) is collected only when a hook exists AND the web connector\n * is configured, exactly as the builder does; an API-only app pays nothing and\n * cannot fail here.\n */\nexport async function runConnectorTypings({\n connectors,\n appRoot,\n options,\n collectRoutes,\n}: ConnectorTypingsInput): Promise<void> {\n if (!connectors.some((connector) => Boolean(connector.build?.typings))) return;\n\n const namedApiRoutes = connectors.some((connector) => connector.name === \"web\")\n ? await collectRoutes()\n : undefined;\n\n await runTypingsContributions(connectors, {\n productionDir: warlockPath(\"production\"),\n appRoot,\n options: options(),\n namedApiRoutes,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,eAAsB,oBAAoB,EACxC,YACA,SACA,SACA,iBACuC;CACvC,IAAI,CAAC,WAAW,MAAM,cAAc,QAAQ,UAAU,OAAO,OAAO,CAAC,GAAG;CAExE,MAAM,iBAAiB,WAAW,MAAM,cAAc,UAAU,SAAS,KAAK,IAC1E,MAAM,cAAc,IACpB;CAEJ,MAAM,wBAAwB,YAAY;EACxC,eAAe,YAAY,YAAY;EACvC;EACA,SAAS,QAAQ;EACjB;CACF,CAAC;AACH"}
|
|
@@ -6,13 +6,15 @@ const isConfigFile = (path) => /^src\/config\/.*\.(ts|tsx)$/.test(normalize(path
|
|
|
6
6
|
const isMainFile = (path) => /^src\/app\/([^/]+\/)?main\.(ts|tsx)$/.test(normalize(path));
|
|
7
7
|
/** `src/app/<module>/routes.ts` — one level deep */
|
|
8
8
|
const isRouteFile = (path) => /^src\/app\/[^/]+\/routes\.(ts|tsx)$/.test(normalize(path));
|
|
9
|
+
/** `src/app/worker.ts` or `src/app/<module>/worker.ts` — mirrors `isMainFile`'s optional module dir */
|
|
10
|
+
const isWorkerFile = (path) => /^src\/app\/([^/]+\/)?worker\.(ts|tsx)$/.test(normalize(path));
|
|
9
11
|
/** `src/app/<module>/events/<file>.ts` */
|
|
10
12
|
const isEventFile = (path) => /^src\/app\/[^/]+\/events\/[^/]+\.(ts|tsx)$/.test(normalize(path));
|
|
11
|
-
/** `src/app/<module>/utils/locales.ts` */
|
|
12
|
-
const isLocaleFile = (path) => /^src\/app\/[^/]+\/utils\/locales\.(ts|tsx)$/.test(normalize(path));
|
|
13
|
+
/** `src/app/<module>/utils/locales.ts` or `locales.json` */
|
|
14
|
+
const isLocaleFile = (path) => /^src\/app\/[^/]+\/utils\/locales\.(ts|tsx|json)$/.test(normalize(path));
|
|
13
15
|
/** Source files the dev server can hot-reload; anything else is data (`.sql`, `.json`, …) */
|
|
14
16
|
const isCodeFile = (path) => /\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/.test(normalize(path));
|
|
15
17
|
|
|
16
18
|
//#endregion
|
|
17
|
-
export { isCodeFile, isConfigFile, isEventFile, isLocaleFile, isMainFile, isRouteFile };
|
|
19
|
+
export { isCodeFile, isConfigFile, isEventFile, isLocaleFile, isMainFile, isRouteFile, isWorkerFile };
|
|
18
20
|
//# sourceMappingURL=special-file-patterns.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"special-file-patterns.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/special-file-patterns.ts"],"sourcesContent":["const normalize = (path: string) => path.replace(/\\\\/g, \"/\");\n\n/** `src/config/**` — any depth, the config key is the raw path */\nexport const isConfigFile = (path: string) => /^src\\/config\\/.*\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/main.ts` or `src/app/<module>/main.ts` */\nexport const isMainFile = (path: string) =>\n /^src\\/app\\/([^/]+\\/)?main\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/routes.ts` — one level deep */\nexport const isRouteFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/routes\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/events/<file>.ts` */\nexport const isEventFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/events\\/[^/]+\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/utils/locales.ts` */\nexport const isLocaleFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/utils\\/locales\\.(ts|tsx)$/.test(normalize(path));\n\n/** Source files the dev server can hot-reload; anything else is data (`.sql`, `.json`, …) */\nexport const isCodeFile = (path: string) =>\n /\\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/.test(normalize(path));\n"],"mappings":";AAAA,MAAM,aAAa,SAAiB,KAAK,QAAQ,OAAO,GAAG;;AAG3D,MAAa,gBAAgB,SAAiB,8BAA8B,KAAK,UAAU,IAAI,CAAC;;AAGhG,MAAa,cAAc,SACzB,uCAAuC,KAAK,UAAU,IAAI,CAAC;;AAG7D,MAAa,eAAe,SAC1B,sCAAsC,KAAK,UAAU,IAAI,CAAC;;AAG5D,MAAa,eAAe,SAC1B,6CAA6C,KAAK,UAAU,IAAI,CAAC;;AAGnE,MAAa,gBAAgB,SAC3B,
|
|
1
|
+
{"version":3,"file":"special-file-patterns.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/special-file-patterns.ts"],"sourcesContent":["const normalize = (path: string) => path.replace(/\\\\/g, \"/\");\n\n/** `src/config/**` — any depth, the config key is the raw path */\nexport const isConfigFile = (path: string) => /^src\\/config\\/.*\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/main.ts` or `src/app/<module>/main.ts` */\nexport const isMainFile = (path: string) =>\n /^src\\/app\\/([^/]+\\/)?main\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/routes.ts` — one level deep */\nexport const isRouteFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/routes\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/worker.ts` or `src/app/<module>/worker.ts` — mirrors `isMainFile`'s optional module dir */\nexport const isWorkerFile = (path: string) =>\n /^src\\/app\\/([^/]+\\/)?worker\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/events/<file>.ts` */\nexport const isEventFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/events\\/[^/]+\\.(ts|tsx)$/.test(normalize(path));\n\n/** `src/app/<module>/utils/locales.ts` or `locales.json` */\nexport const isLocaleFile = (path: string) =>\n /^src\\/app\\/[^/]+\\/utils\\/locales\\.(ts|tsx|json)$/.test(normalize(path));\n\n/** Source files the dev server can hot-reload; anything else is data (`.sql`, `.json`, …) */\nexport const isCodeFile = (path: string) =>\n /\\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/.test(normalize(path));\n"],"mappings":";AAAA,MAAM,aAAa,SAAiB,KAAK,QAAQ,OAAO,GAAG;;AAG3D,MAAa,gBAAgB,SAAiB,8BAA8B,KAAK,UAAU,IAAI,CAAC;;AAGhG,MAAa,cAAc,SACzB,uCAAuC,KAAK,UAAU,IAAI,CAAC;;AAG7D,MAAa,eAAe,SAC1B,sCAAsC,KAAK,UAAU,IAAI,CAAC;;AAG5D,MAAa,gBAAgB,SAC3B,yCAAyC,KAAK,UAAU,IAAI,CAAC;;AAG/D,MAAa,eAAe,SAC1B,6CAA6C,KAAK,UAAU,IAAI,CAAC;;AAGnE,MAAa,gBAAgB,SAC3B,mDAAmD,KAAK,UAAU,IAAI,CAAC;;AAGzE,MAAa,cAAc,SACzB,qCAAqC,KAAK,UAAU,IAAI,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { FileManager } from "./file-manager.mjs";
|
|
2
2
|
|
|
3
3
|
//#region ../core/src/dev-server/special-files-collector.d.ts
|
|
4
|
-
type SpecialFileType = "config" | "main" | "route" | "event" | "locale";
|
|
4
|
+
type SpecialFileType = "config" | "main" | "route" | "event" | "locale" | "worker";
|
|
5
5
|
/**
|
|
6
6
|
* Categorises files into the kinds the dev server treats specially
|
|
7
|
-
* (config / main / route / event / locale) and exposes typed accessors.
|
|
7
|
+
* (config / main / route / event / locale / worker) and exposes typed accessors.
|
|
8
8
|
*/
|
|
9
9
|
declare class SpecialFilesCollector {
|
|
10
10
|
private readonly buckets;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"special-files-collector.d.mts","names":[],"sources":["../../../../../../../core/src/dev-server/special-files-collector.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"special-files-collector.d.mts","names":[],"sources":["../../../../../../../core/src/dev-server/special-files-collector.ts"],"mappings":";;;KAUY,eAAA;;AAAZ;;;cAMa,qBAAA;EAAA,iBACM,OAAA;EASV,OAAA,CAAQ,KAAA,EAAO,GAAA,SAAY,WAAA;EAO3B,OAAA,CAAQ,WAAA,EAAa,WAAA;EAIrB,UAAA,CAAW,YAAA;EAIX,UAAA,CAAW,WAAA,EAAa,WAAA;EAKxB,WAAA,CAAY,YAAA,WAAuB,eAAA;EAUnC,cAAA,CAAe,IAAA,EAAM,eAAA,GAAkB,WAAA;EAUvC,QAAA,IAAY,MAAA,CAAO,eAAA;EAWnB,KAAA;EAAA,QAIC,UAAA;AAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { isConfigFile, isEventFile, isLocaleFile, isMainFile, isRouteFile } from "./special-file-patterns.mjs";
|
|
1
|
+
import { isConfigFile, isEventFile, isLocaleFile, isMainFile, isRouteFile, isWorkerFile } from "./special-file-patterns.mjs";
|
|
2
2
|
|
|
3
3
|
//#region ../core/src/dev-server/special-files-collector.ts
|
|
4
4
|
/**
|
|
5
5
|
* Categorises files into the kinds the dev server treats specially
|
|
6
|
-
* (config / main / route / event / locale) and exposes typed accessors.
|
|
6
|
+
* (config / main / route / event / locale / worker) and exposes typed accessors.
|
|
7
7
|
*/
|
|
8
8
|
var SpecialFilesCollector = class {
|
|
9
9
|
constructor() {
|
|
@@ -12,7 +12,8 @@ var SpecialFilesCollector = class {
|
|
|
12
12
|
main: /* @__PURE__ */ new Map(),
|
|
13
13
|
route: /* @__PURE__ */ new Map(),
|
|
14
14
|
event: /* @__PURE__ */ new Map(),
|
|
15
|
-
locale: /* @__PURE__ */ new Map()
|
|
15
|
+
locale: /* @__PURE__ */ new Map(),
|
|
16
|
+
worker: /* @__PURE__ */ new Map()
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
collect(files) {
|
|
@@ -44,7 +45,8 @@ var SpecialFilesCollector = class {
|
|
|
44
45
|
main: this.buckets.main.size,
|
|
45
46
|
route: this.buckets.route.size,
|
|
46
47
|
event: this.buckets.event.size,
|
|
47
|
-
locale: this.buckets.locale.size
|
|
48
|
+
locale: this.buckets.locale.size,
|
|
49
|
+
worker: this.buckets.worker.size
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
clear() {
|
|
@@ -56,6 +58,7 @@ var SpecialFilesCollector = class {
|
|
|
56
58
|
else if (isRouteFile(relativePath)) this.buckets.route.set(relativePath, fileManager);
|
|
57
59
|
else if (isEventFile(relativePath)) this.buckets.event.set(relativePath, fileManager);
|
|
58
60
|
else if (isLocaleFile(relativePath)) this.buckets.locale.set(relativePath, fileManager);
|
|
61
|
+
else if (isWorkerFile(relativePath)) this.buckets.worker.set(relativePath, fileManager);
|
|
59
62
|
}
|
|
60
63
|
};
|
|
61
64
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"special-files-collector.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/special-files-collector.ts"],"sourcesContent":["import { FileManager } from \"./file-manager\";\
|
|
1
|
+
{"version":3,"file":"special-files-collector.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/special-files-collector.ts"],"sourcesContent":["import { FileManager } from \"./file-manager\";\nimport {\n isConfigFile,\n isEventFile,\n isLocaleFile,\n isMainFile,\n isRouteFile,\n isWorkerFile,\n} from \"./special-file-patterns\";\n\nexport type SpecialFileType = \"config\" | \"main\" | \"route\" | \"event\" | \"locale\" | \"worker\";\n\n/**\n * Categorises files into the kinds the dev server treats specially\n * (config / main / route / event / locale / worker) and exposes typed accessors.\n */\nexport class SpecialFilesCollector {\n private readonly buckets: Record<SpecialFileType, Map<string, FileManager>> = {\n config: new Map(),\n main: new Map(),\n route: new Map(),\n event: new Map(),\n locale: new Map(),\n worker: new Map(),\n };\n\n public collect(files: Map<string, FileManager>): void {\n for (const bucket of Object.values(this.buckets)) bucket.clear();\n for (const [relativePath, fileManager] of files) {\n this.categorise(relativePath, fileManager);\n }\n }\n\n public addFile(fileManager: FileManager): void {\n this.categorise(fileManager.relativePath, fileManager);\n }\n\n public removeFile(relativePath: string): void {\n for (const bucket of Object.values(this.buckets)) bucket.delete(relativePath);\n }\n\n public updateFile(fileManager: FileManager): void {\n this.removeFile(fileManager.relativePath);\n this.categorise(fileManager.relativePath, fileManager);\n }\n\n public getFileType(relativePath: string): SpecialFileType | null {\n for (const [type, bucket] of Object.entries(this.buckets) as [\n SpecialFileType,\n Map<string, FileManager>,\n ][]) {\n if (bucket.has(relativePath)) return type;\n }\n return null;\n }\n\n public getFilesByType(type: SpecialFileType): FileManager[] {\n const files = Array.from(this.buckets[type].values());\n // Routes are loaded sequentially in alphabetical order so registration\n // is deterministic across runs.\n if (type === \"route\") {\n files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n }\n return files;\n }\n\n public getStats(): Record<SpecialFileType, number> {\n return {\n config: this.buckets.config.size,\n main: this.buckets.main.size,\n route: this.buckets.route.size,\n event: this.buckets.event.size,\n locale: this.buckets.locale.size,\n worker: this.buckets.worker.size,\n };\n }\n\n public clear(): void {\n for (const bucket of Object.values(this.buckets)) bucket.clear();\n }\n\n private categorise(relativePath: string, fileManager: FileManager): void {\n if (isConfigFile(relativePath)) {\n this.buckets.config.set(relativePath, fileManager);\n } else if (isMainFile(relativePath)) {\n this.buckets.main.set(relativePath, fileManager);\n } else if (isRouteFile(relativePath)) {\n this.buckets.route.set(relativePath, fileManager);\n } else if (isEventFile(relativePath)) {\n this.buckets.event.set(relativePath, fileManager);\n } else if (isLocaleFile(relativePath)) {\n this.buckets.locale.set(relativePath, fileManager);\n } else if (isWorkerFile(relativePath)) {\n this.buckets.worker.set(relativePath, fileManager);\n }\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAa,wBAAb,MAAmC;;iBAC6C;GAC5E,wBAAQ,IAAI,IAAI;GAChB,sBAAM,IAAI,IAAI;GACd,uBAAO,IAAI,IAAI;GACf,uBAAO,IAAI,IAAI;GACf,wBAAQ,IAAI,IAAI;GAChB,wBAAQ,IAAI,IAAI;EAClB;;CAEA,AAAO,QAAQ,OAAuC;EACpD,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,OAAO,GAAG,OAAO,MAAM;EAC/D,KAAK,MAAM,CAAC,cAAc,gBAAgB,OACxC,KAAK,WAAW,cAAc,WAAW;CAE7C;CAEA,AAAO,QAAQ,aAAgC;EAC7C,KAAK,WAAW,YAAY,cAAc,WAAW;CACvD;CAEA,AAAO,WAAW,cAA4B;EAC5C,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,OAAO,GAAG,OAAO,OAAO,YAAY;CAC9E;CAEA,AAAO,WAAW,aAAgC;EAChD,KAAK,WAAW,YAAY,YAAY;EACxC,KAAK,WAAW,YAAY,cAAc,WAAW;CACvD;CAEA,AAAO,YAAY,cAA8C;EAC/D,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,KAAK,OAAO,GAItD,IAAI,OAAO,IAAI,YAAY,GAAG,OAAO;EAEvC,OAAO;CACT;CAEA,AAAO,eAAe,MAAsC;EAC1D,MAAM,QAAQ,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC,OAAO,CAAC;EAGpD,IAAI,SAAS,SACX,MAAM,MAAM,GAAG,MAAM,EAAE,aAAa,cAAc,EAAE,YAAY,CAAC;EAEnE,OAAO;CACT;CAEA,AAAO,WAA4C;EACjD,OAAO;GACL,QAAQ,KAAK,QAAQ,OAAO;GAC5B,MAAM,KAAK,QAAQ,KAAK;GACxB,OAAO,KAAK,QAAQ,MAAM;GAC1B,OAAO,KAAK,QAAQ,MAAM;GAC1B,QAAQ,KAAK,QAAQ,OAAO;GAC5B,QAAQ,KAAK,QAAQ,OAAO;EAC9B;CACF;CAEA,AAAO,QAAc;EACnB,KAAK,MAAM,UAAU,OAAO,OAAO,KAAK,OAAO,GAAG,OAAO,MAAM;CACjE;CAEA,AAAQ,WAAW,cAAsB,aAAgC;EACvE,IAAI,aAAa,YAAY,GAC3B,KAAK,QAAQ,OAAO,IAAI,cAAc,WAAW;OAC5C,IAAI,WAAW,YAAY,GAChC,KAAK,QAAQ,KAAK,IAAI,cAAc,WAAW;OAC1C,IAAI,YAAY,YAAY,GACjC,KAAK,QAAQ,MAAM,IAAI,cAAc,WAAW;OAC3C,IAAI,YAAY,YAAY,GACjC,KAAK,QAAQ,MAAM,IAAI,cAAc,WAAW;OAC3C,IAAI,aAAa,YAAY,GAClC,KAAK,QAAQ,OAAO,IAAI,cAAc,WAAW;OAC5C,IAAI,aAAa,YAAY,GAClC,KAAK,QAAQ,OAAO,IAAI,cAAc,WAAW;CAErD;AACF"}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
//#region ../core/src/dev-server/translation-keys-sources.ts
|
|
2
2
|
const GROUPED_TRANSLATIONS_MARKER = "groupedTranslations";
|
|
3
|
+
/** `src/app/<module>/utils/locales.json`, the data-only module dictionary. */
|
|
4
|
+
function isModuleLocaleDictionaryPath(path) {
|
|
5
|
+
return /^src\/app\/[^/]+\/utils\/locales\.json$/.test(path.replace(/\\\\/g, "/"));
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
8
|
* Cheap pre-filter for candidate translation-registering source files.
|
|
5
9
|
*
|
|
@@ -10,10 +14,10 @@ const GROUPED_TRANSLATIONS_MARKER = "groupedTranslations";
|
|
|
10
14
|
* every file — this text check keeps that cheap by skipping the AST parse
|
|
11
15
|
* for the files that plainly do not call it, without executing app code.
|
|
12
16
|
*/
|
|
13
|
-
function isTranslationRegisteringSource(source) {
|
|
14
|
-
return source.includes(GROUPED_TRANSLATIONS_MARKER);
|
|
17
|
+
function isTranslationRegisteringSource(path, source) {
|
|
18
|
+
return isModuleLocaleDictionaryPath(path) || source.includes(GROUPED_TRANSLATIONS_MARKER);
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
//#endregion
|
|
18
|
-
export { isTranslationRegisteringSource };
|
|
22
|
+
export { isModuleLocaleDictionaryPath, isTranslationRegisteringSource };
|
|
19
23
|
//# sourceMappingURL=translation-keys-sources.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-keys-sources.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/translation-keys-sources.ts"],"sourcesContent":["const GROUPED_TRANSLATIONS_MARKER = \"groupedTranslations\";\n\n/**\n * Cheap pre-filter for candidate translation-registering source files.\n *\n * `groupedTranslations` calls used to be scanned for on dedicated\n * `src/**/utils/locales.*` files only, so a web module registering keys\n * elsewhere (e.g. `src/web/layout.register.ts`) was silently invisible to the\n * generator. Any app source file can call it, so discovery has to consider\n * every file — this text check keeps that cheap by skipping the AST parse\n * for the files that plainly do not call it, without executing app code.\n */\nexport function isTranslationRegisteringSource(source: string): boolean {\n return source.includes(GROUPED_TRANSLATIONS_MARKER);\n}\n"],"mappings":";AAAA,MAAM,8BAA8B;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"translation-keys-sources.mjs","names":[],"sources":["../../../../../../../core/src/dev-server/translation-keys-sources.ts"],"sourcesContent":["const GROUPED_TRANSLATIONS_MARKER = \"groupedTranslations\";\n\n/** `src/app/<module>/utils/locales.json`, the data-only module dictionary. */\nexport function isModuleLocaleDictionaryPath(path: string): boolean {\n return /^src\\/app\\/[^/]+\\/utils\\/locales\\.json$/.test(path.replace(/\\\\\\\\/g, \"/\"));\n}\n\n/**\n * Cheap pre-filter for candidate translation-registering source files.\n *\n * `groupedTranslations` calls used to be scanned for on dedicated\n * `src/**/utils/locales.*` files only, so a web module registering keys\n * elsewhere (e.g. `src/web/layout.register.ts`) was silently invisible to the\n * generator. Any app source file can call it, so discovery has to consider\n * every file — this text check keeps that cheap by skipping the AST parse\n * for the files that plainly do not call it, without executing app code.\n */\nexport function isTranslationRegisteringSource(path: string, source: string): boolean {\n return isModuleLocaleDictionaryPath(path) || source.includes(GROUPED_TRANSLATIONS_MARKER);\n}\n"],"mappings":";AAAA,MAAM,8BAA8B;;AAGpC,SAAgB,6BAA6B,MAAuB;CAClE,OAAO,0CAA0C,KAAK,KAAK,QAAQ,SAAS,GAAG,CAAC;AAClF;;;;;;;;;;;AAYA,SAAgB,+BAA+B,MAAc,QAAyB;CACpF,OAAO,6BAA6B,IAAI,KAAK,OAAO,SAAS,2BAA2B;AAC1F"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { Path } from "../utils/normalized-path.mjs";
|
|
2
2
|
import { warlockPath } from "../utils/paths.mjs";
|
|
3
3
|
import "../utils/index.mjs";
|
|
4
|
+
import { parseLocaleDictionary } from "../localization/parse-locale-dictionary.mjs";
|
|
5
|
+
import "../localization/index.mjs";
|
|
4
6
|
import { devLogError, devLogInfo, devLogSuccess, devServeLog } from "./dev-logger.mjs";
|
|
7
|
+
import { getFilesFromDirectory } from "./utils.mjs";
|
|
8
|
+
import { extractTranslationKeys } from "./extract-translation-keys.mjs";
|
|
5
9
|
import { filesOrchestrator } from "./files-orchestrator.mjs";
|
|
6
10
|
import { readConfigAst } from "./read-config-ast.mjs";
|
|
7
11
|
import { runTypingsGeneration } from "./run-typings-generation.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { isTranslationRegisteringSource } from "./translation-keys-sources.mjs";
|
|
12
|
+
import { isModuleLocaleDictionaryPath, isTranslationRegisteringSource } from "./translation-keys-sources.mjs";
|
|
10
13
|
import { join, resolve } from "path";
|
|
11
14
|
import { ensureDirectoryAsync } from "@warlock.js/fs";
|
|
12
15
|
import { constants } from "fs";
|
|
@@ -233,11 +236,30 @@ ${driverKeys.map((k) => ` ${this.toInterfaceKey(k)}: true;`).join("\n")}
|
|
|
233
236
|
const keys = /* @__PURE__ */ new Set();
|
|
234
237
|
const sourceFiles = /* @__PURE__ */ new Set();
|
|
235
238
|
for (const [path, fileManager] of filesOrchestrator.getFiles()) {
|
|
236
|
-
if (!isTranslationRegisteringSource(fileManager.source)) continue;
|
|
239
|
+
if (!isTranslationRegisteringSource(path, fileManager.source)) continue;
|
|
237
240
|
sourceFiles.add(path);
|
|
241
|
+
if (isModuleLocaleDictionaryPath(path)) {
|
|
242
|
+
const dictionary = parseLocaleDictionary({
|
|
243
|
+
sourceFile: path,
|
|
244
|
+
source: fileManager.source,
|
|
245
|
+
defaultNamespace: path.split("/")[2]
|
|
246
|
+
});
|
|
247
|
+
for (const key of Object.keys(dictionary.entries)) keys.add(key);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
238
250
|
const sourceFile = await readConfigAst(fileManager.absolutePath);
|
|
239
251
|
if (sourceFile) for (const key of extractTranslationKeys(sourceFile)) keys.add(key);
|
|
240
252
|
}
|
|
253
|
+
for (const absolutePath of await getFilesFromDirectory(join(process.cwd(), "src", "app"), "**/utils/locales.json")) {
|
|
254
|
+
const path = Path.toRelative(absolutePath);
|
|
255
|
+
sourceFiles.add(path);
|
|
256
|
+
const dictionary = parseLocaleDictionary({
|
|
257
|
+
sourceFile: path,
|
|
258
|
+
source: await readFile(absolutePath, "utf-8"),
|
|
259
|
+
defaultNamespace: path.split("/")[2]
|
|
260
|
+
});
|
|
261
|
+
for (const key of Object.keys(dictionary.entries)) keys.add(key);
|
|
262
|
+
}
|
|
241
263
|
for (const key of await listRouteLocaleKeysForTypeGeneration()) keys.add(key);
|
|
242
264
|
this.translationSourceFiles = sourceFiles;
|
|
243
265
|
const content = `// Auto-generated by Warlock.js - DO NOT EDIT
|
|
@@ -517,9 +539,10 @@ ${allKeys.map((key) => ` "${key}": true;`).join("\n")}
|
|
|
517
539
|
const normalizedPath = Path.normalize(file);
|
|
518
540
|
if (normalizedPath.includes("src/config/")) return true;
|
|
519
541
|
if (isRouteLocalesJsonPath(normalizedPath)) return true;
|
|
542
|
+
if (isModuleLocaleDictionaryPath(normalizedPath)) return true;
|
|
520
543
|
if (this.translationSourceFiles.has(normalizedPath)) return true;
|
|
521
544
|
const fileManager = files.get(normalizedPath);
|
|
522
|
-
return fileManager !== void 0 && isTranslationRegisteringSource(fileManager.source);
|
|
545
|
+
return fileManager !== void 0 && isTranslationRegisteringSource(normalizedPath, fileManager.source);
|
|
523
546
|
}))) return;
|
|
524
547
|
await runTypingsGeneration(this.typingsGenerationPorts);
|
|
525
548
|
}
|