Skip to content

Conversation

@kingston
Copy link
Collaborator

@kingston kingston commented Jun 11, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a new TypeScript template extractor with advanced support for organizing imports, extracting variables, and managing export maps.
    • Added utilities for handling file ID maps and enhanced test utilities for template extraction and plugin testing.
    • Extended export fields in package configuration files for improved module access and compatibility.
    • Enhanced configuration and metadata schemas for TypeScript templates, supporting richer template and export definitions.
  • Bug Fixes

    • Improved error handling and validation for template path resolution and import organization.
    • Fixed issues related to duplicate template names and streamlined grouping logic.
  • Refactor

    • Centralized and simplified import paths and generator configuration management across multiple packages.
    • Reorganized plugins and utilities for better maintainability and modularity.
  • Tests

    • Added comprehensive unit tests for new extractors, import organizers, and utility functions.
    • Expanded test coverage for file ID map operations and plugin behaviors.
  • Chores

    • Updated documentation and comments for clarity and future maintenance.
    • Cleaned up and consolidated internal code structure and exports.

@vercel
Copy link

vercel bot commented Jun 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
baseplate-project-builder-web ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 6:20pm

@changeset-bot
Copy link

changeset-bot bot commented Jun 11, 2025

⚠️ No Changeset found

Latest commit: 4fb3498

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Jun 11, 2025

Walkthrough

This change introduces a comprehensive new "extractor-v2" system for TypeScript template extraction and code generation. It adds new extractor implementations, plugins for barrel export management, utilities for organizing imports, and project export mapping. The update includes new configuration files, test utilities, and integration points, while refactoring or removing legacy extractor logic.

Changes

File(s) / Path(s) Change Summary
packages/core-generators/src/renderers/typescript/extractor-v2/ (multiple new files) Added new extractor-v2 modules: project export map builder, import provider rendering, template file extractor, variable extraction, import organization, preprocessing, and typed template rendering.
packages/core-generators/src/renderers/typescript/extractor-v2/index.ts New module re-exporting extractor-v2 actions and extractor.
packages/core-generators/package.json, packages/sync/package.json Added new subpath exports for extractor-v2 modules and test-utils.
packages/core-generators/src/renderers/extractor/plugins/barrel-export.ts, .unit.test.ts, index.ts Added new barrel export plugin, unit tests, and index module for extractor plugins.
packages/core-generators/src/renderers/extractor/plugins/template-paths/paths-file.ts, template-paths.plugin.ts Refactored path file writing, export name handling, and plugin integration for extractor-v2.
packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts Enhanced typed templates plugin to register barrel exports and use generated directory constants.
packages/core-generators/src/renderers/extractor/plugins/index.ts New index module re-exporting extractor plugins.
packages/core-generators/src/renderers/text/utils.ts, .unit.test.ts Added new utility and tests for extracting template variables.
packages/core-generators/src/utils/ts-paths.ts, index.ts Added utility for normalizing TS paths to JS paths and re-exported it.
packages/core-generators/src/generators/node/ts-utils/ (several files) Added extractor config, index module, refactored generator to use generated configuration, removed legacy exports.
packages/core-generators/src/renderers/index.ts Switched from exporting templates to extractor modules.
packages/core-generators/src/renderers/typescript/templates/types.ts Introduced new schemas and types for template metadata, variables, and import providers.
packages/core-generators/src/renderers/typescript/extractor/ (multiple files) Updated types and schemas to align with new extractor-v2 metadata structures.
packages/core-generators/src/renderers/text/text-template-file-extractor.ts Refactored to use unified path resolution and variable extraction logic.
packages/core-generators/src/renderers/raw/types.ts, render-raw-template-action.ts Made RawTemplateFile generic over file options and updated related types.
packages/core-generators/src/renderers/raw/raw-template-file-extractor.ts Refactored to use unified path resolution and improved error handling.
packages/core-generators/src/renderers/typescript/typescript.generator.ts Added support for rendering template groups using extractor-v2.
packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts Improved type usage, metadata validation, and error handling for template rendering.
packages/core-generators/src/renderers/typescript/import-maps/types.ts Added comment for future property rename.
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts, .ts Updated tests and extractor to use new metadata types.
packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts, .unit.test.ts Updated types and test data for new metadata schema.
packages/core-generators/src/renderers/typescript/extractor/extract-ts-template-variables.ts Updated variable type annotations.
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts Switched to new output template metadata schema.
packages/core-generators/src/utils/index.ts Re-exported new TS path utility.
packages/fastify-generators/src/generators/core/ (multiple generator files, configs, and index.ts) Refactored imports to use generated index modules, added new extractor configs, and consolidated exports.
packages/fastify-generators/src/generators/core/logger-service/, config-service/, error-handler-service/ Added new index modules to re-export generated providers and generator logic.
packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts, config-service.generator.ts, error-handler-service.generator.ts Refactored to use generated configuration and imports, removed legacy exports.
packages/fastify-generators/src/generators/core/logger-service/extractor.json, config-service/extractor.json, error-handler-service/extractor.json Added new extractor configs for core generators.
packages/fastify-generators/src/generators/ (other generator files) Updated import paths to use new index modules.
packages/project-builder-server/src/sync/file-id-map.ts, .unit.test.ts Added new module and tests for managing file ID maps.
packages/project-builder-server/src/sync/generate-for-directory.ts Refactored to use new file ID map module.
packages/project-builder-server/src/template-extractor/run-template-extractor-v2.ts Integrated new extractor-v2 and file ID map logic.
packages/react-generators/src/generators/apollo/react-apollo/react-apollo.generator.ts Updated to use new output template metadata type.
packages/sync/src/templates/extractor-v2/ (multiple files: configs, runner, plugins, utils, test-utils, constants) Added new constants, updated config lookup and runner to support file ID maps and new plugin APIs, added new test utilities, and refactored hooks and merging logic.
packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.ts, .unit.test.ts Removed duplicate name validation and related tests.
packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.ts, .unit.test.ts Renamed and refactored to only update in-memory config, updated tests accordingly.
packages/sync/src/templates/extractor-v2/utils/write-extractor-template-jsons.ts Added utility to write extractor.json files for generators.
packages/sync/src/templates/extractor-v2/test-utils/ (multiple new files) Added test utilities for creating mock contexts, plugin instances, and test file structures.
packages/sync/src/templates/extractor-v2/runner/template-extractor-plugin.ts Clarified hook documentation and added exported utility type for plugin instances.
packages/sync/src/templates/extractor-v2/runner/template-file-extractor.ts Added generic extraction context type to extractor interfaces and methods.
packages/sync/src/templates/extractor-v2/runner/initialize-template-extractor-plugins.unit.test.ts Updated test context creation to support new config lookup signature.
packages/sync/src/templates/extractor-v2/runner/template-extractor-api.ts Switched to use new directory constants for file writing.
packages/sync/src/templates/extractor-v2/run-template-file-extractors.ts Added file ID map parameter, refactored merging and writing logic, and updated hook execution order.
packages/sync/src/templates/extractor-v2/constants/ (new files) Added constants for generated and templates directories.
packages/sync/src/templates/extractor-v2/index.ts Re-exported new constants module.
packages/sync/src/utils/parse-generator-name.ts Updated documentation comments with examples.
packages/sync/src/templates/metadata/metadata.ts, packages/sync/src/templates/utils/read-template-file-source.ts Updated TODO comment dates.
packages/core-generators/src/renderers/templates/plugins/barrel-import.ts, .unit.test.ts, index.ts Deleted legacy barrel import plugin, its tests, and index module.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ProjectBuilder
    participant FileIdMap
    participant ExtractorV2
    participant Plugins
    participant BarrelExport
    participant ImportProvider
    participant TypedTemplates

    User->>ProjectBuilder: Initiate code generation
    ProjectBuilder->>FileIdMap: getPreviousGeneratedFileIdMap()
    FileIdMap-->>ProjectBuilder: Map<fileId, relativePath>
    ProjectBuilder->>ExtractorV2: runTemplateFileExtractors(..., fileIdMap)
    ExtractorV2->>Plugins: initialize and run hooks
    ExtractorV2->>ExtractorV2: Extract template metadata
    ExtractorV2->>Plugins: afterExtract hooks
    ExtractorV2->>ExtractorV2: Write template files
    ExtractorV2->>BarrelExport: Register barrel exports
    ExtractorV2->>ImportProvider: Render import providers
    ExtractorV2->>TypedTemplates: Render typed templates
    ExtractorV2->>Plugins: afterWrite hooks
    ExtractorV2->>FileIdMap: writeGeneratedFileIdMap()
    FileIdMap-->>ProjectBuilder: Done
    ProjectBuilder-->>User: Generation complete
Loading

Possibly related PRs

  • halfdomelabs/baseplate#499: Refactors the older organize-ts-template-imports.ts in the extractor directory, while this PR introduces a new version in extractor-v2, both evolving the import organization functionality.
  • halfdomelabs/baseplate#570: Implements foundational infrastructure for the Template Extractor V2 system, which is extended and integrated in this PR.
  • halfdomelabs/baseplate#487: Introduces a new TsImportMap system and refactors output providers, closely related to the new extractor-v2 modules and import handling logic in this PR.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🔭 Outside diff range comments (1)
packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.ts (1)

35-41: ⚠️ Potential issue

Handle missing templates section to avoid a runtime crash

generatorConfig.config may legitimately omit the templates key on first extraction.
When that happens Object.entries(templates) will receive undefined and throw.

-const { name, templates, extractors, ...rest } = generatorConfig.config;
+const {
+  name,
+  templates = {},      // ✅ default to empty object
+  extractors,
+  ...rest
+} = generatorConfig.config;

A defensive default prevents the whole merge from failing on an empty config.

🧹 Nitpick comments (43)
packages/fastify-generators/src/generators/core/readme/extractor.json (1)

9-9: Ensure missing default is handled & consider marking as required
The "default" field was removed from TPL_PROJECT, so consumers must now supply this value at generation time.

  • Verify that the extractor framework gracefully handles a missing default (i.e., doesn’t error or fall back incorrectly).
  • Optionally, add a "required": true flag to the variable definition to make intent explicit.
packages/fastify-generators/src/generators/prisma/prisma/prisma.generator.ts (1)

33-33: Consider simplifying the import by dropping the explicit index.js suffix.

Node/TypeScript will resolve index files automatically. For consistency and brevity, you could use:

-import { configServiceProvider } from '#src/generators/core/config-service/index.js';
+import { configServiceProvider } from '#src/generators/core/config-service';
packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.unit.test.ts (1)

21-34: Heavy repetition – extract a helper to build test files

Every test now repeats the same fileOptions, type, generator, etc. Consider introducing a small factory, e.g.

function testFile(
  override: Partial<TsTemplateOutputTemplateMetadata> = {},
  path = '/test/path/file1.ts',
): TemplateFileExtractorFile<TsTemplateOutputTemplateMetadata> {
  return {
    path,
    metadata: {
      type: 'ts',
      generator: TEST_GENERATOR_NAME,
      name: 'test',
      template: '',
      fileOptions: { kind: 'singleton' },
      ...override,
    },
  };
}

This keeps each test focused on what it actually varies.

packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (1)

70-91: Deduplicate the repeated { kind: 'singleton' } literal

The identical fileOptions object is inlined in every test case. Consider extracting it to a const SINGLETON_FILE_OPTIONS = { kind: 'singleton' } as const; near the top of the file and re-using it. This keeps the test DRY and reduces maintenance if the option shape ever changes.

-          fileOptions: { kind: 'singleton' },
+          fileOptions: SINGLETON_FILE_OPTIONS,

Apply the same replacement for the other occurrences (lines 90-91, 178-179, 330-331, 343-344, 356-357, 369-370, 533-534, 547-548, 685-686, 699-700).

packages/core-generators/src/utils/ts-paths.ts (1)

1-10: Edge-case: .d.ts and non-TS/JS extensions remain untouched

If you later feed a .d.ts or .mts path into this helper it will fall through unmodified, producing mixed .d.ts/.mts imports. At minimum add a JSDoc note clarifying that only .ts/.tsx/.js/.jsx files are expected, or extend the regex.

- * @param filePath - The file path to normalize with a *.ts or *.tsx extension.
+ * @param filePath - The file path to normalize (expects *.ts, *.tsx, *.js or *.jsx).

A unit test covering these edge extensions would also lock behaviour.

packages/core-generators/src/renderers/typescript/extractor-v2/get-resolver-factory.ts (1)

9-14: Consider memoising resolver factories per working directory

ResolverFactory construction is relatively expensive (it parses the referenced tsconfig.json).
If callers invoke getResolverFactory() repeatedly for the same directory during a single extraction run, caching the instance will save a noticeable amount of CPU.

A simple Map-based memoisation keyed by the canonicalised workingDirectory would suffice and keeps the public API unchanged.

packages/project-builder-server/src/template-extractor/run-template-extractor-v2.ts (2)

98-105: Gracefully handle corrupted or mismatched file-ID maps

getPreviousGeneratedFileIdMap already wraps JSON-parse errors, but if the returned map contains stale paths (e.g., files manually deleted), runTemplateFileExtractors may throw later when it attempts to read those files.

Consider pruning entries whose target no longer exists before passing the map downstream:

-  const fileIdMap = await getPreviousGeneratedFileIdMap(appDirectories[0]);
+  const fileIdMap = await getPreviousGeneratedFileIdMap(appDirectories[0]);
+  // Remove IDs pointing at vanished files to avoid cascade failures
+  for (const [id, relPath] of fileIdMap) {
+    if (!fs.existsSync(path.join(appDirectories[0], relPath))) {
+      fileIdMap.delete(id);
+    }
+  }

(This requires an additional import fs from 'node:fs';)


24-28: Extractor order: ensure TsTemplateFileExtractor precedes fallback extractors if overlap is possible

TextTemplateFileExtractor may accept .ts files if mis-configured, leading to double processing.
If that risk exists, place TsTemplateFileExtractor before more generic extractors or add an explicit file-type guard inside each extractor.

packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts (1)

107-108: Consider adding a generic to tighten the files parameter

You could make the function generic and propagate the metadata subtype:

export function writeTsProjectExports<
  TMeta extends TsTemplateOutputTemplateMetadata,
>(
  files: TemplateFileExtractorFile<TMeta>[],
  ...
)

It costs nothing and prevents accidental misuse with a looser metadata shape.

packages/core-generators/src/renderers/typescript/extractor-v2/preprocess-code-for-extraction-hack.test.ts (2)

1-4: Import path extension may back-fire under moduleResolution: node16
Importing a sibling TypeScript file using the .js extension relies on TS’ “import as JS” allowance. If this repo ever switches to the stricter moduleResolution: nodenext + verbatimModuleSyntax, the compiler will refuse to resolve ./preprocess-code-for-extraction-hack.js because the emitted file will actually be .cjs/.mjs. Consider keeping the specifier extensionless or .ts and let build-time tools rewrite it.


8-26: String-equality assertions are brittle – consider trimming leading indent
The current toBe comparison will fail if an extra indent or trailing newline sneaks in. Using a helper such as stripIndent/dedent or expect(result.trim()).toBe(expected.trim()) makes the test intention (marker relocation) independent of whitespace noise.

packages/project-builder-server/src/sync/file-id-map.unit.test.ts (2)

10-12: Redundant manual mocks
vitest.config already automocks node:fs and node:fs/promises via memfs (see past PR-510). Re-declaring vi.mock here is unnecessary noise and can accidentally shadow different mock implementations in the future.


45-47: vol.fromJSON({ 'dir/': null }) creates a file, not a folder
memfs interprets a key ending with / and value null as an empty file. If writeGeneratedFileIdMap expects the directory to exist, the test passes only because the implementation calls mkdir -p internally. Prefer creating the directory explicitly to reflect real-world usage:

-      vol.fromJSON({
-        'test-project/baseplate/': null,
-      });
+      vol.mkdirSync('test-project/baseplate', { recursive: true });
packages/core-generators/src/renderers/typescript/extractor-v2/extract-ts-template-variables.ts (1)

45-48: TsTemplateFileVariable type ignored
discoveredVariables[fullName] = {}; relies on the type having no required fields. If the interface ever grows mandatory properties the compiler will silently accept as any here. Consider instantiating via as const satisfies TsTemplateFileVariable or a factory helper to retain type-safety.

packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.unit.test.ts (1)

62-66: Prefer new Map() over redundant generic & arg

new Map<string, string>([]) adds unnecessary verbosity (and an empty array allocation).
Use new Map<string, string>() or simply new Map() to improve readability.

Also applies to: 150-154, 216-220, 267-271, 324-328, 407-411, 483-487

packages/core-generators/src/renderers/text/utils.ts (1)

41-43: RegExp is case-sensitive

getTextTemplateVariableRegExp uses a plain g flag. If template replacement should be case-insensitive, add i.

packages/core-generators/src/generators/node/ts-utils/ts-utils.generator.ts (2)

16-18: Task name collision: paths

You now have
• a task called paths (NODE_TS_UTILS_GENERATED.paths.task)
• a dependency called paths (NODE_TS_UTILS_GENERATED.paths.provider)

Although sync keeps task and dependency namespaces separate, re-using the same identifier is confusing. Consider renaming one of them (pathsProvider etc.) to improve readability.


26-33: Avoid double casting of key

Casting twice clutters the loop:

-for (const key of Object.keys(NODE_TS_UTILS_GENERATED.templates)) {
-  const template = NODE_TS_UTILS_GENERATED.templates[key as TsUtilKey];
+for (const [key, template] of Object.entries(
+  NODE_TS_UTILS_GENERATED.templates,
+) as [TsUtilKey, unknown][]) {

This keeps type-safety without repetitive as noise.

packages/core-generators/src/renderers/typescript/extractor-v2/default-import-providers.ts (1)

38-43: Placeholder specifier consistency

placeholderModuleSpecifier uses camelCase whereas providerName uses kebab-case. Double-check downstream code (e.g. render-ts-import-providers) expects this exact %camelCaseImports form; otherwise mismatches will occur.

packages/core-generators/src/generators/node/typescript/typescript.generator.ts (3)

18-32: Prefer clearer alias names for v2 imports

Importing the type and the function from the same module and aliasing both to something ending in “V2” is fine, but using the original RenderTsTemplateGroupActionInput identifier for the alias (RenderTsTemplateGroupActionInputV2) while simultaneously alias-renaming the function to renderTsTemplateGroupActionV2 makes the code harder to scan.
A more explicit alias such as RenderTsTemplateGroupActionInput_V2 (or keeping the original name and aliasing the v1 version instead) would reduce the mental load when jumping between v1/v2 implementations.


120-131: addLazyTemplateGroup has no v2 counterpart

You introduced renderTemplateGroupV2, but there is still no addLazyTemplateGroupV2.
If downstream generators start emitting template groups with the new Record<string, TsTemplateFile> signature they cannot be queued lazily, which breaks the “render-on-demand” optimisation the rest of the provider relies on.

Consider adding:

addLazyTemplateGroupV2<T extends Record<string, TsTemplateFile>>(
  payload: RenderTsTemplateGroupActionInputV2<T> & { generatorInfo: GeneratorInfo },
  options?: Omit<LazyTemplateFileEntry, 'payload'>,
): void;

and piping it through the same lazyTemplates mechanism.


354-366: Common render-options block duplicated – extract helper

The bodies of renderTemplateGroup and renderTemplateGroupV2 differ only in the callee (renderTsTemplateGroupAction vs …V2). Duplicating the entire options object inflates the provider and risks config drift.

-              renderTemplateGroupV2: (payload) =>
-                renderTsTemplateGroupActionV2({
-                  ...payload,
-                  renderOptions: {
-                    resolveModule(moduleSpecifier, sourceDirectory) {
-                      return resolveModuleSpecifier(
-                        moduleSpecifier,
-                        sourceDirectory,
-                      );
-                    },
-                    ...sharedRenderOptions,
-                  },
-                }),
+              renderTemplateGroupV2: (payload) =>
+                renderTemplateGroupGeneric(renderTsTemplateGroupActionV2, payload),

where renderTemplateGroupGeneric is a small local helper. This keeps the two paths perfectly in sync.

packages/core-generators/src/renderers/extractor/plugins/barrel-export.unit.test.ts (2)

9-15: Type-only import should reference the .ts file, not the built .js

import type { TemplateExtractorGeneratedBarrelExport } from './barrel-export.js';

When compiling the test suite with TypeScript, importing a type from a .js path forces allowImportingTsExtensions or ends up as any. Point the compiler at the real source:

-import type { TemplateExtractorGeneratedBarrelExport } from './barrel-export.js';
+import type { TemplateExtractorGeneratedBarrelExport } from './barrel-export';

(At runtime Vitest resolves to the transpiled .js anyway.)


24-49: Inline snapshots are brittle

All snapshot assertions use toMatchInlineSnapshot(). Any innocuous refactor (different prettier, line-ending, trailing comma) will break the snapshot and create noisy diffs. Prefer semantic assertions:

expect(result.trim()).toBe(
  "export { quux, qux } from './bar';\n" +
  "export * from './baz';\n" +
  "export { baz } from './foo';",
);

This still guarantees exact output while avoiding the maintenance overhead of inline snapshots.

packages/core-generators/src/renderers/typescript/extractor-v2/preprocess-code-for-extraction-hack.ts (1)

49-55: replaceAll requires Node v15+. Guard or polyfill if older LTS is supported

If the toolchain still needs to run on Node 14 (or on browsers without String.prototype.replaceAll), switch to code.replace(regex, …).

packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.ts (1)

46-50: Duplicate-removal logic only checks by name

You drop existing templates when a name collides, but keep duplicates when
generatorTemplatePath is reused under a different name.
Depending on downstream assumptions this may re-introduce the same file twice.

Consider also de-duplicating on generatorTemplatePath, or assert uniqueness earlier in the pipeline.

packages/core-generators/src/renderers/raw/raw-template-file-extractor.ts (1)

53-70: Minor: avoid per-file try/catch for common I/O failures

Wrapping every limited task with an identical try / catch adds noise and slightly
hurts performance. You could instead:

  1. Pull readOutputFile + writeTemplateFile into a small helper that already
    includes the error context, or
  2. Catch at the Promise.all level—p-limit will surface the original stack.

Not blocking, just a simplification suggestion.

packages/sync/src/templates/extractor-v2/test-utils/file-system-utils.ts (1)

36-41: Use path.posix join for OS-agnostic test paths

Hard-coding / works on POSIX but breaks on Windows when tests run there.

-import { join as joinPath } from 'path';
...
-files[`${generatorPath}/templates/${templatePath}`] = templateContent;
+files[joinPath(generatorPath, 'templates', templatePath)] = templateContent;

Not critical if your CI is Unix-only, but makes the helper truly cross-platform.

packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.ts (1)

6-13: Update JSDoc – description & @throws are now misleading

The implementation no longer performs duplicate-name detection or throws an error, yet the comment still claims it does. This will confuse maintainers and consumers of the utility.
Remove the outdated information or re-introduce validation.

packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts (1)

41-47: Minor: capture dependency on barrel plugin via the returned instance, not name

context.getPlugin(templateExtractorBarrelExportPlugin.name) hinges on the plugin being registered exactly once and by that name.
Passing the actual plugin reference from pluginDependencies (returned in the same order) avoids string coupling and is less error-prone.

packages/core-generators/src/renderers/typescript/extractor-v2/extract-ts-template-variables.unit.test.ts (1)

22-30: Inline snapshots with large whitespace blocks are brittle

Tiny formatting changes in the implementation will force snapshot updates that add no semantic value.
Consider asserting with .toContain() / .replace(/\s+/g,'') or explicit substrings for the placeholders instead.

packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (1)

117-118: Track the migration TODOs to ensure completion.

There are two TODO comments indicating incomplete migration work. Please ensure these are tracked in your issue tracker with a clear migration plan and timeline.

Would you like me to create GitHub issues to track these migration tasks?

Also applies to: 129-131

packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-template-group-action.ts (1)

78-148: Well-structured template group rendering with strong typing.

The implementation demonstrates excellent TypeScript practices with complex type inference and proper error handling. The validation of import map providers prevents runtime errors.

Consider extracting the type assertion logic on lines 119-123 to a helper function for better readability:

+              const getTemplateVariables = (
+                variables: unknown,
+                key: string
+              ): Record<never, string> | undefined => {
+                if (!variables || typeof variables !== 'object') return undefined;
+                return (variables as Record<string, unknown>)[key] as Record<never, string>;
+              };
+
               variables:
-                variables && typeof variables === 'object'
-                  ? (variables[key as keyof typeof variables] as Record<
-                      never,
-                      string
-                    >)
-                  : undefined,
+                getTemplateVariables(variables, key),
packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-import-providers.ts (2)

56-57: Simplify the conditional assignment

The ternary operator with undefined as the false case is redundant.

-          isTypeOnly: projectExport.isTypeOnly ? true : undefined,
+          isTypeOnly: projectExport.isTypeOnly,

194-198: Enhance error message with template information

The error message could be more helpful by including which templates contain the duplicate exports.

       if (duplicateProjectExports.length > 0) {
+        const duplicateDetails = duplicateProjectExports.map(dup => {
+          const template = templates.find(t => 
+            Object.keys(t.config.projectExports ?? {}).includes(dup.name)
+          );
+          return `${dup.name} (in template: ${template?.config.name ?? 'unknown'})`;
+        });
         throw new Error(
-          `Duplicate project exports found in template files for generator ${generatorName}: ${duplicateProjectExports.map((fileExport) => fileExport.name).join(', ')}`,
+          `Duplicate project exports found in template files for generator ${generatorName}: ${duplicateDetails.join(', ')}`,
         );
       }
packages/core-generators/src/renderers/typescript/extractor-v2/organize-ts-template-imports.ts (2)

93-104: Consider tracking the known limitation

The documented limitation about incorrectly identifying used imports when identifiers are redeclared in different scopes is a valid trade-off for performance. Consider creating a tracking issue for this limitation in case it becomes problematic in practice.

Would you like me to create an issue to track this known limitation for future improvement?


185-188: Fix grammatical error in error message

         throw new Error(
-          `Import ${moduleSpecifier} in ${filePath} cannot be a namespace import since it are not supported currently
+          `Import ${moduleSpecifier} in ${filePath} cannot be a namespace import since they are not supported currently
           for template extraction.`,
         );
packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-typed-templates.ts (1)

78-78: Consider compatibility for ES2023 toSorted() method

The toSorted() method is an ES2023 feature that may not be available in all environments. Consider using the traditional sort() method with array spread for better compatibility.

-  const renderedTemplates = templates
-    .map(({ path, config }) => renderTsTypedTemplate(path, config, context))
-    .toSorted((a, b) => a.exportName.localeCompare(b.exportName));
+  const renderedTemplates = templates
+    .map(({ path, config }) => renderTsTypedTemplate(path, config, context))
+    .sort((a, b) => a.exportName.localeCompare(b.exportName));
packages/sync/src/templates/extractor-v2/test-utils/mock-context.ts (2)

32-37: Remove redundant type assertions

The type assertions for packageMap and fileIdMap are unnecessary as they're already typed correctly from the function parameters.

  const configLookup = new TemplateExtractorConfigLookup(
-    packageMap as Map<string, string>,
-    fileIdMap as Map<string, string>,
+    packageMap,
+    fileIdMap,
  );
  const fileContainer = new TemplateExtractorFileContainer([
-    ...packageMap.values(),
-  ] as string[]);
+    ...packageMap.values(),
+  ]);

67-71: Document the private property access pattern

While accessing private properties is acceptable in test utilities, consider adding a comment explaining why this approach is necessary.

  // Access the private cache directly for testing
+  // This is necessary to bypass the normal initialization flow and inject test data directly
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
  const configLookup = context.configLookup as any;
packages/sync/src/templates/extractor-v2/test-utils/plugin-test-utils.ts (1)

68-70: Add comment to clarify no-op behavior

The empty async function serves as a no-op for external APIs. Consider adding a comment for clarity.

      : async () => {
-          // No-op for external APIs
+          // No-op for external APIs that don't support hook execution
        };
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (1)

322-351: Consider documenting the in-place mutation behavior.

The updateExtractorTemplateConfig method correctly updates the template configuration, but it mutates the cached config object directly. While this is acceptable for a cache service, consider adding a JSDoc comment to clarify this behavior for users of the API.

Add documentation about the mutation behavior:

   /**
    * Update the template config for a generator
+   * Note: This mutates the cached configuration in place
    * @param generatorName - The name of the generator
    * @param config - The template config to update
    */
packages/core-generators/src/renderers/typescript/templates/types.ts (1)

34-40: Address the overdue TODO comment.

The TODO comment indicates that exportName should be renamed to exportedName. Since the due date (2025-06-10) has passed, this should be addressed now.

Would you like me to create an issue to track this renaming task or generate a PR to implement the change?

🧰 Tools
🪛 ESLint

[error] 34-38: There is a TODO that is past due date: 2025-06-10. Rename this to exportedName

(unicorn/expiring-todo-comments)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56a3a89 and 4fb3498.

⛔ Files ignored due to path filters (37)
  • packages/core-generators/src/generators/node/ts-utils/generated/index.ts is excluded by !**/generated/**
  • packages/core-generators/src/generators/node/ts-utils/generated/template-paths.ts is excluded by !**/generated/**
  • packages/core-generators/src/generators/node/ts-utils/generated/ts-import-providers.ts is excluded by !**/generated/**
  • packages/core-generators/src/generators/node/ts-utils/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/core-generators/src/generators/node/ts-utils/generated/typed-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/auth/auth-context/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/bull/bull-mq/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/bull/fastify-bull-board/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/index.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/template-paths.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/ts-import-maps.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/ts-import-providers.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/config-service/generated/typed-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/index.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/template-paths.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/ts-import-maps.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/ts-import-providers.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/typed-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/fastify-graceful-shutdown/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/fastify-redis/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/fastify-scripts/generated/index.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/fastify-sentry/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/fastify-server/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/index.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/template-paths.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/ts-import-maps.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/ts-import-providers.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/typed-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/readme/generated/index.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/email/fastify-postmark/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/pothos/pothos-auth/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/pothos/pothos-scalar/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/stripe/fastify-stripe/generated/ts-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/yoga/yoga-plugin/generated/ts-templates.ts is excluded by !**/generated/**
📒 Files selected for processing (107)
  • packages/core-generators/package.json (1 hunks)
  • packages/core-generators/src/generators/metadata/path-roots/path-roots.generator.ts (1 hunks)
  • packages/core-generators/src/generators/node/index.ts (1 hunks)
  • packages/core-generators/src/generators/node/ts-utils/extractor.json (1 hunks)
  • packages/core-generators/src/generators/node/ts-utils/index.ts (1 hunks)
  • packages/core-generators/src/generators/node/ts-utils/ts-extractor.json (0 hunks)
  • packages/core-generators/src/generators/node/ts-utils/ts-utils.generator.ts (1 hunks)
  • packages/core-generators/src/generators/node/typescript/typescript.generator.ts (4 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/barrel-export.ts (1 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/barrel-export.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/index.ts (1 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/template-paths/paths-file.ts (5 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/template-paths/template-paths.plugin.ts (7 hunks)
  • packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts (4 hunks)
  • packages/core-generators/src/renderers/extractor/utils/package-path-specifier.ts (1 hunks)
  • packages/core-generators/src/renderers/index.ts (1 hunks)
  • packages/core-generators/src/renderers/raw/raw-template-file-extractor.ts (2 hunks)
  • packages/core-generators/src/renderers/raw/render-raw-template-action.ts (1 hunks)
  • packages/core-generators/src/renderers/raw/types.ts (1 hunks)
  • packages/core-generators/src/renderers/schemas/template-file-options.ts (1 hunks)
  • packages/core-generators/src/renderers/templates/plugins/barrel-import.ts (0 hunks)
  • packages/core-generators/src/renderers/templates/plugins/barrel-import.unit.test.ts (0 hunks)
  • packages/core-generators/src/renderers/templates/plugins/index.ts (0 hunks)
  • packages/core-generators/src/renderers/text/text-template-file-extractor.ts (2 hunks)
  • packages/core-generators/src/renderers/text/utils.ts (2 hunks)
  • packages/core-generators/src/renderers/text/utils.unit.test.ts (2 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (4 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/build-ts-project-export-map.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/default-import-providers.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/extract-ts-template-variables.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/extract-ts-template-variables.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/get-resolver-factory.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/index.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/organize-ts-template-imports.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/organize-ts-template-imports.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/preprocess-code-for-extraction-hack.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/preprocess-code-for-extraction-hack.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-import-providers.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-template-file.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-template-group-action.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-typed-templates.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor-v2/ts-template-file-extractor.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/extract-ts-template-variables.ts (3 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts (8 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (11 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts (2 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.unit.test.ts (8 hunks)
  • packages/core-generators/src/renderers/typescript/import-maps/types.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/templates/types.ts (4 hunks)
  • packages/core-generators/src/utils/index.ts (1 hunks)
  • packages/core-generators/src/utils/ts-paths.ts (1 hunks)
  • packages/fastify-generators/src/generators/auth/auth-context/auth-context.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/bull/bull-mq/bull-mq.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/bull/fastify-bull-board/fastify-bull-board.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/_composers/fastify-composer.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/axios/axios.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts (4 hunks)
  • packages/fastify-generators/src/generators/core/config-service/extractor.json (1 hunks)
  • packages/fastify-generators/src/generators/core/config-service/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (5 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/extractor.json (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-graceful-shutdown/fastify-graceful-shutdown.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-redis/fastify-redis.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-scripts/fastify-scripts.generator.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/fastify-sentry/fastify-sentry.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-server/fastify-server.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/index.ts (2 hunks)
  • packages/fastify-generators/src/generators/core/logger-service/extractor.json (1 hunks)
  • packages/fastify-generators/src/generators/core/logger-service/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/readme/extractor.json (1 hunks)
  • packages/fastify-generators/src/generators/core/request-context/request-context.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/email/fastify-postmark/fastify-postmark.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-auth/pothos-auth.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-scalar/pothos-scalar.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/prisma/prisma/prisma.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/stripe/fastify-stripe/fastify-stripe.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/yoga/yoga-plugin/yoga-plugin.generator.ts (1 hunks)
  • packages/project-builder-server/src/sync/file-id-map.ts (1 hunks)
  • packages/project-builder-server/src/sync/file-id-map.unit.test.ts (1 hunks)
  • packages/project-builder-server/src/sync/generate-for-directory.ts (2 hunks)
  • packages/project-builder-server/src/template-extractor/run-template-extractor-v2.ts (3 hunks)
  • packages/react-generators/src/generators/apollo/react-apollo/react-apollo.generator.ts (2 hunks)
  • packages/sync/package.json (1 hunks)
  • packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (6 hunks)
  • packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.unit.test.ts (13 hunks)
  • packages/sync/src/templates/extractor-v2/constants/directories.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/constants/index.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/index.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/run-template-file-extractors.ts (7 hunks)
  • packages/sync/src/templates/extractor-v2/runner/initialize-template-extractor-plugins.unit.test.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/runner/template-extractor-api.ts (3 hunks)
  • packages/sync/src/templates/extractor-v2/runner/template-extractor-plugin.ts (2 hunks)
  • packages/sync/src/templates/extractor-v2/runner/template-file-extractor.ts (5 hunks)
  • packages/sync/src/templates/extractor-v2/test-utils/file-system-utils.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/test-utils/index.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/test-utils/mock-context.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/test-utils/plugin-test-utils.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.ts (1 hunks)
  • packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.unit.test.ts (0 hunks)
  • packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.ts (2 hunks)
  • packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.unit.test.ts (14 hunks)
  • packages/sync/src/templates/extractor-v2/utils/write-extractor-template-jsons.ts (1 hunks)
  • packages/sync/src/templates/metadata/metadata.ts (1 hunks)
  • packages/sync/src/templates/utils/read-template-file-source.ts (1 hunks)
  • packages/sync/src/utils/parse-generator-name.ts (1 hunks)
💤 Files with no reviewable changes (5)
  • packages/core-generators/src/generators/node/ts-utils/ts-extractor.json
  • packages/core-generators/src/renderers/templates/plugins/index.ts
  • packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.unit.test.ts
  • packages/core-generators/src/renderers/templates/plugins/barrel-import.unit.test.ts
  • packages/core-generators/src/renderers/templates/plugins/barrel-import.ts
🧰 Additional context used
🧠 Learnings (3)
packages/core-generators/src/renderers/extractor/utils/package-path-specifier.ts (1)
Learnt from: kingston
PR: halfdomelabs/baseplate#521
File: packages/react-generators/src/generators/admin/admin-crud-edit/admin-crud-edit.generator.ts:90-94
Timestamp: 2025-05-05T06:36:50.687Z
Learning: In this codebase, import paths can include `.ts` extensions, and the `resolveModuleSpecifier` function will handle them appropriately. There's no need to strip file extensions before passing paths to functions like `TsCodeUtils.importFragment`.
packages/project-builder-server/src/sync/file-id-map.unit.test.ts (3)
Learnt from: kingston
PR: halfdomelabs/baseplate#510
File: packages/project-builder-server/src/sync/conflict-file-monitor.test.ts:19-24
Timestamp: 2025-04-23T06:44:30.952Z
Learning: When testing file operations in this codebase, the pattern is to use Vitest automocks for 'node:fs' and 'node:fs/promises' (without explicit implementation replacement) while populating a virtual filesystem with vol.fromJSON() from memfs. File operations in tests are performed directly via vol.promises methods.
Learnt from: kingston
PR: halfdomelabs/baseplate#510
File: packages/project-builder-server/src/sync/conflict-file-monitor.test.ts:19-24
Timestamp: 2025-04-23T06:44:30.952Z
Learning: In this codebase, when testing file operations, Vitest's automocks for 'node:fs' and 'node:fs/promises' are used in conjunction with memfs, but without replacing the mock implementation explicitly in each test file. The virtual filesystem is populated using vol.fromJSON or similar methods, which works seamlessly with the automocks.
Learnt from: kingston
PR: halfdomelabs/baseplate#510
File: packages/project-builder-server/src/sync/conflict-file-monitor.test.ts:19-24
Timestamp: 2025-04-23T06:44:30.952Z
Learning: In the project-builder-server test suite, Vitest automocks for 'node:fs' and 'node:fs/promises' are already configured to use memfs without needing explicit implementation replacement in each test file.
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.unit.test.ts (1)
Learnt from: kingston
PR: halfdomelabs/baseplate#510
File: packages/project-builder-server/src/sync/conflict-file-monitor.test.ts:19-24
Timestamp: 2025-04-23T06:44:30.952Z
Learning: When testing file operations in this codebase, the pattern is to use Vitest automocks for 'node:fs' and 'node:fs/promises' (without explicit implementation replacement) while populating a virtual filesystem with vol.fromJSON() from memfs. File operations in tests are performed directly via vol.promises methods.
🧬 Code Graph Analysis (25)
packages/core-generators/src/renderers/typescript/extractor/extract-ts-template-variables.ts (1)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateFileVariable (130-130)
packages/sync/src/templates/extractor-v2/runner/initialize-template-extractor-plugins.unit.test.ts (1)
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (1)
  • TemplateExtractorConfigLookup (43-352)
packages/react-generators/src/generators/apollo/react-apollo/react-apollo.generator.ts (1)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateOutputTemplateMetadata (126-128)
packages/sync/src/templates/extractor-v2/runner/template-extractor-api.ts (1)
packages/sync/src/templates/extractor-v2/constants/directories.ts (2)
  • TEMPLATE_EXTRACTOR_TEMPLATES_DIRECTORY (2-2)
  • TEMPLATE_EXTRACTOR_GENERATED_DIRECTORY (1-1)
packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.unit.test.ts (2)
packages/sync/src/templates/extractor/template-file-extractor.ts (1)
  • TemplateFileExtractorFile (17-28)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateOutputTemplateMetadata (126-128)
packages/fastify-generators/src/generators/core/fastify-scripts/fastify-scripts.generator.ts (3)
packages/fastify-generators/src/generators/core/fastify-scripts/generated/index.ts (1)
  • CORE_FASTIFY_SCRIPTS_GENERATED (4-7)
packages/sync/src/generators/generators.ts (1)
  • createGeneratorTask (196-204)
packages/fastify-generators/src/generators/core/fastify/fastify.generator.ts (1)
  • fastifyOutputProvider (77-78)
packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts (2)
packages/sync/src/templates/extractor/template-file-extractor.ts (1)
  • TemplateFileExtractorFile (17-28)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateOutputTemplateMetadata (126-128)
packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-typed-templates.ts (6)
packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts (1)
  • TemplateExtractorTypedTemplate (26-29)
packages/core-generators/src/renderers/typescript/utils/ts-code-utils.ts (2)
  • TsCodeUtils (85-580)
  • tsTemplate (583-583)
packages/utils/src/string/quot.ts (1)
  • quot (6-8)
packages/core-generators/src/renderers/typescript/imports/builder.ts (1)
  • tsImportBuilder (74-82)
packages/core-generators/src/renderers/extractor/utils/package-path-specifier.ts (1)
  • resolvePackagePathSpecifier (36-46)
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (1)
  • TemplateExtractorTemplateEntry (33-38)
packages/core-generators/src/renderers/extractor/plugins/barrel-export.unit.test.ts (1)
packages/core-generators/src/renderers/extractor/plugins/barrel-export.ts (4)
  • mergeBarrelExports (22-121)
  • mergeGeneratedBarrelExports (123-202)
  • TemplateExtractorGeneratedBarrelExport (16-20)
  • templateExtractorBarrelExportPlugin (204-315)
packages/core-generators/src/generators/node/ts-utils/ts-utils.generator.ts (4)
packages/core-generators/src/generators/node/ts-utils/generated/index.ts (1)
  • NODE_TS_UTILS_GENERATED (5-9)
packages/sync/src/utils/create-generator.ts (1)
  • createGenerator (96-123)
packages/sync/src/generators/generators.ts (1)
  • createGeneratorTask (196-204)
packages/core-generators/src/generators/node/typescript/typescript.generator.ts (1)
  • typescriptFileProvider (148-149)
packages/core-generators/src/renderers/typescript/extractor-v2/default-import-providers.ts (1)
packages/sync/src/utils/parse-generator-name.ts (1)
  • parseGeneratorName (28-41)
packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts (1)
packages/fastify-generators/src/generators/core/config-service/generated/index.ts (1)
  • CORE_CONFIG_SERVICE_GENERATED (5-9)
packages/core-generators/src/generators/node/typescript/typescript.generator.ts (1)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateFile (134-168)
packages/project-builder-server/src/sync/generate-for-directory.ts (1)
packages/project-builder-server/src/sync/file-id-map.ts (1)
  • writeGeneratedFileIdMap (47-58)
packages/project-builder-server/src/template-extractor/run-template-extractor-v2.ts (3)
packages/core-generators/src/renderers/typescript/extractor-v2/ts-template-file-extractor.ts (1)
  • TsTemplateFileExtractor (31-183)
packages/project-builder-server/src/sync/file-id-map.ts (1)
  • getPreviousGeneratedFileIdMap (18-39)
packages/sync/src/templates/extractor-v2/run-template-file-extractors.ts (1)
  • runTemplateFileExtractors (37-176)
packages/core-generators/src/renderers/raw/types.ts (2)
packages/core-generators/src/renderers/schemas/template-file-options.ts (1)
  • TemplateFileOptions (24-24)
packages/sync/src/templates/types.ts (1)
  • TemplateFileBase (21-34)
packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (2)
packages/core-generators/src/renderers/typescript/templates/types.ts (2)
  • TsTemplateFileVariable (130-130)
  • TsTemplateOutputTemplateMetadata (126-128)
packages/sync/src/utils/canonical-path.ts (1)
  • normalizePathToProjectPath (16-21)
packages/sync/src/templates/extractor-v2/test-utils/file-system-utils.ts (2)
packages/sync/src/templates/extractor-v2/test-utils/index.ts (1)
  • createTestFiles (5-5)
packages/sync/src/templates/extractor/template-file-extractor-test-utils.ts (1)
  • templatePath (66-77)
packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (9)
packages/fastify-generators/src/generators/core/error-handler-service/generated/index.ts (1)
  • CORE_ERROR_HANDLER_SERVICE_GENERATED (5-9)
packages/sync/src/generators/generators.ts (1)
  • createGeneratorTask (196-204)
packages/fastify-generators/src/generators/core/fastify-server/fastify-server.generator.ts (1)
  • fastifyServerConfigProvider (72-72)
packages/core-generators/src/generators/node/typescript/typescript.generator.ts (1)
  • typescriptFileProvider (148-149)
packages/fastify-generators/src/generators/core/config-service/index.ts (1)
  • configServiceImportsProvider (3-3)
packages/fastify-generators/src/generators/core/error-handler-service/generated/ts-import-providers.ts (1)
  • errorHandlerServiceImportsProvider (30-33)
packages/fastify-generators/src/generators/core/error-handler-service/index.ts (1)
  • errorHandlerServiceImportsProvider (3-3)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (73-83)
packages/core-generators/src/renderers/typescript/imports/builder.ts (1)
  • tsImportBuilder (74-82)
packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-template-file.ts (4)
packages/core-generators/src/renderers/typescript/extractor-v2/organize-ts-template-imports.ts (2)
  • TsTemplateImportLookupContext (21-38)
  • organizeTsTemplateImports (73-265)
packages/core-generators/src/renderers/typescript/templates/types.ts (2)
  • TsTemplateVariableMap (132-132)
  • TsTemplateFileImportProvider (25-27)
packages/utils/src/maps/map-values-of-map.ts (1)
  • mapValuesOfMap (11-20)
packages/utils/src/maps/key-by.ts (1)
  • mapKeyBy (13-23)
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts (2)
packages/core-generators/src/renderers/typescript/templates/types.ts (3)
  • tsTemplateOutputTemplateMetadataSchema (97-124)
  • TS_TEMPLATE_TYPE (16-16)
  • TsTemplateOutputTemplateMetadata (126-128)
packages/sync/src/templates/extractor/template-file-extractor.ts (1)
  • TemplateFileExtractorFile (17-28)
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (1)
packages/sync/src/templates/extractor-v2/configs/extractor-config.schema.ts (1)
  • TemplateConfig (46-46)
packages/sync/src/templates/extractor-v2/test-utils/mock-context.ts (4)
packages/sync/src/templates/extractor-v2/runner/template-extractor-context.ts (1)
  • TemplateExtractorContext (13-73)
packages/sync/src/tests/logger.test-utils.ts (1)
  • createTestLogger (10-32)
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (1)
  • TemplateExtractorConfigLookup (43-352)
packages/sync/src/templates/extractor-v2/runner/template-extractor-file-container.ts (1)
  • TemplateExtractorFileContainer (10-73)
packages/core-generators/src/renderers/extractor/plugins/template-paths/paths-file.ts (3)
packages/utils/src/paths/posix-join.ts (1)
  • posixJoin (10-12)
packages/sync/src/templates/extractor-v2/constants/directories.ts (1)
  • TEMPLATE_EXTRACTOR_GENERATED_DIRECTORY (1-1)
packages/core-generators/src/renderers/extractor/utils/generated-template-file-names.ts (1)
  • getGeneratedTemplateConstantName (11-16)
packages/sync/src/templates/extractor-v2/runner/template-file-extractor.ts (2)
packages/sync/src/templates/extractor-v2/runner/template-extractor-context.ts (1)
  • TemplateExtractorContext (13-73)
packages/sync/src/templates/extractor-v2/runner/template-extractor-api.ts (1)
  • TemplateExtractorApi (16-107)
🪛 ESLint
packages/core-generators/src/renderers/typescript/templates/types.ts

[error] 10-10: Expected "@baseplate-dev/sync/extractor-v2" to come before "@baseplate-dev/utils".

(perfectionist/sort-imports)


[error] 11-14: Imports "TemplateFileOptions" are only used as type.

(@typescript-eslint/consistent-type-imports)


[error] 11-14: Missed spacing between "@baseplate-dev/sync/extractor-v2" and "#src/renderers/schemas/template-file-options.js".

(perfectionist/sort-imports)


[error] 34-38: There is a TODO that is past due date: 2025-06-10. Rename this to exportedName

(unicorn/expiring-todo-comments)


[error] 130-130: An empty interface declaration allows any non-nullish value, including literals like 0 and "".

  • If that's what you want, disable this lint rule with an inline comment or configure the 'allowInterfaces' rule option.
  • If you want a type meaning "any object", you probably want object instead.
  • If you want a type meaning "any value", you probably want unknown instead.

(@typescript-eslint/no-empty-object-type)

🪛 Biome (1.9.4)
packages/core-generators/src/renderers/typescript/templates/types.ts

[error] 130-130: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: test
  • GitHub Check: Lint
  • GitHub Check: Test E2E
🔇 Additional comments (99)
packages/sync/src/templates/utils/read-template-file-source.ts (1)

33-33: Update confirmed: TODO date reflects latest plan.
The updated TODO comment date (“2025-06-12”) correctly aligns with the migration schedule.

packages/sync/src/templates/metadata/metadata.ts (1)

17-17: Non‐functional comment update
This change only updates the TODO date; there’s no impact on behavior.

packages/fastify-generators/src/generators/core/request-context/request-context.generator.ts (1)

19-19: Align import to consolidated index module
Switching to import from ../logger-service/index.js centralizes exports per the refactoring. Ensure that index.js re‐exports loggerServiceConfigProvider.

packages/core-generators/src/renderers/typescript/import-maps/types.ts (1)

9-10: Document planned rename for clarity
The TODO marks a future rename of name to exportedName, aligning with extractor-v2 naming conventions.

packages/fastify-generators/src/generators/core/fastify-redis/fastify-redis.generator.ts (1)

23-23: Use consolidated config-service index
Importing from ../config-service/index.js centralizes both providers. Confirm that index.js exports configServiceImportsProvider and configServiceProvider.

packages/fastify-generators/src/generators/pothos/pothos-auth/pothos-auth.generator.ts (1)

17-17: Centralize import to core error-handler-service index
Updating the import path to index.js aligns with the barrel-file refactoring. Verify index.js re-exports errorHandlerServiceImportsProvider.

packages/fastify-generators/src/generators/pothos/pothos-scalar/pothos-scalar.generator.ts (1)

17-17: Import path update for errorHandlerServiceImportsProvider
Refactors import to the new centralized index.js export.

packages/fastify-generators/src/generators/auth/auth-context/auth-context.generator.ts (1)

15-15: Standardize errorHandlerServiceImportsProvider import source
Switches to the generated ts-import-providers.js for centralized imports.

packages/fastify-generators/src/generators/bull/fastify-bull-board/fastify-bull-board.generator.ts (1)

23-23: Consolidate errorHandlerServiceImportsProvider import
Updated to import from core/error-handler-service/index.js for consistency.

packages/fastify-generators/src/generators/core/axios/axios.generator.ts (1)

12-12: Update import for errorHandlerServiceConfigProvider
Aligns import path with the new index.js central exporter.

packages/fastify-generators/src/generators/email/fastify-postmark/fastify-postmark.generator.ts (1)

21-21: Refactor config-service imports to index module
Imports both configServiceImportsProvider and configServiceProvider from the consolidated index.js.

packages/fastify-generators/src/generators/bull/bull-mq/bull-mq.generator.ts (1)

13-17: Import path consolidation looks correct – please double-check re-export

The switch to index.js paths should improve modularity, but make sure errorHandlerServiceImportsProvider and loggerServiceImportsProvider are actually re-exported from those indexes – otherwise you’ll get a runtime “export not found” error once compiled.
A quick grep across the repo (or running tsc --noEmit) will surface any missing re-exports.

packages/core-generators/src/generators/metadata/path-roots/path-roots.generator.ts (1)

9-13: Updated extractor-plugin imports look good

The new paths reference the extractor plugin that now owns the TemplatePathRoot type and TEMPLATE_PATHS_METADATA_FILE constant. The change is cohesive with the plugin refactor and should compile cleanly.

packages/fastify-generators/src/generators/core/_composers/fastify-composer.ts (1)

10-12: Index-based service imports improve encapsulation

Moving the Fastify service generators behind index.js barrels reduces deep-path coupling and simplifies future refactors. No further action needed.

Also applies to: 18-18

packages/fastify-generators/src/generators/yoga/yoga-plugin/yoga-plugin.generator.ts (1)

32-37: Provider import paths updated – verify names remain unchanged

The providers are now imported via their package indexes. If any of those indexes renamed or aliased the individual exports, update the local identifiers here to match; otherwise compilation will fail late in the build. A quick ts-node -O '{\"module\":\"esnext\"}' --swc ./scripts/verify-imports.ts or a plain tsc --noEmit in CI would catch it.

packages/fastify-generators/src/generators/core/fastify-graceful-shutdown/fastify-graceful-shutdown.generator.ts (1)

8-11: Import moved from maps to providers – ensure the file exists

The path now targets generated/ts-import-providers.js. Confirm that the generator which produces this file was renamed accordingly in all places; otherwise this reference will break at runtime or during code-gen.

packages/core-generators/src/utils/index.ts (1)

2-2: Re-export new TS path normalization utility
Adding the ts-paths.js barrel export aligns with the existing exports and centralizes path normalization logic.

packages/sync/src/templates/extractor-v2/constants/index.ts (1)

1-1: Expose directory constants via barrel export
Re-exporting from ./directories.js enables consumers to import directory names alongside the other constants in a single entry point.

packages/sync/src/utils/parse-generator-name.ts (1)

8-9: Improve ParsedGeneratorName documentation clarity
The added examples for packageName, generatorPath, and generatorBasename enhance understandability without altering behavior.

Also applies to: 12-13, 16-17

packages/fastify-generators/src/generators/core/fastify-server/fastify-server.generator.ts (1)

29-30: Standardize service imports through index barrels
Switching to ../config-service/index.js and ../logger-service/index.js consolidates imports and reduces coupling to individual generator files.

packages/fastify-generators/src/generators/stripe/fastify-stripe/fastify-stripe.generator.ts (2)

20-21: Centralize config and error-handler service imports
Moving configServiceImportsProvider, configServiceProvider, and errorHandlerServiceImportsProvider to their respective index.js barrels improves consistency and maintainability.


23-23: Consolidate logger service import
Importing loggerServiceImportsProvider from its index barrel aligns this module with the rest of the generator imports.

packages/core-generators/src/generators/node/index.ts (1)

6-6:

Details

✅ Verification successful

Ensure the barrel file re-exports the full public surface

Changing the path from ./ts-utils/ts-utils.generator.js to ./ts-utils/index.js is fine as long as the new barrel keeps re-exporting every symbol that was previously reachable by consumers. Any omission will be a silent breaking change.


🏁 Script executed:

#!/usr/bin/env bash
# List symbols re-exported by the old generator file vs the new barrel.
rg --no-heading -n $'export .*' packages/core-generators/src/generators/node/ts-utils/ts-utils.generator.ts
rg --no-heading -n $'export .*' packages/core-generators/src/generators/node/ts-utils/index.ts

Length of output: 463


Barrel File Correctly Re-exports All Symbols

The comparison shows that the new index.ts barrel exports every symbol from the old generator plus additional imports providers, so no public API is lost:

• Old exports in ts-utils.generator.ts
export const tsUtilsGenerator = createGenerator({...})

• New barrel in ts-utils/index.ts

  1. export type { TsUtilsImportsProvider } from './generated/ts-import-providers.js';
  2. export { tsUtilsImportsProvider } from './generated/ts-import-providers.js';
  3. export * from './ts-utils.generator.js'; (includes tsUtilsGenerator)

All previously reachable symbols remain available.

packages/fastify-generators/src/generators/core/fastify-sentry/fastify-sentry.generator.ts (1)

25-32: Import path convergence looks good

Importing from the neighbouring index.js barrels simplifies path maintenance and avoids deep relative imports. Nice cleanup – no issues spotted.

packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.unit.test.ts (1)

573-575: 👍 Correct metadata type enforcement

Using satisfies TsTemplateOutputTemplateMetadata guarantees compile-time safety after the schema change. Looks solid.

packages/react-generators/src/generators/apollo/react-apollo/react-apollo.generator.ts (2)

4-5: Updated metadata import aligns with extractor-v2

Switching to TsTemplateOutputTemplateMetadata is required after the schema overhaul. Good catch.


573-575: Singleton file option makes sense for generated artefact

Marking the pseudo-file as a singleton prevents accidental duplicates during extraction. No concerns.

packages/core-generators/src/renderers/index.ts (1)

1-1: Potential breaking change: templates exports removed

Replacing the public export from ./templates/index.js with ./extractor/index.js will break downstream consumers importing template helpers directly from @baseplate-dev/core-generators/renderers.

Please double-check usage across the monorepo (and external docs) or keep the old path as a re-export to avoid a major version bump.

packages/sync/src/templates/extractor-v2/runner/template-extractor-api.ts (3)

8-11: Centralize directory constants for maintainability
The import replaces hardcoded strings with TEMPLATE_EXTRACTOR_TEMPLATES_DIRECTORY and TEMPLATE_EXTRACTOR_GENERATED_DIRECTORY. Ensure that the path (../constants/directories.js) is correct and that these constants are re-exported if needed elsewhere.


78-84: Use constant for templates directory in writeTemplateFile
This replaces the literal 'templates' segment with TEMPLATE_EXTRACTOR_TEMPLATES_DIRECTORY. Verify that generatorTemplatePath is strictly a relative path (without leading directory segments) to avoid double inclusion.


100-106: Use constant for generated directory in writeGeneratedFile
The 'generated' segment is now driven by TEMPLATE_EXTRACTOR_GENERATED_DIRECTORY. Confirm that relativePath does not already contain that segment, preventing malformed file paths.

packages/sync/src/templates/extractor-v2/runner/initialize-template-extractor-plugins.unit.test.ts (1)

17-20: Sync mock context with updated constructor signature
The test helper now correctly instantiates TemplateExtractorConfigLookup with both packageMap and fileIdMap. Ensure no other tests or code paths remain using the old single-argument constructor.

packages/core-generators/src/renderers/typescript/extractor-v2/index.ts (1)

1-2: Add re-export for extractor-v2 TypeScript modules
Good consolidation of the new renderers under a single entry point. Confirm that the package’s exports field in package.json includes the "./extractor-v2" subpath to make these available to consumers.

packages/sync/src/templates/extractor-v2/index.ts (1)

1-3: Expose constants through public API
Re-exporting ./constants/index.js makes the directory constants accessible downstream. Validate that constants/index.js exports all intended values (e.g., TEMPLATE_EXTRACTOR_TEMPLATES_DIRECTORY, TEMPLATE_EXTRACTOR_GENERATED_DIRECTORY).

packages/fastify-generators/src/generators/core/index.ts (2)

5-6: Switch to index entry for config and error-handler services
Updating these exports to point at their index.js entry points keeps paths consistent. Verify that both config-service/index.js and error-handler-service/index.js correctly export their generators.


15-15: Switch to index entry for logger service
Similarly, ensure logger-service/index.js exposes the expected generator and matches the structure used elsewhere.

packages/core-generators/src/renderers/extractor/plugins/index.ts (1)

1-5: Barrel index is clean and idiomatic
Re-exporting from a single entry-point simplifies downstream import paths. No issues spotted.

packages/core-generators/src/renderers/extractor/utils/package-path-specifier.ts (1)

40-44: Reuse the new normalizeTsPathToJsPath helper instead of duplicating the regex

The same extension-stripping logic now lives in utils/ts-paths.ts. Re-using it avoids divergent behaviour and makes future changes (e.g. .mts / .cts support) one-liner.

-import { normalizeTsPathToJsPath } from '../../../utils/ts-paths.js';
 ...
-    return `#${parsed.filePath.replace(/\.(t|j)sx?$/, '.js')}`;
+    return `#${normalizeTsPathToJsPath(parsed.filePath)}`;

[ suggest_essential_refactor ]

packages/core-generators/src/renderers/typescript/extractor/extract-ts-template-variables.ts (1)

16-19: Type alias update looks correct

Switching to TsTemplateFileVariable aligns with the new metadata model; no functional concerns.

packages/sync/src/templates/extractor-v2/constants/directories.ts (1)

1-2: Constants for directory names look good
Centralizing these string literals improves maintainability and consistency across modules.

packages/fastify-generators/src/generators/core/error-handler-service/index.ts (1)

1-3: Re-export structure is clear and consistent
Consolidating exports in this index file simplifies imports for consumers.

packages/sync/package.json (1)

26-30: Expose new extractor-v2 test-utils export
The added ./extractor-v2/test-utils entry correctly points to the built declarations and JS. This aligns with the new utilities and ensures they're consumable externally.

packages/fastify-generators/src/generators/core/fastify-scripts/fastify-scripts.generator.ts (4)

1-5: Update imports to centralized core-generators package
Importing renderRawTemplateFileAction from @baseplate-dev/core-generators and consolidating provider imports here aligns with the refactoring pattern.


13-14: Use unified generated index for fastify-scripts
Switching to CORE_FASTIFY_SCRIPTS_GENERATED replaces two separate import sources and improves maintainability.


29-35: Reference generated paths in buildTasks
Updating paths dependency and initial paths field to use the generated paths.task and paths.provider is correct and consistent with other generators.


58-61: Render raw template using generated templates
Utilizing CORE_FASTIFY_SCRIPTS_GENERATED.templates.tsconfig for the template source ensures template consistency.

packages/core-generators/package.json (1)

26-30: Expose extractor-v2 subpath in core-generators
Adding the ./extractor-v2 export correctly points to the new TypeScript v2 extractor artifacts, enabling external consumers to import them.

packages/core-generators/src/renderers/typescript/extractor-v2/get-resolver-factory.ts (1)

15-22:

Details

❌ Incorrect review comment

Extension aliases reference extensions that are not in the allowed‐extensions list

extensionAlias maps .cjs → .cts / .mjs → .mts, yet neither .cts nor .mts appear in the extensions array (line 15).
If the underlying resolver respects the extensions whitelist when traversing aliases, any import ending up with .cts / .mts will fail to resolve.

-    extensions: ['.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json', '.node'],
+    extensions: [
+      '.ts',
+      '.tsx',
+      '.d.ts',
+      '.js',
+      '.jsx',
+      '.json',
+      '.node',
+      '.cts',
+      '.mts',
+    ],

Alternatively, remove the alias entries if they are not needed.
Please verify against oxc-resolver behaviour and add a regression test.


🏁 Script executed:

#!/bin/bash
set -e
# Locate the get-resolver-factory.ts file
file=$(fd --full-path 'get-resolver-factory.ts' -c ts -0 | head -n1)
echo "Found file: $file"
# Print the relevant section around extensions & extensionAlias
sed -n '1,200p' "$file"

Length of output: 306


🏁 Script executed:

#!/bin/bash
set -e
# Search for extensionAlias and extensions definitions in TypeScript files
rg -n "extensionAlias" -A5 -C2 --type ts
rg -n "extensions:" -A8 -C2 --type ts

Length of output: 5413


🏁 Script executed:

#!/bin/bash
set -e
file="packages/core-generators/src/renderers/typescript/extractor-v2/get-resolver-factory.ts"
echo "Showing extensionAlias block for verification:"
rg -n "extensionAlias" -A20 -C2 "$file"

Length of output: 564


Ignore outdated extensionAlias concern
The extensionAlias block in
packages/core-generators/src/renderers/typescript/extractor-v2/get-resolver-factory.ts
only contains mappings for .js and .jsx, and there are no .cjs or .mjs entries. The missing .cts/.mts issue does not apply to the current code. No changes required.

Likely an incorrect or invalid review comment.

packages/fastify-generators/src/generators/core/config-service/extractor.json (1)

1-16: Looks good – schema aligns with v2 extractor expectations

The singleton template definition is consistent and no issues are apparent.

packages/fastify-generators/src/generators/core/logger-service/extractor.json (1)

1-16: Configuration JSON is valid and follows the new structure

No functional concerns.

packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts (1)

11-12: Ensure TsTemplateOutputTemplateMetadata really contains projectExports

The implementation relies on file.metadata.projectExports further down. If the new metadata type omits or renames that property, the call-site compiles (because it’s accessed through any/unknown) but blows up at runtime.
Please double-check that tsTemplateOutputTemplateMetadataSchema exposes the same shape as before.

packages/fastify-generators/src/generators/core/logger-service/index.ts (1)

1-3: Re-export wrapper looks good

Path names and ordering are consistent with the other generators introduced in this PR.

packages/core-generators/src/renderers/raw/render-raw-template-action.ts (1)

20-24: Edge-case: id is always in scope but may be undefined

id is destructured unconditionally, yet absent for singleton templates.
The subsequent check guards against missing id for instance kinds, so behaviour is fine.
Just ensure no downstream code assumes id is a string for the singleton branch.

packages/sync/src/templates/extractor-v2/utils/write-extractor-template-jsons.ts (1)

25-31: Confirm fileContainer.writeFile is synchronous or await the promise

writeExtractorTemplateJsons is declared void and does not await the writeFile call.
If writeFile returns a promise (common in async FS abstractions) errors could be lost or the caller could exit before writes finish.

-    context.fileContainer.writeFile(
+    await context.fileContainer.writeFile(

Update the function signature to async if necessary.

packages/fastify-generators/src/generators/core/config-service/index.ts (1)

1-3: Consistent export surface

Matches the pattern used for logger-service; promotes discoverability.

packages/core-generators/src/generators/node/ts-utils/index.ts (1)

1-3: Barrel file is clean – nothing to change
Single-point re-exports are concise and correctly typed.

packages/sync/src/templates/extractor-v2/test-utils/index.ts (1)

1-18: All good – barrel improves DX
The centralised re-export keeps test helpers discoverable and avoids deep import paths.

packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.unit.test.ts (1)

94-95: Missing await may swallow asynchronous errors

If mergeExtractorTemplateEntries becomes or already is async, these invocations drop the resulting promise and the test will pass even when the merge fails.
Safer pattern:

-await mergeExtractorTemplateEntries(metadataEntries, context);
+await mergeExtractorTemplateEntries(metadataEntries, context);

Confirm the function’s signature; adjust accordingly.

Also applies to: 180-181, 237-238, 287-288, 345-346, 491-492

packages/core-generators/src/renderers/text/utils.ts (1)

65-83: extractTemplateVariables – edge-cases worth guarding

  1. Throwing when a variable value is not found is great for early failure, but it means a single optional variable breaks the whole extraction. Consider a non-throwing mode or a flag if optional variables are expected.
  2. The loop recreates a RegExp for every variable. For large variable sets this is fine, but if performance ever matters, pre-compiling could help.
  3. For .gql files both delimiters are ''; the replacement becomes ${key} without any fence. That’s intentional, but double-check consumers expect the naked key.

No action required if these behaviours are intentional; just flagging them.

packages/sync/src/templates/extractor-v2/runner/template-extractor-plugin.ts (1)

25-32: Docs & type additions look solid

The hook descriptions and the new TemplateExtractorPluginInstance utility type are clear and improve DX.

packages/core-generators/src/renderers/typescript/extractor-v2/default-import-providers.ts (1)

36-43: Potential circular import with @baseplate-dev/sync

default-import-providers.ts lives inside core-generators but imports parseGeneratorName from @baseplate-dev/sync, which in turn depends on core-generators in several places. Ensure the build graph doesn’t introduce a circular dependency (ESM cycles can break TS emit & Jest mocks).

If detected, consider extracting parseGeneratorName into a shared utility package.

packages/core-generators/src/generators/node/ts-utils/extractor.json (1)

10-12: Verify special key notEmpty in projectExports

"projectExports": { "notEmpty": {} } is not a conventional export map entry (all other entries map an identifier to an options object).
If notEmpty is a sentinel for “this file must export something”, ensure the extractor knows about it; otherwise consumers trying to import notEmpty will fail.

packages/core-generators/src/renderers/typescript/extractor-v2/organize-ts-template-imports.unit.test.ts (1)

122-136: Test assumes default export can be merged into named import

import F from './default-module.ts'; … expect(result).toContain('import { A, B, F } from "%testImports"')

Bundling a default export into a named list is only valid if export { default as F } exists in the provider.
Ensure the organiser rewrites the default export accordingly; otherwise the generated code will not type-check.

packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts (1)

84-86: imports task appears unused inside this generator

CORE_CONFIG_SERVICE_GENERATED.imports.task is registered but never consumed in
dependencies.
If no other build task relies on it, consider dropping the task to keep the
pipeline minimal.

Double-check before removal in case external generators depend on the side-effects.

packages/sync/src/templates/extractor-v2/utils/group-template-files-by-type.ts (1)

26-33: Avoid JSON.stringify for dedupe key – cheaper & clearer string concat works

uniqBy only needs a unique primitive key. Serialising an object on every iteration produces unnecessary allocations.

-const uniqueTemplateFiles = uniqBy(files, (f) =>
-  JSON.stringify({
-    g: f.metadata.generator,
-    t: f.metadata.name,
-  }),
-);
+const uniqueTemplateFiles = uniqBy(
+  files,
+  (f) => `${f.metadata.generator}:${f.metadata.name}`,
+);

[ suggest_optional_refactor ]

packages/core-generators/src/renderers/text/utils.unit.test.ts (1)

86-96: Expected CSS replacement string looks suspicious

'./* className */ { color: red; }' keeps the leading dot but removes the class name entirely.
Should it be './* className */ { … }' (dot + delimiter) or '/* className */ { … }' (no dot)?
Please verify the intended delimiter semantics.

packages/core-generators/src/renderers/raw/types.ts (1)

47-51: LGTM! Good improvement to type safety.

The addition of generic type parameters to RawTemplateFile and createRawTemplateFile enhances type safety while maintaining backward compatibility through the default type parameter.

Also applies to: 56-58

packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (1)

134-139: Good validation for instance templates.

The validation ensuring instance templates have an ID is a good defensive programming practice that will prevent runtime errors.

packages/project-builder-server/src/sync/file-id-map.ts (1)

1-58: Well-implemented file ID map management.

The implementation demonstrates good practices:

  • Comprehensive error handling with context
  • Type-safe schema validation
  • Graceful handling of missing files
  • Deterministic output through sorting
packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-template-file.ts (1)

17-61: Clean implementation of template rendering.

The function properly handles:

  • Variable extraction and import organization
  • Shebang preservation for executable scripts
  • Addition of @ts-nocheck to prevent type errors in generated code
packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.unit.test.ts (3)

17-21: LGTM! Good test data structure.

The mock file ID map follows a clear naming convention (package#extractor:file -> id) that makes the test cases easy to understand.


432-551: Comprehensive test coverage for the new method.

The test suite for updateExtractorTemplateConfig covers all the important scenarios:

  • Successfully updating an existing template
  • Error handling when template doesn't exist
  • Error handling when generator doesn't exist

Good job on the thorough test coverage!


553-589: Clear and focused tests for file ID lookup.

The tests for getOutputRelativePathForTemplate effectively verify the lookup functionality with both existing and non-existent templates.

packages/fastify-generators/src/generators/core/error-handler-service/extractor.json (1)

1-67: Well-structured extractor configuration.

The configuration properly defines all required metadata for the error handling templates. The import provider references are correctly specified using package path specifiers.

Note: All template fields are empty strings (lines 8, 23, 39, 58). Ensure this is intentional and that the template content is managed elsewhere.

packages/sync/src/templates/extractor-v2/run-template-file-extractors.ts (3)

145-146: Good architectural improvement separating merge from write operations.

The refactoring to separate mergeExtractorTemplateEntries (in-memory operation) from writeExtractorTemplateJsons (file I/O) improves the code structure and allows for better error handling and transactional behavior.

Also applies to: 168-171


133-139: Good use of API pattern for extractor interface.

Creating TemplateExtractorApi instances provides a clean, controlled interface for extractors to interact with the system.


93-97:

Details

✅ Verification successful

Verify hook execution order aligns with plugin dependencies.

The hooks are now executed in reverse order. This typically makes sense for cleanup/finalization hooks where dependencies should be processed in reverse order.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the reverse hook execution order is documented and used consistently

# Search for documentation about hook execution order
rg -A 5 "hook.*reverse|reverse.*order" --type ts

# Look for other hook executions to ensure consistency
ast-grep --pattern 'for (const $_ of $_.toReversed()) {
  $$$
}'

Length of output: 3928


Hook execution order is correct and consistent

The runHooks implementation uses toReversed() as documented in
sync/src/templates/extractor-v2/runner/template-extractor-plugin.ts (“Hooks are executed in reverse dependency order…”).
This matches other usages (e.g., toposort-local tests, React wrapper application) and requires no changes.

packages/core-generators/src/renderers/text/text-template-file-extractor.ts (2)

29-60: Excellent error handling improvements.

The addition of try-catch blocks with detailed error messages including the file path and original error cause will greatly improve debugging when template extraction fails.


70-74:

Details

✅ Verification successful

Clean refactoring using the variable extraction utility.

The use of extractTemplateVariables utility simplifies the code and centralizes the variable extraction logic.


🏁 Script executed:

#!/bin/bash
# Description: Verify the extractTemplateVariables utility implementation and its test coverage

# Check the utility implementation
rg -A 10 "export.*extractTemplateVariables" packages/core-generators/src/renderers/text/utils.ts

# Check test coverage for the utility
fd "utils.*test" packages/core-generators/src/renderers/text/ --exec cat {}

Length of output: 5405


extractTemplateVariables utility is well-covered and ready to ship

All edge cases—including empty variables, file-specific delimiters, overlapping values, word boundaries, and missing-value errors—are thoroughly tested in packages/core-generators/src/renderers/text/utils.test.ts. No further changes needed.

packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts (1)

24-24: Consistent metadata type refactoring.

The replacement of TsTemplateFileMetadata with TsTemplateOutputTemplateMetadata is applied consistently throughout the file. The new type name better reflects its purpose as output template metadata.

Also applies to: 105-108

packages/core-generators/src/renderers/typescript/extractor-v2/build-ts-project-export-map.ts (1)

1-124: LGTM!

The implementation is well-structured with proper handling of edge cases. The function correctly:

  • Filters for singleton templates only
  • Skips templates without output paths
  • Builds a comprehensive export map with all necessary metadata
packages/core-generators/src/renderers/typescript/extractor-v2/ts-template-file-extractor.ts (1)

31-183: Well-structured template extractor implementation

The extractor is well-designed with:

  • Proper plugin dependencies management
  • Good error handling with contextual information
  • Efficient concurrent processing with limits
  • Clean separation of concerns between metadata extraction, file writing, and generated files
packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (1)

17-21: Clean refactoring to use generated imports and paths

The refactoring successfully replaces all hardcoded imports and paths with references to the centralized CORE_ERROR_HANDLER_SERVICE_GENERATED object. This improves maintainability and consistency across the codebase.

Also applies to: 46-47, 54-54, 61-61, 66-68, 82-84, 102-102, 108-108, 115-116, 137-137, 139-139, 143-146

packages/core-generators/src/renderers/typescript/extractor-v2/render-ts-typed-templates.ts (2)

97-120: Well-structured template rendering logic

The function cleanly separates grouped and ungrouped templates, processes them appropriately, and returns a combined result. Good use of functional programming patterns.


32-32:

Details

✅ Verification successful

Verify ES2020+ compatibility for import.meta.dirname

The code uses import.meta.dirname which is an ES2020+ feature. Ensure that the target Node.js version and build configuration support this feature.

Run the following script to check the minimum Node.js version requirement:


🏁 Script executed:

#!/bin/bash
# Description: Check for Node.js version requirements and import.meta usage

# Check package.json for engine requirements
fd -e json -x grep -l "engines" {} \; | xargs grep -A2 "engines" | grep -E "node|npm"

# Check for other import.meta usage in the codebase
rg "import\.meta\." -A 2

Length of output: 64956


import.meta.dirname is supported by our Node.js target (>=22.0.0)

All packages specify "node": "^22.0.0" in their engines field, and import.meta.dirname is fully supported in Node.js 22+. No changes needed.

packages/sync/src/templates/extractor-v2/test-utils/plugin-test-utils.ts (1)

12-43: Well-implemented mock plugin API

The mock API correctly handles hook registration and sequential execution. Good design for testing plugin behavior.

packages/core-generators/src/renderers/extractor/plugins/template-paths/paths-file.ts (2)

24-84: Good refactoring of path constants and export names

The centralization of the generated paths file name and the addition of rootExportName to the interface improves consistency and maintainability.


207-257: Proper integration with barrel export system

The function now correctly returns the export name for barrel export registration and uses centralized path constants.

packages/sync/src/templates/extractor-v2/runner/template-file-extractor.ts (2)

35-60: LGTM! Well-designed extraction context enhancement.

The addition of the generic TExtractionContext parameter with a default of unknown is a clean way to allow extractors to pass temporary context data between extraction and writing phases without persisting it to extractor.json. The optional extractionContext property maintains backward compatibility.


132-139: Good addition of async support for writeTemplateFiles.

Allowing both synchronous and asynchronous return types provides flexibility for implementations that may need to perform async operations during template file writing.

packages/sync/src/templates/extractor-v2/configs/template-extractor-config-lookup.ts (2)

55-58: LGTM! Clean dependency injection for fileIdMap.

The addition of fileIdMap to the constructor enables tracking of file IDs across extraction runs, which is essential for maintaining stable references to generated files.


212-254: Well-implemented template type filtering and config retrieval.

The getGeneratorConfigsForExtractorType method provides a flexible way to query generator configurations by template type with proper schema validation. The optional generator config schema handling and the structured return type make this a robust addition.

packages/core-generators/src/renderers/extractor/plugins/barrel-export.ts (2)

22-121: Excellent implementation of barrel export merging.

The mergeBarrelExports function handles the complexity of merging barrel exports well:

  • Properly groups exports by module and type
  • Handles star exports with correct precedence
  • Maintains consistent sorting for deterministic output
  • Separates type-only and regular exports appropriately

204-315: Well-structured barrel export plugin implementation.

The plugin correctly:

  • Accumulates exports during the extraction process
  • Processes them in the afterWrite hook
  • Handles both regular and generated barrel exports
  • Ensures the generator file is always exported with the wildcard export

The separation of concerns between regular and generated barrel exports is clean and maintainable.

packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts (1)

20-20: Good refactoring to use centralized generated modules!

The consolidation of imports, paths, and templates into CORE_LOGGER_SERVICE_GENERATED improves maintainability and follows the consistent pattern established across other core generators. The functionality remains intact while reducing duplication.

Also applies to: 50-51, 54-54, 58-58, 79-79, 86-86

packages/core-generators/src/renderers/extractor/plugins/template-paths/template-paths.plugin.ts (4)

34-38: LGTM! Clean utility function.

The getPathsRootExportName function properly encapsulates the logic for retrieving the root export name from the paths file export names.


89-125: Excellent addition for centralizing template path resolution!

The resolveTemplatePaths function properly encapsulates the path resolution logic with clear error handling. The distinction between singleton and non-singleton templates is well-handled, and the error message provides useful context for debugging.


127-140: Well-integrated with the new barrel export system!

The afterWrite hook properly registers generated path files with the barrel export plugin. Good use of normalizeTsPathToJsPath to ensure consistent path formats.


196-206: Good improvement to error handling!

Throwing an explicit error when no template path root is found is better than silent failure. This will help catch configuration issues early and make debugging easier.


import { FASTIFY_PACKAGES } from '#src/constants/fastify-packages.js';
import { configServiceProvider } from '#src/generators/core/config-service/config-service.generator.js';
import { configServiceProvider } from '#src/generators/core/config-service/index.js';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Validate updated import path for configServiceProvider.

The import path now points to index.js instead of the original generator file. Please ensure that:

  1. packages/fastify-generators/src/generators/core/config-service/index.js indeed exports configServiceProvider.
  2. Your TypeScript and Node resolution settings support importing .js modules from TS source.

🏁 Script executed:

#!/bin/bash
# Verify that configServiceProvider is exported from the new index file
fd index.js packages/fastify-generators/src/generators/core/config-service/ | \
  xargs grep -R "export.*configServiceProvider"

Length of output: 250


Ensure configServiceProvider Is Re-exported from index.js

The search shows configServiceProvider is only exported in
packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts
and not re-exported in index.js, so the import from index.js will fail at runtime.

To fix:

  • In packages/fastify-generators/src/generators/core/config-service/index.js, add:
    export { configServiceProvider } from './config-service.generator.js';
  • Or change the import to point directly at the generator file:
    import { configServiceProvider }
      from '#src/generators/core/config-service/config-service.generator';
  • Also confirm your tsconfig.json and Node resolution settings (allowJs, moduleResolution: "node") support importing .js modules from TS sources.
🤖 Prompt for AI Agents
In packages/fastify-generators/src/generators/prisma/prisma/prisma.generator.ts
at line 33, the import of configServiceProvider from index.js will fail because
index.js does not re-export it. Fix this by either adding an export statement
for configServiceProvider in
packages/fastify-generators/src/generators/core/config-service/index.js that
re-exports it from config-service.generator.js, or change the import in
prisma.generator.ts to directly import from config-service.generator.ts. Also
verify that your tsconfig.json and Node resolution settings support importing
.js modules from TypeScript sources.

Comment on lines 5 to 7
z.object({
kind: z.literal('singleton'),
kind: z.literal('singleton').optional().default('singleton'),
/**
Copy link

@coderabbitai coderabbitai bot Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

discriminatedUnion requires the discriminator to be present – making kind optional will break validation

Zod’s discriminatedUnion('kind', …) demands that the kind property exist in the raw input so it can pick the proper branch.
Marking it .optional().default('singleton') means:

  1. Input objects that omit kind now fail the discriminator check before defaults are applied.
  2. Objects with kind: undefined are indistinguishable from the second variant and will also fail.

The previous mandatory literal was correct; keep kind required and rely on the .default({ kind: 'singleton' }) at the union level.

-      kind: z.literal('singleton').optional().default('singleton'),
+      kind: z.literal('singleton'),

Please add/adjust a unit test that parses an object {} and expects it to succeed due to the union-level default, ensuring future refactors don’t regress this behaviour.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
z.object({
kind: z.literal('singleton'),
kind: z.literal('singleton').optional().default('singleton'),
/**
z.object({
kind: z.literal('singleton'),
/**
🤖 Prompt for AI Agents
In packages/core-generators/src/renderers/schemas/template-file-options.ts
around lines 5 to 7, the 'kind' property is incorrectly marked as optional with
a default, which breaks Zod's discriminatedUnion validation that requires 'kind'
to be present in the input. Change 'kind' to be a required literal without
'.optional().default()' and instead apply the default at the union schema level.
Additionally, add or update a unit test to parse an empty object '{}' and assert
that it succeeds by using the union-level default, preventing future
regressions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually not necessary. Allows fileOptions to be set to {}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingston Got it — I understand you’d like callers to be able to pass an empty object ({}) for fileOptions.

Just a heads-up: with Zod’s current implementation, making the discriminant optional does not actually achieve that.
z.discriminatedUnion('kind', …) looks at the raw input before any defaults are applied. If the kind key is missing (as in {}), discriminatedUnion can’t decide which branch to use and the parse fails.

Quick check:

import { z } from 'zod';

const schemaRequired = z.discriminatedUnion('kind', [
  z.object({ kind: z.literal('singleton') }),
  z.object({ kind: z.literal('instance') }),
]);

const schemaOptional = z.discriminatedUnion('kind', [
  z.object({ kind: z.literal('singleton').optional().default('singleton') }),
  z.object({ kind: z.literal('instance') }),
]);

schemaRequired.parse({ kind: 'singleton' }); // ✅
schemaRequired.parse({});                    // ❌  Error: "Invalid discriminator value. Expected 'singleton' | 'instance'"

schemaOptional.parse({ kind: 'singleton' }); // ✅
schemaOptional.parse({});                    // ❌  same error

(The optional/default on the field is ignored during the discriminator check.)

To allow fileOptions = {} you’ll need a different approach, e.g.:

  1. Wrap the discriminated union in a .default({ kind: 'singleton' }) and make the whole field optional at the call site, or
  2. Use a regular union + custom refine, or
  3. Accept {} via .partial() and coerce afterwards.

Happy to adjust if you’d like to explore one of these, otherwise I’ll leave the current change as-is. Let me know!

Comment on lines +9 to +12
const TSX_VARIABLE_REGEX =
/\{\/\* TPL_([A-Z0-9_]+):START \*\/\}([\s\S]*?)\{\/\* TPL_\1:END \*\/\}/g;
const COMMENT_VARIABLE_REGEX =
/\/\* TPL_([A-Z0-9_]+):COMMENT:START \*\/([\s\S]*?)\/\* TPL_\1:COMMENT:END \*\//g;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

TSX variable regex too strict – fails with whitespace/newlines
Prettier frequently emits { /* TPL_FOO:START */ }, with spaces/newlines between the brace and the comment. The current pattern requires them to be adjacent, so such variables are silently skipped.

-const TSX_VARIABLE_REGEX =
-  /\{\/\* TPL_([A-Z0-9_]+):START \*\/\}([\s\S]*?)\{\/\* TPL_\1:END \*\/\}/g;
+const TSX_VARIABLE_REGEX =
+  /\{\s*\/\*\s*TPL_([A-Z0-9_]+):START\s*\*\/\s*\}([\s\S]*?)\{\s*\/\*\s*TPL_\1:END\s*\*\/\s*\}/g;

This loosens the pattern while keeping it anchored to the same variable name.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const TSX_VARIABLE_REGEX =
/\{\/\* TPL_([A-Z0-9_]+):START \*\/\}([\s\S]*?)\{\/\* TPL_\1:END \*\/\}/g;
const COMMENT_VARIABLE_REGEX =
/\/\* TPL_([A-Z0-9_]+):COMMENT:START \*\/([\s\S]*?)\/\* TPL_\1:COMMENT:END \*\//g;
const TSX_VARIABLE_REGEX =
/\{\s*\/\*\s*TPL_([A-Z0-9_]+):START\s*\*\/\s*\}([\s\S]*?)\{\s*\/\*\s*TPL_\1:END\s*\*\/\s*\}/g;
const COMMENT_VARIABLE_REGEX =
/\/\* TPL_([A-Z0-9_]+):COMMENT:START \*\/([\s\S]*?)\/\* TPL_\1:COMMENT:END \*\//g;
🤖 Prompt for AI Agents
In
packages/core-generators/src/renderers/typescript/extractor-v2/extract-ts-template-variables.ts
around lines 9 to 12, the TSX_VARIABLE_REGEX is too strict because it requires
the comment to be immediately adjacent to the braces, causing it to miss matches
when there are spaces or newlines. Modify the regex to allow optional whitespace
characters between the braces and the comment markers while still anchoring to
the same variable name, so it correctly matches patterns like `{ /*
TPL_FOO:START */ }` with spaces or newlines.

Comment on lines +22 to 23
const mockFileIdMap = new Map<string, string>([]);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Instantiate a fresh Map per test to avoid state bleed-through

mockFileIdMap is declared once and then passed into every new TemplateExtractorConfigLookup.
If TemplateExtractorConfigLookup mutates the supplied map (very likely, given the “ID map” semantics), test cases may influence one another. Create a new map inside each test or in beforeEach instead:

-const mockFileIdMap = new Map<string, string>([]);
+let mockFileIdMap: Map<string, string>;
+
+beforeEach(() => {
+  mockFileIdMap = new Map<string, string>();
+  vol.reset();
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const mockFileIdMap = new Map<string, string>([]);
// replace the single, shared const with a fresh map per test
- const mockFileIdMap = new Map<string, string>([]);
+ let mockFileIdMap: Map<string, string>;
+
+ beforeEach(() => {
+ mockFileIdMap = new Map<string, string>();
+ vol.reset();
+ });
🤖 Prompt for AI Agents
In
packages/sync/src/templates/extractor-v2/utils/merge-extractor-template-entries.unit.test.ts
around lines 22 to 23, the mockFileIdMap is declared once and shared across
tests, which risks state bleed-through if mutated. To fix this, move the
instantiation of mockFileIdMap inside each test or into a beforeEach hook so
that each test gets a fresh Map instance, preventing tests from affecting each
other's state.

Comment on lines +23 to +29
const startMarkerRegex = /(\w+)\s*(\/\* (TPL_[A-Z0-9_]+):START \*\/)\s*\(/g;
transformedCode = transformedCode.replaceAll(
startMarkerRegex,
(match, identifier, startMarkerComment) =>
// Replace with: identifier, opening parenthesis, the START comment
`${identifier}(${startMarkerComment}`,
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Regex too strict – breaks on member or generic calls

startMarkerRegex only matches an identifier made of \w+.
Cases like obj.method /* … */( or factory<MyType> /* … */( will be missed, causing incomplete preprocessing and extraction errors.

A slightly more permissive pattern fixes this:

-const startMarkerRegex = /(\w+)\s*(\/\* (TPL_[A-Z0-9_]+):START \*\/)\s*\(/g;
+const startMarkerRegex = /([\w.$<>]+)\s*(\/\* (TPL_[A-Z0-9_]+):START \*\/)\s*\(/g;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const startMarkerRegex = /(\w+)\s*(\/\* (TPL_[A-Z0-9_]+):START \*\/)\s*\(/g;
transformedCode = transformedCode.replaceAll(
startMarkerRegex,
(match, identifier, startMarkerComment) =>
// Replace with: identifier, opening parenthesis, the START comment
`${identifier}(${startMarkerComment}`,
);
const startMarkerRegex = /([\w.$<>]+)\s*(\/\* (TPL_[A-Z0-9_]+):START \*\/)\s*\(/g;
transformedCode = transformedCode.replaceAll(
startMarkerRegex,
(match, identifier, startMarkerComment) =>
// Replace with: identifier, opening parenthesis, the START comment
`${identifier}(${startMarkerComment}`,
);
🤖 Prompt for AI Agents
In
packages/core-generators/src/renderers/typescript/extractor-v2/preprocess-code-for-extraction-hack.ts
around lines 23 to 29, the regex startMarkerRegex is too restrictive by only
matching simple word characters (\w+) as identifiers, which fails on member
accesses like obj.method or generic calls like factory<MyType>. Update the regex
to allow more complex identifiers including dots and angle brackets so it
matches these cases, ensuring the preprocessing correctly captures all relevant
patterns.

Comment on lines +102 to +106
barrelExportPlugin.addGeneratedBarrelExport(generatorName, {
moduleSpecifier: `./${normalizeTsPathToJsPath(TYPED_TEMPLATES_FILE_NAME)}`,
namedExport: exportName,
name: 'templates',
});
Copy link

@coderabbitai coderabbitai bot Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Barrel export path is wrong – generated file lives in a sub-directory

TYPED_TEMPLATES_FILE_PATH resolves to generated/typed-templates.ts, but the barrel export currently points to ./typed-templates.js.
Consumers will get “module not found” at runtime.

- moduleSpecifier: `./${normalizeTsPathToJsPath(TYPED_TEMPLATES_FILE_NAME)}`,
+ moduleSpecifier: `./${normalizeTsPathToJsPath(
+     TYPED_TEMPLATES_FILE_PATH,
+   )}`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
barrelExportPlugin.addGeneratedBarrelExport(generatorName, {
moduleSpecifier: `./${normalizeTsPathToJsPath(TYPED_TEMPLATES_FILE_NAME)}`,
namedExport: exportName,
name: 'templates',
});
barrelExportPlugin.addGeneratedBarrelExport(generatorName, {
moduleSpecifier: `./${normalizeTsPathToJsPath(
TYPED_TEMPLATES_FILE_PATH,
)}`,
namedExport: exportName,
name: 'templates',
});
🤖 Prompt for AI Agents
In
packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts
around lines 102 to 106, the barrel export path incorrectly points to
'./typed-templates.js' instead of the correct sub-directory path. Update the
moduleSpecifier to use TYPED_TEMPLATES_FILE_PATH (normalized to a JS path) to
reflect the actual location of the generated file, ensuring consumers can
resolve the module at runtime without errors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's accurate since generated barrel export is from the generated directory.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingston Got it—thanks for clarifying.
Because the barrel-export plugin writes into generated/index.ts, the moduleSpecifier indeed needs to be relative to that file, so ./${normalizeTsPathToJsPath(TYPED_TEMPLATES_FILE_NAME)} is the correct value. I’m withdrawing the suggestion. 👍


✏️ Learnings added
Learnt from: kingston
PR: halfdomelabs/baseplate#571
File: packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts:102-106
Timestamp: 2025-06-11T18:31:22.221Z
Learning: For `templateExtractorBarrelExportPlugin.addGeneratedBarrelExport`, the generated barrel exports are written into `generated/index.ts`, therefore the `moduleSpecifier` must be specified relative to that file (e.g., `./typed-templates.js`), not the project root.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines 203 to 205
// Write file ID map
const fileIdMap = Object.fromEntries(
[...fileIdToRelativePathMap.entries()].sort(([a], [b]) =>
a.localeCompare(b),
),
);
await writeJson(path.join(projectDirectory, FILE_ID_MAP_PATH), fileIdMap);
await writeGeneratedFileIdMap(projectDirectory, fileIdToRelativePathMap);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

writeGeneratedFileIdMap bypasses the pluggable operations interface

Every other side-effect is routed through operations to aid testing & overriding, but this one calls the concrete import directly.
Add it to GeneratorOperations (with a sensible default) and invoke via operations.writeGeneratedFileIdMap(...) for consistency.

🤖 Prompt for AI Agents
In packages/project-builder-server/src/sync/generate-for-directory.ts around
lines 203 to 205, the call to writeGeneratedFileIdMap bypasses the pluggable
operations interface used elsewhere. To fix this, add writeGeneratedFileIdMap as
a method to the GeneratorOperations interface with a default implementation,
then replace the direct call with operations.writeGeneratedFileIdMap(...) to
maintain consistency and enable easier testing and overriding.

Comment on lines +113 to 122
const templateMetadata: TsTemplateOutputTemplateMetadata | undefined = {
name: template.name,
template:
'path' in template.source
? template.source.path
? // TODO[2025-06-11]: Remove this once we've migrated all TS templates.
path.isAbsolute(template.source.path)
? ''
: template.source.path
: 'content-only-template',
generator: generatorInfo.name,
Copy link

@coderabbitai coderabbitai bot Jun 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider preserving template identification for absolute paths.

Setting the template path to an empty string for absolute paths (line 119) removes valuable debugging information from the template metadata. Consider using a descriptive identifier like '<absolute-path>' or extracting the filename instead.

         template:
           'path' in template.source
-            ? // TODO[2025-06-11]: Remove this once we've migrated all TS templates.
-              path.isAbsolute(template.source.path)
-              ? ''
-              : template.source.path
+            ? path.isAbsolute(template.source.path)
+              ? `<absolute:${path.basename(template.source.path)}>`
+              : template.source.path
             : 'content-only-template',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const templateMetadata: TsTemplateOutputTemplateMetadata | undefined = {
name: template.name,
template:
'path' in template.source
? template.source.path
? // TODO[2025-06-11]: Remove this once we've migrated all TS templates.
path.isAbsolute(template.source.path)
? ''
: template.source.path
: 'content-only-template',
generator: generatorInfo.name,
const templateMetadata: TsTemplateOutputTemplateMetadata | undefined = {
name: template.name,
template:
'path' in template.source
? path.isAbsolute(template.source.path)
? `<absolute:${path.basename(template.source.path)}>`
: template.source.path
: 'content-only-template',
generator: generatorInfo.name,
// …other fields…
};
🤖 Prompt for AI Agents
In
packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts
between lines 113 and 122, the template path is set to an empty string when it
is an absolute path, which removes useful debugging information. Instead of
setting it to an empty string, update the code to preserve a meaningful
identifier by either using a placeholder like '<absolute-path>' or extracting
and using the filename from the absolute path to retain useful metadata for
debugging.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just temporary while we transition

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingston Got it — since this empty-string placeholder is only a stop-gap during the transition, we’ll leave the current logic untouched for now. When the migration is finished and the metadata format stabilizes, we can revisit this to restore richer template identifiers.

(ʘ curious bunny peers at migrating code ʘ)

>;

export interface TsTemplateVariable {}
export interface TsTemplateFileVariable {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace empty interface with type alias or add documentation.

The empty interface TsTemplateFileVariable is flagged by static analysis. If this is a placeholder for future properties, document it. Otherwise, use a type alias.

Option 1 - Use a type alias:

-export interface TsTemplateFileVariable {}
+export type TsTemplateFileVariable = Record<string, never>;

Option 2 - Document the placeholder:

+/**
+ * Placeholder interface for template file variables.
+ * Currently empty but reserved for future properties.
+ */
 export interface TsTemplateFileVariable {}
🧰 Tools
🪛 Biome (1.9.4)

[error] 130-130: An empty interface is equivalent to {}.

Safe fix: Use a type alias instead.

(lint/suspicious/noEmptyInterface)

🪛 ESLint

[error] 130-130: An empty interface declaration allows any non-nullish value, including literals like 0 and "".

  • If that's what you want, disable this lint rule with an inline comment or configure the 'allowInterfaces' rule option.
  • If you want a type meaning "any object", you probably want object instead.
  • If you want a type meaning "any value", you probably want unknown instead.

(@typescript-eslint/no-empty-object-type)

🤖 Prompt for AI Agents
In packages/core-generators/src/renderers/typescript/templates/types.ts at line
130, the empty interface TsTemplateFileVariable should be replaced with a type
alias if it is not intended to have properties, or add a comment above it
explaining it is a placeholder for future properties. Choose one approach:
either convert the empty interface to a type alias with an empty object type or
add clear documentation to justify the empty interface.

Comment on lines +10 to +14
import { templateConfigSchema } from '@baseplate-dev/sync/extractor-v2';
import {
TemplateFileOptions,
templateFileOptionsSchema,
} from '#src/renderers/schemas/template-file-options.js';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix import ordering and use type-only imports.

The static analysis correctly identifies import ordering issues and that TemplateFileOptions is only used as a type.

Apply this diff to fix the issues:

-import { CASE_VALIDATORS } from '@baseplate-dev/utils';
-import { templateConfigSchema } from '@baseplate-dev/sync/extractor-v2';
-import {
-  TemplateFileOptions,
-  templateFileOptionsSchema,
-} from '#src/renderers/schemas/template-file-options.js';
+import { CASE_VALIDATORS } from '@baseplate-dev/utils';
+import { templateConfigSchema } from '@baseplate-dev/sync/extractor-v2';
+
+import type { TemplateFileOptions } from '#src/renderers/schemas/template-file-options.js';
+import { templateFileOptionsSchema } from '#src/renderers/schemas/template-file-options.js';

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 ESLint

[error] 10-10: Expected "@baseplate-dev/sync/extractor-v2" to come before "@baseplate-dev/utils".

(perfectionist/sort-imports)


[error] 11-14: Imports "TemplateFileOptions" are only used as type.

(@typescript-eslint/consistent-type-imports)


[error] 11-14: Missed spacing between "@baseplate-dev/sync/extractor-v2" and "#src/renderers/schemas/template-file-options.js".

(perfectionist/sort-imports)

🤖 Prompt for AI Agents
In packages/core-generators/src/renderers/typescript/templates/types.ts around
lines 10 to 14, the import statements have ordering issues and
TemplateFileOptions is used only as a type. Reorder the imports to follow the
project's import order conventions and change the import of TemplateFileOptions
to a type-only import to avoid including unnecessary code in the bundle.

@kingston kingston merged commit 0d85654 into main Jun 11, 2025
11 checks passed
@kingston kingston deleted the kingston/eng-735-phase-5-typescript-extractor-implement-ts-extractor-with branch June 11, 2025 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants