Skip to content

Conversation

@kingston
Copy link
Collaborator

@kingston kingston commented Apr 15, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a comprehensive TypeScript template extraction and rendering system with enhanced metadata validation, import management, and grouping capabilities.
    • Added utilities for organizing imports, stripping template variables, formatting generated files, and managing template groups.
    • Implemented a Fastify config service generator with typed config objects, Zod validation, environment file generation, and improved integration.
    • Added context-aware execution for generator tasks using runner context for task-specific tracking.
    • Created utilities for simplified config field map creation and provider task generation.
  • Bug Fixes

    • Improved validation and error handling for template variables and imports to reduce generation errors.
    • Fixed import paths and utility sources across multiple generators for improved consistency and maintainability.
  • Refactor

    • Simplified TypeScript template rendering APIs, moving to synchronous rendering and action-based models.
    • Modularized Fastify error handler and logger service generators with clearer task separation.
    • Consolidated utility exports and updated import paths for consistency across packages.
    • Replaced direct Prettier formatting calls with a centralized formatting utility for generated files.
    • Updated config field management to use dynamic task-aware field maps.
    • Separated utility imports for clarity, moving quot to a dedicated package.
    • Refined import merging logic to better handle type-only imports.
  • Tests

    • Added extensive unit tests for TypeScript template extraction, import organization, template rendering, and variable stripping.
    • Expanded test coverage for config service generation, runner context propagation, and utility functions.
    • Updated tests to reflect synchronous rendering and new metadata formats.
  • Chores

    • Updated dependencies and internal utilities for concurrency, provider inference, and field mapping.
    • Enhanced CLI and server command argument validation by requiring mandatory parameters.
    • Removed deprecated exports and cleaned up unused utilities.
    • Standardized export paths for core generators and error handler services.

@linear
Copy link

linear bot commented Apr 15, 2025

@changeset-bot
Copy link

changeset-bot bot commented Apr 15, 2025

🦋 Changeset detected

Latest commit: 284e7cb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@halfdomelabs/baseplate-plugin-storage Patch
@halfdomelabs/project-builder-server Patch
@halfdomelabs/project-builder-cli Patch
@halfdomelabs/fastify-generators Patch
@halfdomelabs/react-generators Patch
@halfdomelabs/core-generators Patch
@halfdomelabs/utils Patch
@halfdomelabs/sync Patch
@halfdomelabs/project-builder-common Patch
@halfdomelabs/project-builder-test Patch
@halfdomelabs/project-builder-web Patch
@halfdomelabs/create-project Patch
@halfdomelabs/project-builder-lib Patch

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link

coderabbitai bot commented Apr 15, 2025

Walkthrough

This set of changes introduces a major refactor and enhancement to the template extraction, configuration, and code generation systems across the monorepo. The TypeScript template extraction pipeline is overhauled with the addition of a schema-driven extractor, improved import organization, and more robust template metadata handling. The configuration service for Fastify generators is modularized and migrated to a new generator file, with corresponding updates to all dependent generators. Utility functions for field mapping and provider tasks are added to the sync package, leveraging task context via AsyncLocalStorage. The runner system is updated to propagate and access task IDs, ensuring dynamic context is available throughout generator execution. Numerous import paths are corrected for clarity and specificity. Tests are updated or added to validate new behaviors, especially around template extraction, formatting, and configuration. Several internal APIs are streamlined, and utility exports are reorganized to improve maintainability.

Changes

File(s) / Group Change Summary
packages/core-generators/package.json Added new dependencies (change-case, memfs, oxc-resolver, p-limit).
packages/core-generators/src/__mocks__/fs.cts, src/__mocks__/fs/promises.cts Added mock filesystem modules using memfs for testing.
packages/core-generators/src/generators/node/node/node.generator.ts, src/generators/node/node/package-dependencies-container.ts Refactored field map/config instantiation and dependency container to allow dynamic source tracking via task context.
packages/core-generators/src/generators/node/typescript/index.ts Refactored TypeScript file provider API: replaced direct file writing with action-based rendering, updated types, and streamlined configuration.
packages/core-generators/src/renderers/typescript/actions/* Added new action modules for rendering TypeScript template files and groups; provided index for exports; added comprehensive tests.
packages/core-generators/src/renderers/typescript/extractor/* Introduced new extractor for TypeScript templates, import organization, variable stripping, and project export writing; added tests and templates.
packages/core-generators/src/renderers/typescript/imports/builder.ts Allowed pre-populating import builder with named imports.
packages/core-generators/src/renderers/typescript/imports/merge-ts-import-declarations.ts, .unit.test.ts Simplified logic for determining type-only imports; clarified test expectations.
packages/core-generators/src/renderers/typescript/index.ts Added re-exports for new actions and extractor modules.
packages/core-generators/src/renderers/typescript/renderers/file.ts, .unit.test.ts Simplified template rendering API to synchronous, string-based; unified import map handling; updated tests.
packages/core-generators/src/renderers/typescript/renderers/template.ts, .unit.test.ts Simplified variable replacement logic, improved metadata annotation, and enforced variable usage; updated tests.
packages/core-generators/src/renderers/typescript/templates/creators.ts, templates/types.ts Refactored template file and group types, added schema validation, and introduced creation helpers.
packages/core-generators/src/renderers/typescript/ts-code-utils.ts, .unit.test.ts Improved object key escaping in code fragments; added templateWithImports utility; added test for key escaping.
packages/core-generators/src/utils/index.ts, src/utils/string.ts Removed string utility and its export (functionality moved to external package).
packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts Added new modular Fastify config service generator with improved schema, file output, and provider interface.
packages/fastify-generators/src/generators/core/config-service/index.ts Deleted old config service implementation.
packages/fastify-generators/src/generators/core/config-service/templates/config.ts Updated config template to use injected schema and verification tokens.
packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts Modularized error handler service generator, split config and logger tasks, centralized templates and imports.
packages/fastify-generators/src/generators/core/error-handler-service/templates/plugins/error-handler.ts, others Updated template tokens and import sources; added @ts-nocheck to utility files.
packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts Updated to use new TypeScript-specific imports, templates, and rendering logic.
packages/fastify-generators/src/generators/*/index.ts (many files) Updated import paths for config and error handler services to new generator files; updated config field setting to use new APIs and code fragments.
packages/fastify-generators/src/generators/pothos/*, src/generators/prisma/*, src/writers/pothos/*, others Changed source of quot utility to @halfdomelabs/utils.
packages/react-generators/src/generators/*/index.ts Changed source of quot utility to @halfdomelabs/utils.
packages/project-builder-cli/src/commands/extract-templates.ts, packages/project-builder-server/src/* Made app argument mandatory for template extraction; updated extractor usage for new TypeScript extractor and stricter app matching.
packages/sync/src/providers/providers.ts Added type utility for inferring provider dependency types.
packages/sync/src/runner/generator-runner.ts, .unit.test.ts, runner-context.ts, index.ts Introduced runner context using AsyncLocalStorage for task IDs; ensured context is set during task execution; added tests and exports.
packages/sync/src/templates/extractor/* Refactored extractor to operate on a single output directory, added context for base directory, replaced formatting logic with new utility, and updated tests/utilities.
packages/sync/src/templates/metadata/write-generators-metadata.ts, .unit.test.ts Simplified generator metadata writing logic, removed file and generator set filtering, updated tests accordingly.
packages/sync/src/templates/raw-template/render-raw-template-action.ts, text-template/render-text-template-file-action.ts Updated import paths for utility functions.
packages/sync/src/templates/utils/* Added new formatter utility for Prettier-based formatting; created index for template utilities.
packages/sync/src/utils/create-config-field-map.ts, create-provider-task.ts, index.ts Added new utility functions for config field maps and provider tasks, leveraging runner context; updated exports.

Sequence Diagram(s)

sequenceDiagram
    participant CLI/Server
    participant TemplateExtractor
    participant TsTemplateFileExtractor
    participant FileSystem
    participant Prettier
    participant Generator

    CLI/Server->>TemplateExtractor: runTemplateExtractorsForProject(directory, app, context, logger)
    TemplateExtractor->>TsTemplateFileExtractor: extractTemplateFiles(files)
    TsTemplateFileExtractor->>FileSystem: read template files
    TsTemplateFileExtractor->>Prettier: formatGeneratedTemplateContents(contents, filePath)
    Prettier-->>TsTemplateFileExtractor: formatted contents
    TsTemplateFileExtractor->>FileSystem: write processed template files and import maps
    TsTemplateFileExtractor-->>TemplateExtractor: extraction complete
    TemplateExtractor-->>CLI/Server: extraction complete
Loading
sequenceDiagram
    participant Generator
    participant Runner
    participant Task
    participant RunnerContext

    Generator->>Runner: executeGeneratorEntry(entry, ...)
    Runner->>RunnerContext: runInRunnerContext({taskId}, () => ...)
    RunnerContext->>Task: task.run(...), task.build(...)
    Task-->>RunnerContext: result
    RunnerContext-->>Runner: result
    Runner-->>Generator: result
Loading
sequenceDiagram
    participant FastifyGenerator
    participant ConfigServiceGenerator
    participant FileSystem
    participant TemplateRenderer

    FastifyGenerator->>ConfigServiceGenerator: run (setup/build)
    ConfigServiceGenerator->>TemplateRenderer: renderTemplateFile / renderTemplateGroup
    TemplateRenderer->>FileSystem: write config.ts, .env, .env.example
    FileSystem-->>ConfigServiceGenerator: files written
    ConfigServiceGenerator-->>FastifyGenerator: config provider ready
Loading

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=halfdomelabs/baseplate&utm_content=496):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `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 generate unit testing code for this file.`
  -	`@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 generate unit testing code.`
  - `@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.`

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 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.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@socket-security
Copy link

socket-security bot commented Apr 15, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedoxc-resolver@​5.2.0981008195100

View full report

@socket-security
Copy link

socket-security bot commented Apr 15, 2025

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert (click for details)
Warn Medium
@oxc-resolver/[email protected] is an Unpopular package.

Location: Package overview

Source

ℹ Read more on: This package | This alert | What are unpopular packages?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: Unpopular packages may have less maintenance and contain other problems.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@oxc-resolver/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
@oxc-resolver/[email protected] is an Unpopular package.

Location: Package overview

Source

ℹ Read more on: This package | This alert | What are unpopular packages?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: Unpopular packages may have less maintenance and contain other problems.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@oxc-resolver/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

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: 2

🧹 Nitpick comments (34)
packages/fastify-generators/src/generators/core/error-handler-service/templates/utils/zod.ts (1)

1-1: Type checking disabled for template utility file.

Adding // @ts-nocheck is acceptable for template files where type errors are expected due to dynamic code generation. Consider documenting the rationale for future maintainers.

packages/sync/src/templates/utils/formatter.ts (1)

18-25: Global caching approach is straightforward.
Be aware that if .prettierrc files are changed during runtime, the cache won't auto-refresh. Consider adding invalidation logic if live updates to Prettier configurations are required.

packages/core-generators/src/generators/node/node/package-dependencies-container.ts (1)

30-34: Constructor extension to handle dynamic source.
Storing getDynamicSource in a field is straightforward. Be sure to handle cases where it may be undefined.

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

104-111: Appending Sentry-based logging to loggerActions.
The code fragment precisely references logErrorToSentry. Ensure that the context variable is accessible in the final compiled environment.

packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts (2)

68-101: Unclear test name for import preservation.

The test name suggests it should "clean up unused imports" but the expected behavior shown in the snapshot is to preserve all imports, including the unused one. This mismatch between the test name and actual behavior could cause confusion.

Consider renaming this test to "should preserve all imports including unused ones" to better reflect the expected behavior:

-  it('should clean up unused imports using ts-morph', () => {
+  it('should preserve all imports including unused ones', () => {

1-147: Consider adding tests for nested or overlapping template blocks.

The test suite covers basic template variable stripping, hoisted block removal, import preservation, and error handling, but doesn't explicitly test how the function handles nested or overlapping template blocks.

Consider adding a test case that verifies the behavior with nested template blocks:

it('should handle nested template blocks correctly', () => {
  const metadata: TsTemplateFileMetadata = {
    type: TS_TEMPLATE_TYPE,
    name: 'test-template',
    generator: 'test-generator',
    template: 'test-template.ts',
    variables: {
      TPL_OUTER: { description: 'Outer variable' },
      TPL_INNER: { description: 'Inner variable' },
    },
  };

  const content = `
    /* TPL_OUTER:START */
    const outer = "Outer";
    /* TPL_INNER:START */
    const inner = "Inner";
    /* TPL_INNER:END */
    const afterInner = "After Inner";
    /* TPL_OUTER:END */
  `;

  const result = stripTsTemplateVariables(metadata, content);
  expect(result).toMatchInlineSnapshot(); // Update snapshot after implementation
});
packages/sync/src/templates/metadata/write-generators-metadata.ts (1)

10-41: Update JSDoc to reflect parameter changes.

The JSDoc comment still mentions the removed files parameter which is no longer part of the function signature.

Update the JSDoc comment to reflect the current parameter list:

/**
 * Writes the generator metadata map to the project root that
 * contains the information about the generators that were used to generate the project
 *
 * @param generatorEntry - The generator bundle that was used to generate the project
- * @param files - Map of file paths to file data
 * @param outputDirectory - Base directory where files are being written
 * @returns Promise that resolves when all metadata files are written
 */
packages/core-generators/src/renderers/typescript/extractor/templates/imports-file.ts (2)

1-34: Add documentation to explain template usage.

The template lacks documentation explaining its purpose, usage, and the meaning of the placeholders. Given the complexity of the import map provider pattern, documentation would help developers understand how to use and modify the generated code.

Consider adding JSDoc comments to the template string:

export const IMPORTS_FILE_TEMPLATE = `
+/**
+ * This file defines a typed import map provider for the generated TypeScript code.
+ * It provides type-safe access to imports across the generated code.
+ */
import { createReadOnlyProviderType } from '@halfdomelabs/sync';

import type { TsImportMapProviderFromSchema } from 'TPL_TS_IMPORTS';

import {
  createTsImportMapProvider,
  createTsImportMapSchema,
} from 'TPL_TS_IMPORTS';

+/**
+ * Schema defining the structure of the import map.
+ */
const TPL_IMPORTS_SCHEMA_VAR =
  createTsImportMapSchema(TPL_IMPORTS_SCHEMA);

+/**
+ * Type representing the import map provider based on the schema.
+ */
type TPL_IMPORTS_PROVIDER_TYPE_VAR = TsImportMapProviderFromSchema<
  typeof TPL_IMPORTS_SCHEMA_VAR
>;

+/**
+ * Read-only provider instance for accessing the import map.
+ */
export const TPL_IMPORTS_PROVIDER_VAR =
  createReadOnlyProviderType<TPL_IMPORTS_PROVIDER_TYPE_VAR>(
    'TPL_PROVIDER_NAME',
  );

+/**
+ * Creates an import map provider instance for the given import base.
+ * @param importBase - The base path for imports, must start with '@/'
+ * @returns A typed import map provider instance
+ */
export function TPL_CREATE_IMPORT_MAP_FUNCTION(
  importBase: string,
): TPL_IMPORTS_PROVIDER_TYPE_VAR {
  if (!importBase.startsWith('@/')) {
    throw new Error('importBase must start with @/');
  }

  return createTsImportMapProvider(
    TPL_IMPORTS_SCHEMA_VAR,
    TPL_IMPORT_MAP_CREATOR,
  );
}`;

26-28: Consider enhancing error message.

The error message when importBase doesn't start with '@/' could be more informative by including the actual value provided.

Enhance the error message to include the actual value:

-    throw new Error('importBase must start with @/');
+    throw new Error(`importBase must start with @/, got: \${importBase}`);
packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts (1)

147-149: Import map creation updated to use fixed path.

The import path is now hardcoded to '@/src/services'. This aligns with the validation in the createLoggerServiceImports function that requires paths to start with '@/', but might be less flexible for projects using different import aliases.

Consider making the import base path configurable if projects might use different import alias structures.

packages/core-generators/src/renderers/typescript/ts-code-utils.ts (2)

120-123: Ensure consistency of key naming patterns vs. earlier checks.
You’re allowing [A-Z0-9_a-z]+$ here, but in earlier logic (e.g., line 8) the allowed pattern differs (it includes a dash - but not a lowercase range). Confirm you truly intend to permit different patterns or unify them for consistent key validation throughout the code.


186-198: Consider providing documentation for the new templateWithImports method.
This is a helpful addition, but it’s not immediately clear how the returned function behaves outside your utility context, especially regarding this.template. A short docstring clarifying usage and the interplay with the template method would improve maintainability.

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

7-7: Consider referencing package paths without explicitly including 'node_modules'

Importing directly from 'node_modules/@halfdomelabs/utils/dist/...' can hinder portability if the library structure changes. It's usually safer to import via the published package name or an alias rather than referencing the node_modules directory.


59-67: Add explicit return type for function clarity

The function implicitly returns a shaped object. While this is valid, an explicit return type interface or type alias can improve maintainability and provide clearer API documentation for future contributors.


100-104: Improve error handling for duplicate exports

Throwing a generic Error is acceptable, but consider a custom error class (e.g., DuplicateExportError) or additional file path details to simplify debugging large projects with many files.


124-165: Consider modularizing the rendering logic

The code to construct and render the import map file is somewhat lengthy. Extracting the rendering logic into a helper function or class can improve readability and testability.

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

139-246: Robust checks for project export import map

The test comprehensively verifies import map generation for type-only vs. value exports. Good coverage of path transformation. Ideally, add a case for duplicate export detection to ensure the test suite covers error behavior.


248-477: Comprehensive multi-generator resolution testing

Verifying cross-generator imports and distinct import maps ensures modular correctness. The approach of referencing one generator’s exports in another is well-tested. As a future enhancement, consider testing cyclical references or partial name collisions for completeness.

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

16-24: Refine type naming for clarity
Consider renaming ProjectExportLookupMap to something more descriptive (e.g., ProjectExportsByPathMap) for improved readability. This can help new contributors quickly understand its contents and usage.

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

13-46: Complex generics for template definition
These mapped and conditional types can be quite powerful, yet they might become difficult for future contributors to maintain. Adding a short explanatory comment or an example usage snippet can help.


73-125: Assess potential batch rendering performance
Processing each template sequentially ensures predictable ordering but may become a bottleneck if hundreds of templates are grouped. Consider adding an option for concurrency if the underlying rendering is safe to parallelize.

packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (2)

3-10: Remove unused imports
Ensure each imported symbol from @halfdomelabs/core-generators is actually needed. If not, remove them to maintain a cleaner codebase and shorter dependency graphs.


41-45: Refine naming
Names like configTask and errorHandlerServiceConfigProvider might be more explicit if they included the term "error" or "handler." This can help future maintainers quickly recognize their responsibilities.

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

39-41: Enhance descriptor schema usage or remove if unneeded.
The descriptorSchema is fairly minimal, only specifying an optional placeholder. If it’s not intended for expansion, consider removing it to reduce boilerplate. Otherwise, provide a more explicit description of how to use placeholder.


46-63: Add inline comments or dev docs for new config field properties.
The ConfigField interface has multiple optional properties (seedValue, exampleValue) which directly affect .env files. A short docstring or reference to a usage guide would make the workflow clearer to future maintainers.


155-219: Verify .env generation behavior for existing environments.
The builder logic writes .env and .env.example files but prevents overwriting existing .env via shouldNeverOverwrite: true. This is good for preserving local credentials. However, ensure users understand they won’t get newly introduced fields automatically if .env already exists.

Do you want an automated script to prompt users about new env fields instead of silently ignoring them?

packages/core-generators/src/renderers/typescript/renderers/file.ts (2)

22-26: Add clarification for options interface.
RenderTsCodeFileTemplateOptions extends RenderTsTemplateOptions with additional fields like importSortOptions and resolveModule. Consider adding docstrings to ensure users know how these fields influence import transformations.


109-114: Consider validating importMapProviders more strictly.
Currently, the code checks only for an importMap property in providers. If other fields are needed in the future, ensure consistent validation to avoid subtle runtime errors.

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

262-306: Refactor for clearer separation of concerns.
The file task sets up renderTemplateFile and renderTemplateGroup. While the logic is correct, consider extracting the import resolution logic into a helper for easier testing and reuse, especially since it’s repeated in both rendering methods.

packages/core-generators/src/renderers/typescript/templates/types.ts (2)

46-63: Enhance doc for variables usage in templates.
Though variables is documented, detailing how each variable type is resolved in the resulting code (string vs TsCodeFragment) could reduce confusion for new contributors.


100-124: Enforce uniform naming or grouping in template group definitions.
createTsTemplateGroup lumps templates under a single interface but does not strongly enforce consistent naming conventions. Consider optional validations or docs.

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

81-85: Confirm validity of @src/renderers/typescript/index.js import.

Returning '@src/renderers/typescript/index.js' as an import path might require a custom alias or mapping in your TypeScript build configuration. If this alias is not properly set up, it may break import resolution. Consider providing an explicit .ts extension or ensuring your build config fully supports .js outputs for local modules.


135-135: Evaluate necessity of // @ts-nocheck.

While disabling type checking can expedite generation, it reduces type coverage in the generated file. If possible, consider a more granular approach (e.g., @ts-expect-error) for specific known issues to avoid concealing real errors in the generated output.


254-257: Enhance generator name validation.

Currently checking generatorName.includes('#') helps prevent incorrect formatting, but consider adding a more descriptive or stricter validation method (possibly a regex) to provide clearer error messages and provide better future-proofing.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between d829285 and a0fcbe9.

⛔ Files ignored due to path filters (11)
  • packages/fastify-generators/src/generators/core/config-service/generated/import-maps.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-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/error-handler-service/generated/templates.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-templates.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/import-maps.ts is excluded by !**/generated/**
  • packages/fastify-generators/src/generators/core/logger-service/generated/templates.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-templates.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (107)
  • packages/core-generators/package.json (1 hunks)
  • packages/core-generators/src/__mocks__/fs.cts (1 hunks)
  • packages/core-generators/src/__mocks__/fs/promises.cts (1 hunks)
  • packages/core-generators/src/generators/node/node/node.generator.ts (3 hunks)
  • packages/core-generators/src/generators/node/node/package-dependencies-container.ts (5 hunks)
  • packages/core-generators/src/generators/node/typescript/index.ts (9 hunks)
  • packages/core-generators/src/renderers/typescript/actions/index.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-group-action.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-group-action.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/index.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/organize-ts-template-imports.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/organize-ts-template-imports.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/templates/imports-file.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/write-ts-project-exports.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/imports/builder.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/imports/merge-ts-import-declarations.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/imports/merge-ts-import-declarations.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/index.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/renderers/file.ts (5 hunks)
  • packages/core-generators/src/renderers/typescript/renderers/file.unit.test.ts (7 hunks)
  • packages/core-generators/src/renderers/typescript/renderers/template.ts (3 hunks)
  • packages/core-generators/src/renderers/typescript/renderers/template.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/templates/creators.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/templates/types.ts (2 hunks)
  • packages/core-generators/src/renderers/typescript/ts-code-utils.ts (2 hunks)
  • packages/core-generators/src/renderers/typescript/ts-code-utils.unit.test.ts (1 hunks)
  • packages/core-generators/src/utils/index.ts (0 hunks)
  • packages/core-generators/src/utils/string.ts (0 hunks)
  • packages/fastify-generators/src/generators/auth0/auth0-module/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/bull/bull-mq/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/bull/fastify-bull-board/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/_composers/fastify-composer.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/axios/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/config-service/config-service.generator.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/config-service/index.ts (0 hunks)
  • packages/fastify-generators/src/generators/core/config-service/templates/config.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (4 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/templates/plugins/error-handler.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/templates/services/error-logger.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/templates/utils/http-errors.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/error-handler-service/templates/utils/zod.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-graceful-shutdown/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/fastify-redis/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/fastify-sentry/index.ts (5 hunks)
  • packages/fastify-generators/src/generators/core/fastify-server/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/fastify/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts (3 hunks)
  • packages/fastify-generators/src/generators/core/logger-service/templates/logger.ts (1 hunks)
  • packages/fastify-generators/src/generators/email/fastify-postmark/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/email/fastify-sendgrid/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-auth/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-enum/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-find-query/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-list-query/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-object/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-scalar/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-sentry/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/prisma/_shared/crud-method/primary-key-input.ts (1 hunks)
  • packages/fastify-generators/src/generators/prisma/embedded-relation-transformer/index.ts (1 hunks)
  • packages/fastify-generators/src/generators/prisma/prisma/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/stripe/fastify-stripe/index.ts (3 hunks)
  • packages/fastify-generators/src/generators/yoga/yoga-plugin/index.ts (2 hunks)
  • packages/fastify-generators/src/writers/pothos/helpers.ts (1 hunks)
  • packages/fastify-generators/src/writers/pothos/input-types.ts (1 hunks)
  • packages/fastify-generators/src/writers/pothos/object-types.ts (1 hunks)
  • packages/fastify-generators/src/writers/pothos/scalar-fields.ts (1 hunks)
  • packages/project-builder-cli/src/commands/extract-templates.ts (1 hunks)
  • packages/project-builder-server/src/sync/index.ts (1 hunks)
  • packages/project-builder-server/src/template-extractor/run-template-extractor.ts (4 hunks)
  • packages/react-generators/src/generators/admin/admin-crud-enum-input/index.ts (1 hunks)
  • packages/react-generators/src/generators/admin/admin-crud-foreign-input/index.ts (1 hunks)
  • packages/react-generators/src/generators/admin/admin-layout/index.ts (1 hunks)
  • packages/react-generators/src/generators/auth/auth-login-page/index.ts (1 hunks)
  • packages/react-generators/src/generators/core/_utils/render-routes.ts (1 hunks)
  • packages/react-generators/src/generators/core/react-datadog/index.ts (1 hunks)
  • packages/react-generators/src/generators/core/react/index.ts (1 hunks)
  • packages/sync/src/providers/providers.ts (1 hunks)
  • packages/sync/src/runner/generator-runner.ts (3 hunks)
  • packages/sync/src/runner/generator-runner.unit.test.ts (5 hunks)
  • packages/sync/src/runner/index.ts (1 hunks)
  • packages/sync/src/runner/runner-context.ts (1 hunks)
  • packages/sync/src/templates/extractor/index.ts (1 hunks)
  • packages/sync/src/templates/extractor/run-template-file-extractors.ts (2 hunks)
  • packages/sync/src/templates/extractor/run-template-file-extractors.unit.test.ts (14 hunks)
  • packages/sync/src/templates/extractor/template-file-extractor-test-utils.ts (3 hunks)
  • packages/sync/src/templates/extractor/template-file-extractor.ts (5 hunks)
  • packages/sync/src/templates/index.ts (1 hunks)
  • packages/sync/src/templates/metadata/write-generators-metadata.ts (3 hunks)
  • packages/sync/src/templates/metadata/write-generators-metadata.unit.test.ts (4 hunks)
  • packages/sync/src/templates/raw-template/render-raw-template-action.ts (1 hunks)
  • packages/sync/src/templates/text-template/render-text-template-file-action.ts (1 hunks)
  • packages/sync/src/templates/utils/formatter.ts (1 hunks)
  • packages/sync/src/templates/utils/index.ts (1 hunks)
  • packages/sync/src/templates/utils/read-template-file-source.ts (1 hunks)
  • packages/sync/src/utils/create-config-field-map.ts (1 hunks)
  • packages/sync/src/utils/create-config-provider-task.ts (2 hunks)
  • packages/sync/src/utils/create-provider-task.ts (1 hunks)
  • packages/sync/src/utils/index.ts (1 hunks)
⛔ Files not processed due to max files limit (17)
  • packages/sync/src/utils/parse-generator-name.ts
  • packages/sync/src/utils/parse-generator-name.unit.test.ts
  • packages/utils/src/field-map/field-map.ts
  • packages/utils/src/index.ts
  • packages/utils/src/maps/index.ts
  • packages/utils/src/maps/key-by.ts
  • packages/utils/src/maps/key-by.unit.test.ts
  • packages/utils/src/maps/safe-merge-map.ts
  • packages/utils/src/maps/safe-merge-map.unit.test.ts
  • packages/utils/src/paths/get-common-path-prefix.ts
  • packages/utils/src/paths/get-common-path-prefix.unit.test.ts
  • packages/utils/src/string/index.ts
  • packages/utils/src/string/quot.ts
  • packages/utils/src/string/quot.unit.test.ts
  • plugins/baseplate-plugin-storage/package.json
  • plugins/baseplate-plugin-storage/src/generators/fastify/prisma-file-transformer/index.ts
  • plugins/baseplate-plugin-storage/src/generators/fastify/storage-module/index.ts
💤 Files with no reviewable changes (3)
  • packages/core-generators/src/utils/string.ts
  • packages/core-generators/src/utils/index.ts
  • packages/fastify-generators/src/generators/core/config-service/index.ts
🧰 Additional context used
🧬 Code Graph Analysis (25)
packages/project-builder-server/src/sync/index.ts (1)
packages/sync/src/templates/metadata/write-generators-metadata.ts (1)
  • writeGeneratorsMetadata (52-64)
packages/fastify-generators/src/generators/email/fastify-sendgrid/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/fastify-generators/src/generators/yoga/yoga-plugin/index.ts (1)
packages/sync/src/utils/create-config-field-map.ts (1)
  • createConfigFieldMap (14-20)
packages/fastify-generators/src/generators/stripe/fastify-stripe/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/sync/src/utils/create-config-field-map.ts (2)
packages/utils/src/field-map/field-map.ts (4)
  • FieldMapSchema (184-184)
  • FieldMapSchemaBuilder (197-249)
  • FieldMap (192-194)
  • createFieldMap (264-284)
packages/sync/src/runner/runner-context.ts (1)
  • getRunnerContext (33-35)
packages/sync/src/runner/generator-runner.ts (3)
packages/sync/src/runner/runner-context.ts (1)
  • runInRunnerContext (21-23)
packages/sync/src/generators/generators.ts (1)
  • GeneratorTaskResult (102-116)
packages/sync/src/providers/providers.ts (1)
  • Provider (11-11)
packages/fastify-generators/src/generators/core/fastify-server/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/fastify-generators/src/generators/email/fastify-postmark/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/sync/src/runner/generator-runner.unit.test.ts (3)
packages/sync/src/providers/providers.ts (1)
  • Provider (11-11)
packages/sync/src/runner/runner-context.ts (1)
  • getRunnerContext (33-35)
packages/sync/src/runner/generator-runner.ts (1)
  • executeGeneratorEntry (53-318)
packages/sync/src/templates/extractor/run-template-file-extractors.ts (3)
packages/sync/src/utils/evented-logger.ts (1)
  • Logger (3-8)
packages/sync/src/templates/extractor/create-generator-info-map.ts (1)
  • createGeneratorInfoMap (21-64)
packages/sync/src/templates/constants.ts (1)
  • TEMPLATE_METADATA_FILENAME (2-2)
packages/core-generators/src/generators/node/node/package-dependencies-container.ts (1)
packages/utils/src/field-map/field-map.ts (2)
  • FieldContainerDynamicSourceGetter (1-1)
  • FieldContainerOptions (3-10)
packages/core-generators/src/renderers/typescript/actions/render-ts-template-group-action.unit.test.ts (6)
packages/core-generators/src/renderers/typescript/templates/types.ts (2)
  • createTsTemplateGroup (120-124)
  • createTsTemplateFile (88-98)
packages/core-generators/src/renderers/typescript/actions/render-ts-template-group-action.ts (1)
  • renderTsTemplateGroupAction (73-124)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/sync/src/output/builder-action-test-helpers.ts (1)
  • testAction (35-42)
packages/core-generators/src/renderers/typescript/imports/builder.ts (1)
  • tsImportBuilder (69-77)
packages/core-generators/src/renderers/typescript/import-maps/ts-import-map.ts (2)
  • createTsImportMapSchema (9-13)
  • createTsImportMap (23-67)
packages/sync/src/templates/extractor/template-file-extractor.ts (1)
packages/sync/src/templates/utils/formatter.ts (1)
  • formatGeneratedTemplateContents (56-67)
packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.ts (1)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateFileMetadata (38-40)
packages/fastify-generators/src/generators/core/axios/index.ts (3)
packages/core-generators/src/generators/node/typescript/index.ts (1)
  • typescriptProvider (87-88)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/core-generators/src/renderers/typescript/imports/builder.ts (1)
  • tsImportBuilder (69-77)
packages/fastify-generators/src/generators/core/fastify-sentry/index.ts (2)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/core-generators/src/renderers/typescript/imports/builder.ts (1)
  • tsImportBuilder (69-77)
packages/fastify-generators/src/generators/core/logger-service/logger-service.generator.ts (3)
packages/fastify-generators/src/generators/core/logger-service/generated/ts-templates.ts (1)
  • CORE_LOGGER_SERVICE_TS_TEMPLATES (10-10)
packages/core-generators/src/renderers/typescript/ts-code-utils.ts (1)
  • TsCodeUtils (38-199)
packages/fastify-generators/src/generators/core/logger-service/generated/ts-import-maps.ts (1)
  • createLoggerServiceImports (21-31)
packages/fastify-generators/src/generators/prisma/prisma/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/fastify-generators/src/generators/auth0/auth0-module/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/fastify-generators/src/generators/core/fastify-redis/index.ts (1)
packages/core-generators/src/renderers/typescript/fragments/creators.ts (1)
  • tsCodeFragment (30-44)
packages/core-generators/src/generators/node/node/node.generator.ts (2)
packages/core-generators/src/generators/node/node/package-dependencies-container.ts (1)
  • createNodePackageDependenciesContainer (140-144)
packages/sync/src/utils/create-config-field-map.ts (1)
  • createConfigFieldMap (14-20)
packages/core-generators/src/renderers/typescript/templates/creators.ts (2)
packages/core-generators/src/renderers/typescript/templates/types.ts (2)
  • TsTemplateVariableMap (46-46)
  • TsTemplateFile (48-72)
packages/sync/src/providers/providers.ts (1)
  • ProviderType (17-40)
packages/core-generators/src/renderers/typescript/templates/types.ts (4)
packages/sync/src/templates/metadata/metadata.ts (1)
  • templateFileMetadataBaseSchema (3-20)
packages/sync/src/providers/providers.ts (2)
  • ProviderType (17-40)
  • InferProviderType (42-42)
packages/sync/src/templates/types.ts (1)
  • TemplateFileBase (21-34)
packages/core-generators/src/renderers/typescript/fragments/types.ts (1)
  • TsCodeFragment (45-62)
packages/core-generators/src/renderers/typescript/renderers/file.ts (6)
packages/core-generators/src/renderers/typescript/renderers/template.ts (2)
  • RenderTsTemplateOptions (6-15)
  • renderTsTemplateToTsCodeFragment (24-97)
packages/core-generators/src/renderers/typescript/imports/sort-imports/sort-import-declarations.ts (1)
  • SortImportDeclarationsOptions (12-28)
packages/core-generators/src/renderers/typescript/imports/types.ts (1)
  • TsImportDeclaration (22-43)
packages/core-generators/src/renderers/typescript/fragments/types.ts (1)
  • TsHoistedFragment (16-36)
packages/core-generators/src/renderers/typescript/import-maps/types.ts (1)
  • TsImportMap (30-30)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TsTemplateFileVariableValue (74-74)
packages/core-generators/src/renderers/typescript/ts-code-utils.ts (2)
packages/core-generators/src/renderers/typescript/imports/types.ts (1)
  • TsImportDeclaration (22-43)
packages/core-generators/src/renderers/typescript/fragments/types.ts (1)
  • TsCodeFragment (45-62)
🔇 Additional comments (205)
packages/fastify-generators/src/generators/core/logger-service/templates/logger.ts (1)

2-2: Whitespace addition improves readability.

Adding a blank line after the file-level comment is a minor but positive readability improvement.

packages/sync/src/templates/text-template/render-text-template-file-action.ts (1)

13-13: Import path update improves maintainability.

Switching to a centralized utility import path is a best practice and aligns with the broader codebase refactor.

packages/sync/src/templates/raw-template/render-raw-template-action.ts (1)

4-4: Import path update improves maintainability.

Centralizing utility imports is a best practice and this change is consistent with the codebase refactor.

packages/fastify-generators/src/writers/pothos/helpers.ts (1)

5-5: Importing quot from utils improves modularity.

Moving utility imports to a dedicated package is a best practice for separation of concerns and code reuse.

packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/index.ts (1)

12-12: Importing quot from utils improves modularity.

This change aligns with best practices for utility separation and code reuse.

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

9-9: Import path update improves clarity.

The import path update for errorHandlerServiceProvider to explicitly reference the generator file is correct and aligns with best practices for modularity and maintainability.

packages/react-generators/src/generators/admin/admin-layout/index.ts (1)

12-12: Utility import source update is correct.

Switching the quot import to @halfdomelabs/utils is a positive modularization step and maintains consistency across the codebase.

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

15-15: Utility import modularization is correct.

Importing quot from @halfdomelabs/utils is consistent with the codebase's modularization goals.

packages/react-generators/src/generators/auth/auth-login-page/index.ts (1)

13-13: Utility import modularization is correct.

Switching the quot import to @halfdomelabs/utils is a positive modularization step and maintains consistency across the codebase.

packages/fastify-generators/src/generators/core/error-handler-service/templates/utils/http-errors.ts (1)

1-1: Addition of // @ts-nocheck is appropriate for template files.

Disabling TypeScript checking is standard for code templates that may be transformed or interpolated. No issues found.

packages/sync/src/templates/utils/read-template-file-source.ts (1)

5-5: Import path update improves consistency.

The import path change is correct and aligns with the refactor for utility standardization.

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

15-15: Import path update for errorHandlerServiceProvider improves clarity.

Switching to the explicit generator file path is a good practice for maintainability.

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

17-17: Import path update for errorHandlerServiceProvider improves clarity.

Switching to the explicit generator file path is a good practice for maintainability.

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

18-18: Import path update for errorHandlerServiceProvider improves clarity.

Switching to the explicit generator file path is a good practice for maintainability.

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

12-12: Import path update improves clarity and modularity.

The import path for errorHandlerServiceProvider is now more explicit and aligns with best practices for modular imports. No issues found.

packages/fastify-generators/src/generators/pothos/pothos-sentry/index.ts (1)

13-13: Import path update improves clarity and modularity.

The import path for errorHandlerServiceProvider is now more explicit and aligns with best practices for modular imports. No issues found.

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

3-4: Utility import modularization is correct.

Importing quot from @halfdomelabs/utils improves clarity and modularity. No issues found.

packages/fastify-generators/src/writers/pothos/input-types.ts (1)

1-2: Utility import modularization is correct.

Importing quot from @halfdomelabs/utils improves clarity and modularity. No issues found.

packages/fastify-generators/src/generators/prisma/_shared/crud-method/primary-key-input.ts (1)

3-4: Utility import modularization is correct.

Importing quot from @halfdomelabs/utils improves clarity and modularity. No issues found.

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

24-24: Approve import standardization from @halfdomelabs/utils.

The change to import quot directly from @halfdomelabs/utils instead of from @halfdomelabs/core-generators aligns with the project's effort to standardize utility imports.

packages/fastify-generators/src/writers/pothos/object-types.ts (1)

1-2: Approve consistent utility import pattern.

Separating TypescriptCodeUtils and quot imports improves modularization by sourcing utilities from the appropriate packages.

packages/fastify-generators/src/generators/pothos/pothos-prisma-object/index.ts (1)

13-13: Approve import standardization.

Moving the quot import to come from @halfdomelabs/utils maintains consistency with the pattern applied across the codebase.

packages/fastify-generators/src/generators/pothos/pothos-prisma-enum/index.ts (1)

1-3: Approve consistent utility import refactoring.

Separating the imports to source TypescriptCodeUtils from core-generators and quot from utils package improves organization and consistency.

packages/fastify-generators/src/generators/pothos/pothos-prisma-list-query/index.ts (1)

9-9: Import path refactor is correct.

The import of quot from @halfdomelabs/utils is consistent with the modularization objective and does not affect functionality.

packages/fastify-generators/src/generators/pothos/pothos-prisma-find-query/index.ts (1)

9-9: Utility import refactor is correct.

Switching the quot import to @halfdomelabs/utils is a safe modularization step and does not impact logic.

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

7-7: Export path update is correct.

Changing the utils export to './utils/index.js' aligns with the new utility module structure and is non-breaking.

packages/react-generators/src/generators/core/_utils/render-routes.ts (1)

4-4: Utility import refactor is correct.

Importing quot from @halfdomelabs/utils is consistent with the modularization effort and does not affect logic.

packages/react-generators/src/generators/admin/admin-crud-enum-input/index.ts (1)

3-3: Utility import refactor is correct.

Switching the quot import to @halfdomelabs/utils is a safe modularization step and does not impact logic.

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

41-47: New dependencies are appropriate and justified.

The additions of change-case, memfs, oxc-resolver, and p-limit are well-justified for the new template extraction and rendering features. No issues found.

packages/fastify-generators/src/generators/prisma/embedded-relation-transformer/index.ts (1)

8-8: Import source for quot is now correct.

Switching the import of quot to @halfdomelabs/utils improves modularity and separation of concerns. No issues.

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

3-3: Import path for config is now explicit and modular.

The update to import config from %configServiceImports aligns with the new modular provider structure. No issues.

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

76-76: Simplified nodeConfig.isEsm.set call is correct.

Removing the explicit taskId argument is correct and matches the new internal context management. No issues.

packages/react-generators/src/generators/admin/admin-crud-foreign-input/index.ts (1)

3-3: Import source for quot is now correct.

Switching the import of quot to @halfdomelabs/utils improves modularity and separation of concerns. No issues.

packages/project-builder-server/src/sync/index.ts (1)

170-170: Function signature updated correctly.

The call to writeGeneratorsMetadata has been updated to match the new function signature, removing the output.files parameter. This aligns with the changes in the packages/sync/src/templates/metadata/write-generators-metadata.ts file where the function was simplified to only require the generator entry and output directory.

packages/sync/src/runner/index.ts (1)

2-2: Public API extended to include runner context.

This addition exposes the context management utilities from runner-context.js, which implement context management for generator runners using Node.js AsyncLocalStorage. This is a good enhancement that enables task ID tracking during generator execution.

packages/core-generators/src/__mocks__/fs/promises.cts (1)

1-2: Good mock implementation for testing.

This mock correctly exports the promises property from the memfs package's fs object, providing an in-memory mock of the Node.js fs.promises API. This is a good practice for testing file operations without affecting the real file system.

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

112-120: Good test case for handling invalid identifier keys.

This test validates that object keys containing special characters (like hyphens) are properly escaped as string literals in the generated TypeScript code. This ensures that the mergeFragmentsAsObject method correctly handles object keys that are not valid JavaScript identifiers.

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

1-1: Clean re-export pattern implemented

The re-export pattern is well-implemented, providing a clean public API for the TypeScript extractor functionality. This approach enhances maintainability by centralizing the exports through a single entry point.

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

8-9: Improved import specificity

The imports have been updated to reference specific generator files directly, rather than importing from index files. This makes dependencies more explicit and helps prevent potential circular dependencies.

packages/fastify-generators/src/generators/core/error-handler-service/templates/services/error-logger.ts (1)

19-21: Template placeholders standardized with TPL_ prefix

The placeholder tokens have been updated with a clear TPL_ prefix, making it more evident that these are template placeholders to be replaced during code generation. This convention improves clarity in template files.

packages/core-generators/src/__mocks__/fs.cts (1)

1-2: Good mock implementation using memfs

The implementation of an in-memory filesystem mock using memfs is a good practice for isolating tests from the actual filesystem. This approach allows for predictable and repeatable test scenarios.

packages/sync/src/providers/providers.ts (1)

98-103: Well-designed type utility for provider inference

This new conditional type InferProviderDependency<T> elegantly abstracts away the complexity of extracting provider types from different interfaces. It creates a unified way to infer the underlying provider type from either a ProviderDependency or ProviderType, which will improve type safety and inference in code that works with providers.

The implementation properly follows TypeScript's type inference patterns with the nested conditional type approach.

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

1-2: Clean index exports for the new action modules

This barrel file provides a clean, centralized export point for the TypeScript template rendering actions. This pattern simplifies imports for consumers and helps maintain a clear API boundary.

packages/sync/src/templates/utils/index.ts (1)

1-2: Good organizational pattern for template utilities

This index file follows the module aggregation pattern for centralizing exports. It provides a convenient single import point for accessing template utilities, which improves maintainability and import organization throughout the codebase.

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

2-2: Clean addition of test utilities to the public API

Adding test utilities to the extractor package's public API is a good practice that will facilitate testing for consumers of this module. The placement between the existing exports maintains alphabetical order.

packages/fastify-generators/src/generators/yoga/yoga-plugin/index.ts (3)

18-18: Good migration to context-aware field map creation

Replacing createFieldMap with createConfigFieldMap aligns with the PR's broader goal of making generators context-aware.


29-30: Improved import path specificity

Updating import paths to explicitly reference .generator.js files rather than directory indexes improves code clarity and helps avoid potential circular dependencies. This is consistent with similar import path refinements across the codebase.


93-93: Successfully upgraded to context-aware field map

This change implements the migration from createFieldMap to createConfigFieldMap, which will enable the field map to access the current task ID via the runner context. This is crucial for the reverse generation engine functionality being introduced.

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

1-2: New exports enhance TypeScript generation capabilities

These new exports integrate the action-based rendering model and TypeScript template file extractor into the core TypeScript renderer package. This aligns well with the PR objective of introducing a reverse generation engine for TypeScript.

packages/fastify-generators/src/generators/core/config-service/templates/config.ts (2)

3-3: Improved template-driven configuration approach

The change from inline schema creation to using a predefined schema constant makes the template more flexible and aligns with the template-based code generation architecture.


7-7: Standardized template variable naming

Renaming to TPL_ADDITIONAL_VERIFICATIONS follows the convention of prefixing template placeholders with TPL_, making the code generation process more consistent.

packages/core-generators/src/renderers/typescript/imports/merge-ts-import-declarations.ts (1)

51-51: Simplified type-only import logic

The logic for determining the isTypeOnly property has been simplified while maintaining the same behavior. This is more readable and aligns with TypeScript's behavior where a type-only import declaration makes all its contained imports type-only.

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

47-49: Improved template variable metadata format

The test now expects a more explicit format with distinct start and end comments wrapping template variable replacements. This provides clearer boundaries for template variable replacements, especially for complex replacements that might span multiple lines.

packages/core-generators/src/renderers/typescript/imports/builder.ts (1)

69-76: Nice enhancement adding support for initial named imports.

This is a good enhancement to the tsImportBuilder function that allows it to be initialized with a set of named imports. This makes the API more flexible for consumers who need to start with a predefined set of imports.

The implementation correctly handles the optional nature of the parameter with the namedImports?.map() optional chaining syntax.

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

4-12: Good integration with the context-aware field map system.

The import changes correctly align with the new dynamic source tracking system, replacing createFieldMap with the context-aware createConfigFieldMap utility.


42-42: Proper propagation of options to the dependencies container.

This change correctly passes t.options to the dependencies container, allowing it to access the task context and dynamic source information.


130-132: Well-implemented migration to context-aware field maps.

The switch from createFieldMap to createConfigFieldMap ensures that the node generator's package JSON fields properly track their sources via the runner context task IDs.

packages/sync/src/utils/create-config-provider-task.ts (2)

20-20: Good modularization of the context-aware field map utility.

The import change correctly references the new local module containing the context-aware field map creation utility.


109-109: Excellent integration with runner context for source tracking.

Using createConfigFieldMap instead of createFieldMap ensures that configuration fields are properly associated with the current task ID from the runner context, improving traceability.

packages/project-builder-cli/src/commands/extract-templates.ts (2)

20-20: Updated parameter type to match new required behavior.

The function signature correctly reflects that app is now a required string parameter instead of optional.

This change aligns with the command definition update and the corresponding server-side changes in the template extraction workflow.


16-16:

Details

❓ Verification inconclusive

Breaking change: app parameter is now required.

This change makes the app parameter mandatory in the CLI command, which is a breaking change for existing users who might be running the command without specifying an app.

Make sure this change is documented in the release notes/changelog. Also, verify that the error message when not providing the app parameter is clear and helpful for users.


🏁 Script executed:

#!/bin/bash
# Verify the error message displayed when the app parameter is missing
pbcli extract-templates . 2>&1 | grep -E "error|required|missing"

Length of output: 62


Action Required: Verify Clear Error Message for Missing app Parameter

The change that makes the app parameter mandatory is critical and may affect existing users. However, our initial verification did not yield any error output when running the command without the app parameter:

pbcli extract-templates . 2>&1 | grep -E "error|required|missing"

No error message was detected, which prevents us from confirming that users will see a clear, helpful error when the parameter is omitted. Please manually verify that:

  • Running pbcli extract-templates without the app parameter prompts a clear and informative error message.
  • The breaking change is appropriately documented in the release notes/changelog.
packages/core-generators/src/renderers/typescript/imports/merge-ts-import-declarations.unit.test.ts (2)

110-110: Explicit isTypeOnly property improves test clarity.

The addition of isTypeOnly: false makes the test more explicit about the behavior being tested. This clarifies that the import keeps its type-only status based on the parent declaration, not the individual import.


114-114: Consistent property usage in test case.

Adding isTypeOnly: false here maintains consistency with the type-only import declaration above, making the test more explicit and easier to understand.

packages/sync/src/runner/generator-runner.ts (3)

28-28: Added new context management import.

This import allows for task context propagation during generator execution.


156-162: Enhanced task execution with runner context.

Wrapping the task.run call with runInRunnerContext enables dynamic context propagation while maintaining the original functionality. This allows the taskId to be accessible throughout the execution flow.


205-209: Added context propagation for the build step.

Similar to the change in the init step, this wraps the generator.build method call with runInRunnerContext to ensure the taskId is available in the context during the build phase.

packages/fastify-generators/src/generators/prisma/prisma/index.ts (3)

12-12: Added import for tsCodeFragment utility.

This import will be used to create TypeScript code fragments for configuration validators, improving code generation.


35-35: Updated import path for better module resolution.

The import path was changed to reference the specific generator file rather than the directory index, improving clarity and stability of imports.


144-147: Updated configuration field definition approach.

The code now:

  1. Uses configFields.set instead of getConfigEntries().set
  2. Uses validator property instead of value
  3. Applies tsCodeFragment for the schema validator

This aligns with the new pattern for defining configuration fields across Fastify generators.

packages/sync/src/utils/create-config-field-map.ts (1)

14-20: Well-designed utility for task-aware configuration field maps.

This new utility function elegantly bridges configuration fields with the task execution context. By providing a getDynamicSource callback that retrieves the current task ID, it enables dynamic context awareness in configuration field maps.

This is a good abstraction that centralizes the pattern of creating field maps with task context awareness.

packages/fastify-generators/src/generators/email/fastify-sendgrid/index.ts (3)

5-5: Import added for code fragment support.

The addition of tsCodeFragment import enables type-safe creation of TypeScript code fragments with proper import handling, which is used for the validation schema below.


16-16: Improved import specificity.

Updated import path to reference the specific generator file rather than the directory index. This makes dependencies more explicit and improves build tooling's ability to track dependencies.


44-49: Updated config field API with code fragment validation.

The configuration service API has been updated to use configFields.set instead of getConfigEntries().set, and the validation schema is now defined using tsCodeFragment instead of a string literal. This provides better type safety and enables IDE support for the schema definition.

packages/sync/src/utils/index.ts (1)

1-2: Added exports for new utility modules.

These new utility exports provide important functionality:

  • concurrency.js - Likely contains utilities for managing concurrent operations
  • create-config-field-map.js - Creates field maps with dynamic source tracking
  • create-provider-task.js - Facilitates creating generator tasks with type-safe inference
  • parse-generator-name.js - Utilities for parsing generator names

These additions support the broader refactoring effort across the monorepo.

Also applies to: 7-7, 12-12

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

8-8: Import added for code fragment support.

The addition of tsCodeFragment import enables type-safe creation of TypeScript code fragments with proper import handling, consistent with other generator files.


22-22: Improved import specificity.

Updated import path to reference the specific generator file rather than the directory index, making dependencies more explicit and improving build tooling's ability to track dependencies.


67-71: Updated config field API with code fragment validation.

The configuration service API has been updated to use configFields.set instead of getConfigEntries().set, and the validation schema is now defined using tsCodeFragment instead of TypescriptCodeUtils.createExpression. This provides better type safety and enables IDE support for the schema definition.

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

9-9: Import added for code fragment support.

The addition of tsCodeFragment import enables type-safe creation of TypeScript code fragments with proper import handling, consistent with other generator files.


25-25: Improved import specificity.

Updated import path to reference the specific generator file rather than the directory index, making dependencies more explicit and improving build tooling's ability to track dependencies.


123-134: Updated config field API with advanced validation schemas.

The configuration service API has been updated to use configFields.mergeObj() instead of getConfigEntries().merge(), with validation schemas now defined using tsCodeFragment. This provides:

  1. Better type safety for config fields
  2. More expressive validation schemas (with defaults, min/max values)
  3. Consistent approach to configuration handling across generators

The port validation properly coerces input to numbers and sets appropriate min/max constraints.

packages/fastify-generators/src/generators/auth0/auth0-module/index.ts (6)

24-24: Dependency import path updated to specific generator file.

Import has been updated to reference the specific generator file instead of index. This matches the pattern used in other files and improves clarity by making the exact source explicitly visible.


83-88: Configuration API updated to use configFields.set with typed validators.

The configuration setup for AUTH0_DOMAIN has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation. This approach provides better type safety and consistency with other generator modules.


90-95: Configuration API updated to use configFields.set with typed validators.

The configuration setup for AUTH0_AUDIENCE has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation.


110-116: Configuration API updated to use configFields.set with typed validators.

The configuration setup for AUTH0_TENANT_DOMAIN has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation.


118-124: Configuration API updated to use configFields.set with typed validators.

The configuration setup for AUTH0_CLIENT_ID has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation.


126-131: Configuration API updated to use configFields.set with typed validators.

The configuration setup for AUTH0_CLIENT_SECRET has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation.

packages/fastify-generators/src/generators/email/fastify-postmark/index.ts (3)

5-5: Added import for tsCodeFragment.

Added the import for tsCodeFragment which is now used for configuration validation.


16-16: Dependency import path updated to specific generator file.

Import has been updated to reference the specific generator file instead of index. This improves clarity by making the exact source explicitly visible.


42-47: Configuration API updated to use configFields.set with typed validators.

The configuration setup for POSTMARK_API_TOKEN has been updated to use the newer configuration API with configFields.set and tsCodeFragment for validation. This approach provides better type safety and consistency with other generator modules.

packages/sync/src/runner/generator-runner.unit.test.ts (4)

21-21: Added import for the runner context accessor.

Imported getRunnerContext from the new runner-context module to access the current task context during testing.


59-59: Added optional run parameter to test helper function.

Extended the buildGeneratorEntry helper to accept an optional run callback, allowing tests to execute custom logic during the run phase of generator execution.

Also applies to: 73-74


90-96: Updated test helper to incorporate run callback.

Modified the test helper to execute the optional run callback before returning providers and build function, allowing tests to verify behavior during the run phase.


141-157: Added test to verify task ID propagation.

Added a new test that verifies the task ID is correctly set and accessible in the runner context during both the run and build phases of generator execution. This ensures that task context is properly propagated throughout the generation process.

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

4-5: Updated exports to reference specific generator files.

Modified the exports to point directly to specific generator files rather than directory indexes. This makes the export sources more explicit and aligns with the import pattern used across the codebase.

packages/sync/src/utils/create-provider-task.ts (1)

11-32: Clean, type-safe abstraction for provider-dependent tasks

This utility function elegantly simplifies the creation of generator tasks that depend on a single provider. The implementation is well-documented with JSDoc comments and uses generics to ensure strong type safety.

packages/fastify-generators/src/generators/stripe/fastify-stripe/index.ts (3)

5-5: Import addition aligns with updated validation pattern

Adding the tsCodeFragment utility supports the transition to typed code fragments for validators.


17-18: Explicit import paths improve clarity

The updated import paths directly reference the specific generator files, making dependencies more explicit and easier to track.


60-69: Enhanced type safety in config validation

The switch from string literal validators to typed code fragments using tsCodeFragment improves type safety and consistency. This change aligns with the broader refactoring pattern across generators.

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

4-4: New TypeScript template extractor integration

Adding the TsTemplateFileExtractor import introduces enhanced TypeScript template extraction capabilities.


24-24: Extended template extraction support

Adding the TypeScript template file extractor to the creators list enables enhanced template extraction for TypeScript files.


76-84: Improved validation prevents ambiguous app selection

This validation ensures a single app directory is selected, preventing ambiguity when multiple directories match the app name. The update to pass only a single directory to runTemplateFileExtractors aligns with this change.


53-53:

Details

✅ Verification successful

Stricter app parameter typing might impact backward compatibility

The app parameter is now required as a string, removing its optionality. Verify that all calling code provides this parameter.


🏁 Script executed:

#!/bin/bash
# Check for places where runTemplateExtractorsForProject is called
rg -A 3 'runTemplateExtractorsForProject\(' --type ts

Length of output: 859


Verification Complete – Backward Compatibility Confirmed

The change to require the app parameter as a string has been verified. All call sites, including the one in packages/project-builder-cli/src/commands/extract-templates.ts, provide this argument, so there is no backward compatibility issue.

packages/core-generators/src/renderers/typescript/renderers/file.unit.test.ts (4)

4-7: Updated imports for new import map functionality

These imports support the enhanced import map handling capabilities being tested.


12-28: Simplified test case for synchronous rendering

This test has been updated to use the new synchronous API of renderTsCodeFileTemplate, passing template contents directly rather than using an async file-based approach.


52-55: Consistent API updates across test cases

All test cases have been consistently updated to use the new synchronous rendering API, improving test readability and maintainability.

Also applies to: 84-91, 130-133


149-197: Comprehensive test for multiple import maps

This new test verifies an important capability - handling multiple import maps correctly. The test creates separate import maps and confirms they are properly merged and resolved during rendering.

packages/sync/src/templates/extractor/run-template-file-extractors.unit.test.ts (6)

24-25: Correctly updates to single output directory pattern.

The refactoring from multiple output directories to a single outputDirectory variable aligns with the function signature change in the implementation. This simplification makes the code easier to maintain and understand.


58-92: Test data setup properly updated for single directory pattern.

The file system mock has been successfully updated to use the single output directory, maintaining test coverage while aligning with the new implementation.


100-105: Function call signature correctly updated.

The call to runTemplateFileExtractors now passes a single output directory instead of an array, matching the updated function signature.


114-148: Expectations properly updated to use single output directory.

The tests now correctly verify that the extractor is called with file paths based on the single output directory.


151-223: Successfully refactored duplicate template test case.

This test has been properly updated to use the single output directory while still testing the important behavior of selecting the most recently modified template file when duplicates exist.


225-256: Error handling test successfully updated.

The test for the error scenario has been properly updated to use the single output directory.

packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.ts (4)

3-6: Well-structured regular expressions for template variable handling.

The regular expressions are clearly defined to match template variable blocks and hoisted code blocks with appropriate naming conventions.


8-19: Clear documentation of function purpose and behavior.

The JSDoc comments effectively explain the function's purpose, behavior, and parameters.


20-37: Robust template variable processing with error handling.

The code correctly extracts declared variables, processes the template content, and provides meaningful error messages for unknown variables.


38-46: Thorough validation of template variables.

The code ensures all declared variables are present in the content, providing a safeguard against metadata-content inconsistencies.

packages/sync/src/runner/runner-context.ts (4)

1-13: Good use of AsyncLocalStorage for context management.

The implementation uses Node.js's AsyncLocalStorage appropriately to maintain context across asynchronous operations. The interface is well-defined with proper documentation.


14-23: Clean implementation of context wrapper function.

The runInRunnerContext function provides a clear API for executing functions within a specific runner context.


25-35: Correctly documented getter with usage warning.

The getRunnerContext function is properly documented with a clear warning about its intended use for debugging and testing only, which helps prevent misuse in production code.


1-35:

Details

✅ Verification successful

Verify integration with task execution flow.

Since this is a new module that provides context management for generator runners, ensure it's properly integrated with the task execution flow in the generator runner.


🏁 Script executed:

#!/bin/bash
# Check how the runner context is used in the generator runner
rg -A 3 -B 2 "runInRunnerContext|getRunnerContext" "packages/sync/src/runner"

Length of output: 3697


Integration Confirmed: Runner Context Management in Task Execution Flow

The new context module is properly integrated:

  • The functions runInRunnerContext and getRunnerContext are used in the main generator runner (packages/sync/src/runner/generator-runner.ts) to manage task execution contexts.
  • Unit tests in packages/sync/src/runner/generator-runner.unit.test.ts correctly verify that the task context (e.g., taskId) is captured and accessible via getRunnerContext.

No further modifications are necessary.

packages/sync/src/templates/metadata/write-generators-metadata.unit.test.ts (3)

25-52: Successfully simplified test for single generator.

The test has been updated to remove the files parameter from the call to writeGeneratorsMetadata, aligning with the implementation changes.


54-98: Updated nested generators test with correct paths.

The nested generators test has been properly updated with the new base directory path and expected output format. The mock implementations have been adjusted to match the new structure.


54-98:

Details

❓ Verification inconclusive

Verify calculation of relative paths in implementation.

The test expects the metadata to contain relative paths like 'src/test' and 'src/child', but it's not immediately clear how the implementation derives these paths from the base directories.


🏁 Script executed:

#!/bin/bash
# Examine how write-generators-metadata.ts calculates relative paths
cat packages/sync/src/templates/metadata/write-generators-metadata.ts | grep -A 20 "writeGeneratorsMetadata"

Length of output: 519


Action Required: Please verify how buildGeneratorInfoMapRecursive derives relative paths.

The writeGeneratorsMetadata function delegates the path calculation to buildGeneratorInfoMapRecursive, and the test expects generator paths like 'src/test' and 'src/child' derived from the provided absolute baseDirectory values. However, it's not immediately clear from the snippet how these relative paths (with an injected "src" directory) are computed.

  • Please confirm that buildGeneratorInfoMapRecursive calculates the relative path by:
    • Using the package root (obtained via findNearestPackageJson)
    • Converting the absolute base directory to a path relative to that package root, with necessary transformations (e.g., replacing "dist" with "src").

If the current implementation performs these calculations accurately, no changes are needed. Otherwise, please adjust the logic in buildGeneratorInfoMapRecursive accordingly.

packages/sync/src/templates/utils/formatter.ts (4)

1-6: Imports from Prettier look good.
They provide all the necessary utilities for formatting.


8-16: ALLOWED_EXTENSIONS enhances clarity and maintainability.
Defining a set of supported extensions prevents accidental formatting of unsupported files.


27-44: Robust fallback logic for Prettier config.
The function properly returns the default config if resolveConfigFile or resolveConfig fails, ensuring consistent formatting.


56-67: Well-structured format function.
Using filepath in the Prettier options ensures correct parser selection.

packages/core-generators/src/generators/node/node/package-dependencies-container.ts (4)

1-5: New imports align with usage of dynamic source.
They integrate cleanly with the field container concept from @halfdomelabs/utils.


15-15: Optional 'source' field clarifies dependency origin.
This addition helps trace dependencies. No issues found.


74-82: Assigning 'source' with conditional calls.
Gracefully handles undefined sources. This is consistent with the new optional property.


140-143: Factory function upgrade.
Providing options for dynamic sources maintains consistency with the container constructor.

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

14-15: Switch to tsCodeFragment and tsImportBuilder.
This change follows the new builder-based approach for generating TypeScript code and imports.


30-34: Refined imports for config service and error handler.
Consolidating imports in generator files improves clarity and maintainability.


84-86: Dependency injection for errorHandlerServiceConfig.
This is a clean extension to integrate Sentry with error handling routines.


148-152: Adding SENTRY_DSN as a config field.
Registering the field with an optional string validator is a sensible default approach.

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

29-31: Function signature simplified to use a single output directory

The function has been refactored to accept a single outputDirectory string instead of an array of directories, which simplifies the interface and aligns with the project's evolution toward a more focused template extraction approach.


35-38: Simplified generator info map creation

The generator info map creation is now streamlined to work with a single output directory, removing the previous complexity of merging multiple maps.


43-43: Added baseDirectory property to extractor creator context

This change properly propagates the output directory as the base directory for extractors, ensuring they have the correct context for template extraction.


49-49: Simplified glob pattern for template metadata files

The glob pattern has been updated to reflect the single output directory approach, making the code more straightforward and efficient.

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

6-8: Updated imports to use TypeScript fragment utilities

Replaced the previous TypescriptCodeUtils import with more specific utilities (tsCodeFragment and tsImportBuilder), which aligns with the project's move toward a more modular approach to code generation.


13-13: Updated error handler service import path

The import has been updated to use the new errorHandlerServiceConfigProvider from the dedicated generator file, reflecting the modularization of the error handler service.


27-30: Updated dependency injection to use the new config provider

The dependencies and parameter names have been updated to use the new configuration provider pattern, ensuring compatibility with the refactored error handler service.


44-49: Refactored error handler integration to use declarative code fragments

Instead of directly manipulating files with imperative code, the generator now pushes a code fragment to the error handler's context actions array. This is a significant improvement that:

  1. Makes the code more declarative and easier to understand
  2. Improves testability by reducing side effects
  3. Follows the new pattern of using typed code fragments
  4. Supports the modular architecture of the generator system
packages/core-generators/src/renderers/typescript/actions/render-ts-template-group-action.unit.test.ts (4)

1-19: Well-structured test setup with proper imports and mocks

The test file correctly imports the necessary utilities and sets up filesystem mocking using memfs, which is essential for isolated unit testing of file operations. The beforeEach hook ensures a clean state for each test.


24-91: Comprehensive test for rendering multiple templates with variables

This test thoroughly verifies that the template group action can:

  1. Process a template group with multiple templates
  2. Apply different variables to each template
  3. Correctly output files with transformed content
  4. Maintain the expected directory structure

The test structure is clear, with a good setup-execute-verify pattern.


93-134: Proper testing of import resolution with custom module resolver

This test verifies the advanced capability to resolve import paths using a custom resolver function, which is crucial for maintaining correct module references in generated code. The test properly asserts both that the file was created and that its contents match the expected transformed output.


136-212: Thorough testing of import map handling in template groups

This test correctly verifies that import maps are properly processed across multiple templates in a group, ensuring that placeholder imports are replaced with actual package paths. The test uses snapshots to verify the exact content formatting, which is appropriate for this use case.

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

1-19: Well-structured test setup with proper imports and mocking

Similar to the template group tests, this file correctly sets up the testing environment with appropriate imports and filesystem mocks to ensure isolated tests.


21-70: Comprehensive test for template file rendering with metadata

This test thoroughly verifies that the template file action:

  1. Correctly reads from template paths
  2. Replaces template variables with provided values
  3. Includes template metadata in the output when requested
  4. Sets the correct file ID based on generator and template information

The assertions are comprehensive and cover all aspects of the expected functionality.


72-101: Properly tests inline template content with imports

This test verifies that templates defined with inline content (rather than file paths) work correctly, especially when introducing imports for variables. This is an important use case for programmatically generated templates.


103-130: Robust error handling test for mismatched variables

This test ensures that the action correctly validates that all required template variables are provided before rendering, preventing silent failures or incomplete template substitution. The explicit error testing is a good practice.


132-192: Thorough testing of multiple import maps

This test correctly verifies that the template file action can handle multiple import maps simultaneously, replacing different placeholders with their respective mapped imports. The snapshot assertion provides a comprehensive check of the final formatted output.

packages/sync/src/templates/extractor/template-file-extractor.ts (5)

15-15: Good addition of formatGeneratedTemplateContents import.

This change replaces direct Prettier calls with a centralized formatting utility, which will improve consistency and maintainability across template files.


50-53: Good addition of baseDirectory property.

This property improves the context awareness of extractors by providing access to the project's root directory, which is essential for resolving relative paths correctly.


72-74: Well-designed accessor method for baseDirectory.

The protected getProjectBaseDirectory() method provides a clean way for subclasses to access the project root directory without directly accessing the context property.


108-115: Good refactoring of formatting logic.

Replacing inline formatting with the centralized formatGeneratedTemplateContents utility improves consistency and maintainability. The type checking is preserved correctly.


147-150: Good refactoring of TypeScript file formatting.

This change consistently applies the new formatting approach to TypeScript files as well, ensuring uniform formatting across all generated templates.

packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts (5)

1-8: Good test setup with appropriate imports.

The imports are well-organized, including the necessary testing utilities and the types/functions being tested.


9-40: Well-structured test for basic template variable stripping.

This test correctly verifies that template variable blocks are replaced with their variable names, using appropriate metadata setup and snapshot testing.


42-66: Comprehensive test for hoisted block removal.

The test properly verifies that HOISTED blocks are completely removed from the template content, which is important for the template generation process.


103-123: Good error handling test for unknown template variables.

This test correctly verifies that the function throws an appropriate error when encountering template variables not defined in the metadata.


125-147: Good error handling test for missing template variables.

This test correctly verifies that the function throws an appropriate error when template variables defined in metadata are missing from the content.

packages/sync/src/templates/metadata/write-generators-metadata.ts (3)

16-16: Good simplification of condition.

The simplified condition checks only if the generator name is already in the map, removing unnecessary complexity.


39-39: Good simplification of recursive call.

Removed the unnecessary parameter from the recursive method call, consistent with the simplified approach.


52-57: Good simplification of method signature and implementation.

Removing the files parameter simplifies the API and implementation, focusing only on the essential generator entry and output directory parameters.

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

1-34: Well-structured template for import map provider generation.

The template provides a consistent structure for generating TypeScript modules that create and export typed import map providers. It includes appropriate imports, type definitions, validation, and exports.

packages/core-generators/src/renderers/typescript/templates/creators.ts (1)

2-2: Types updated to align with schema-validated template system.

The function has been updated to use the new TsTemplateVariableMap and TsTemplateFile types instead of the older loosely-typed templates. This is part of the broader refactoring to improve type safety across the template creation, rendering, and extraction workflows.

Also applies to: 4-4, 12-12, 18-19

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

1-227: Well-structured test suite with comprehensive coverage.

The tests thoroughly validate the writeTsProjectExports function's behavior, including:

  • Handling empty project exports
  • Processing various export types (regular and type-only)
  • Path resolution differences between core and external generators
  • Error handling for duplicate exports
  • Proper path mapping generation

All test cases have clear assertions and good setup code.

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

1-136: Good test coverage for import organization functionality.

This test suite effectively validates the organizeTsTemplateImports function, covering:

  • Successful consolidation of imports and removal of unused ones
  • Error handling for unsupported namespace imports
  • Error handling for imports not found in project exports

The mock resolver pattern is well implemented and the test assertions are thorough.

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

26-29: Import paths updated to use new TypeScript-specific modules.

The imports have been updated to use the new modules with "ts-" prefixes, aligning with the TypeScript template rendering infrastructure introduced in this PR.


126-144: Template rendering refactored to use the new action-based approach.

The implementation has been updated from the older async file writing method to the new action-based rendering system with renderTemplateFile. However, the destination path is now hardcoded to 'src/services/logger.ts', which might reduce flexibility for projects with different directory structures.

Was hardcoding the destination path intentional? Consider if this path should be configurable based on project needs or derived from some configuration.


157-157: Export path updated to match new module structure.

The export statement has been updated to match the new file structure with TypeScript-specific modules.

packages/core-generators/src/renderers/typescript/renderers/template.ts (7)

2-2: No issues with the new import.
This import helps define the type for template variable values. All good.


24-26: Exported function signature is appropriate.
Exporting the function with a clear param type ensures proper usage of template variables. No points of concern here.


44-63: Block template metadata handling looks solid.
The logic neatly inserts commented metadata blocks when includeMetadata is true, removing variables from variableKeys. This ensures correct detection of used variables. No major issues found.


65-66: Regex-based variable replacement approach is fine.
Using a capturing group with lookahead to match the prefix is a sound solution for variable substitution.


74-75: Variable tracking is properly updated.
Removing the key from variableKeys helps ensure leftover variables are flagged later.


76-78: Inline metadata comment insertion is correct.
You are consistently wrapping replaced segments with START/END markers, promoting reliable reverse generation.


82-87: Unused variable detection is well-implemented.
Throwing an error for any leftover variables clarifies if references are missing in the template.

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

34-137: Thorough test of variable logic and import cleanup

This test method provides solid coverage of variable replacement, hoisted block removal, and unused import cleanup. Great approach using in-memory FS; you might also consider a negative test that confirms behavior with malformed or missing variables.

packages/sync/src/templates/extractor/template-file-extractor-test-utils.ts (4)

10-13: Addition of second generator constants

These constants facilitate testing multiple generators in parallel. Makes sense for broader coverage of multi-generator scenarios, improving test realism.


26-32: Great extension of generatorInfoMap

Including the second generator in generatorInfoMap broadens the test context. This helps robustly verify cross-generator references and import resolution.


46-50: Expanded exports for second generator

Exposing new constants for the second generator aligns with multi-generator testing. This fosters uniform naming and easy reference in tests.


63-80: Addition of outputPath utility

The outputPath utility centralizes path generation for test outputs, reducing potential path-handling bugs and improving readability.

packages/core-generators/src/renderers/typescript/extractor/organize-ts-template-imports.ts (4)

1-14: Consider verifying module versions
While these imports are essential for code transformations, confirm that the current versions of oxc-resolver and ts-morph are compatible with the rest of your toolchain.

Would you like me to provide a script to confirm the package versions used in the codebase?


26-37: Comprehensive docstring
The documentation is thorough and clearly outlines the function's purpose, steps, and return value. This level of clarity will benefit maintainers and foster readability.


38-63: Be cautious with organizeImports()
The call to sourceFile.organizeImports() may remove imports perceived as unused but still needed in certain circumstances (e.g., for type augmentation). Ensure you have robust test coverage around tricky or borderline cases.


64-148: Efficient concurrency with Promise.all()
Resolving imports concurrently is a sensible design choice, but be mindful of scaling to large codebases. If performance becomes an issue, consider caching resolution results or introducing streaming mechanisms to handle massive imports.

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

1-12: Avoid naming conflicts
All imported types appear valid. Double-check for potential naming collisions with other modules in the codebase or third-party libraries.


47-72: Flexible interface design
Allowing partial or required template variables based on the presence of generics strikes a good balance between strict typing and usability. This is a neat approach to type safety.

packages/fastify-generators/src/generators/core/error-handler-service/error-handler-service.generator.ts (3)

15-29: Well-structured config provider task
The separation of error-handler config creation into its own provider task is both clean and maintainable, ensuring each concern is neatly isolated.


71-125: Confirm plugin and template registration
Check that each newly introduced generator task consistently renders or registers the TypeScript files for the error handler, ensuring the plugin is properly integrated and discoverable at runtime.


127-172: Validate dynamic error logging merges
Combining contextActions and loggerActions via TsCodeUtils.mergeFragments is a neat pattern. Confirm the final expansions function as intended under various runtime conditions.

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

120-153: Confirm default environment variable coverage.
Here, only APP_ENVIRONMENT is defined, with defaults like 'development' or 'production'. For more robust setups, consider adding standard fields (e.g., PORT, DATABASE_URL) or ensuring that user-defined fields can be appended easily.

Would you like to add more environment variables or clarify how users should add them?

packages/core-generators/src/renderers/typescript/renderers/file.ts (2)

79-92: Hoisted fragments writing approach looks solid.
This utility function writeHoistedFragments neatly handles metatagging with HOISTED:${h.key}:START/END. It’s a clean solution for controlling fragment placement.


117-118: Retain partial, minimal duplication checks.
renderTsTemplateToTsCodeFragment already handles unused variables. If there’s any chance of re-invoking it with the same variables, confirm that no duplication occurs across calls.

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

19-23: Good introduction of typed render payloads.
These new types (RenderTsTemplateFileActionInput and friends) standardize the template rendering approach, improving maintainability.


151-152: No immediate concerns with setup task usage.
The setup: createGeneratorTask(setupTask) pattern is consistent with the rest of the code, ensuring typed configuration merges.

packages/core-generators/src/renderers/typescript/templates/types.ts (3)

12-36: Leverage the template metadata for robust type safety.
The extended schema properly requires type: z.literal(TS_TEMPLATE_TYPE). This approach locks in strong correctness guarantees for TypeScript-based templates. No issues at a glance.


74-80: Check runtime edge cases for variable naming.
InferTsTemplateVariablesFromMap expects uppercase, prefix-based replacements from upstream. If users supply lowercased or unpredictable keys, they may hit errors. A warning or fallback might help.


88-98: Factory function usage is helpful.
createTsTemplateFile centralizes file creation logic. The typed approach is straightforward, guaranteeing correct inference for variables and providers.

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

67-70: Scrutinize extension aliases for potential coverage gaps.

The extension alias covers a variety of TS/JS extensions, but you might want to confirm usage scenarios for .tsx, .cts, .mts, etc. Specifically, consider whether the existing .replace(/\.ts$/, '.js') logic aligns with all mapped extensions in these aliases or if additional transformations for .tsx or others might be necessary.


113-133: Validate import source rewriting logic and potential multi-extension scenarios.

The block generating usedImportProviders rewrites the .ts extension to .js for import sources. Ensure that this step remains consistent with your extension alias strategy. If you need to handle .tsx or other variants, consider broadening the replacement to avoid resolution issues for template files with non-.ts extensions.


223-224: Appreciate concurrency limit usage.

Applying pLimit to manage the extraction concurrency is a prudent choice for large codebases, preventing excessive resource consumption. This design ensures stable performance under heavy loads and is a well-structured approach.


319-375: Overall code structure and maintainability.

The top-level logic in extractTemplateFiles—grouping by generator, generating import files, checking for duplicate providers, and proceeding with extraction—is well-organized. It cleanly separates concerns and makes the workflow easy to follow.

Comment on lines +48 to +52
// Remove HOISTED blocks
processedContent = processedContent.replaceAll(HOISTED_REGEX, '');

return processedContent;
}
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

Consider adding unit tests for edge cases.

The implementation handles the happy path and basic error cases, but consider adding tests for edge cases such as:

  1. Multiple occurrences of the same variable
  2. Variable blocks with nested content
  3. Malformed variable blocks (missing END tags)

🏁 Script executed:

#!/bin/bash
# Check if unit tests exist for strip-ts-template-variables.ts
fd --type f "strip-ts-template-variables.unit.test.ts" -x cat {} \; | grep -E "describe|it|test"

Length of output: 1126


Add Additional Edge Case Unit Tests for Template Variable Extraction

The current unit tests cover the basic functionality (e.g., stripping template variables and removing HOISTED blocks) as evidenced by the test output. However, it appears that the following edge cases are not explicitly tested:

  • Multiple occurrences of the same variable
  • Variable blocks with nested content
  • Malformed variable blocks (e.g., missing END tags)

Please consider adding targeted tests to cover these scenarios in the unit test file (packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts).

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: 1

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

19-31: Mock resolver could be improved with more comprehensive testing scenarios.

The mock resolver implementation is simplistic and only handles the happy path. Consider extending it to simulate resolution failures to test error handling.

function createMockResolver(): ResolverFactory {
  return {
    async: vi.fn().mockImplementation((folder: string, source: string) =>
      Promise.resolve({
        path: source.startsWith('./')
          ? path.join(folder, source.slice(2))
          : source,
        error: null,
      }),
    ),
+   // Add cases to simulate resolution failures
+   // For example, to test specific import paths:
+   // if (source.includes('non-existent')) {
+   //   return Promise.resolve({ path: null, error: new Error('Cannot find module') });
+   // }
    sync: vi.fn(),
  } as unknown as ResolverFactory;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between a0fcbe9 and c07a684.

📒 Files selected for processing (4)
  • .changeset/witty-keys-relate.md (1 hunks)
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts (1 hunks)
  • packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/witty-keys-relate.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core-generators/src/renderers/typescript/extractor/strip-ts-template-variables.unit.test.ts
  • packages/core-generators/src/renderers/typescript/actions/render-ts-template-file-action.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (3)
packages/sync/src/templates/extractor/template-file-extractor-test-utils.ts (2)
  • TemplateFileExtractorTestUtils (40-81)
  • templatePath (63-74)
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.ts (1)
  • TsTemplateFileExtractor (52-375)
packages/core-generators/src/renderers/typescript/templates/types.ts (1)
  • TS_TEMPLATE_TYPE (10-10)
🔇 Additional comments (5)
packages/core-generators/src/renderers/typescript/extractor/ts-template-file-extractor.unit.test.ts (5)

1-13: Well structured imports and mocking setup.

The file correctly imports the necessary dependencies, including mocking the filesystem modules with memfs. Good separation between external libraries, internal modules, and Node.js built-ins.


14-17: Appropriate test lifecycle hooks.

Good practice to reset the virtual filesystem and clear mocks before each test to ensure test isolation.


33-137: The first test case comprehensively validates core template extraction functionality.

The test successfully verifies that the extractor:

  1. Properly removes hoisted code blocks
  2. Replaces template variables with their placeholder names
  3. Cleans up unused imports
  4. Generates correct template definition files

The snapshot assertions provide strong guarantees against regressions.


139-246: Strong verification of import map generation.

This test thoroughly validates that the generated import maps:

  1. Include the correct schema definitions
  2. Generate proper provider types
  3. Create appropriate path mappings for exports
  4. Handle type-only exports correctly

The detailed assertions and snapshots will catch any regressions in import map generation.


248-477: Great cross-generator import resolution test.

This test effectively verifies that imports between different generators are properly resolved, which is a key feature for a modular template system. It confirms:

  1. Import maps are generated for both generators
  2. Cross-generator imports are transformed to use provider imports
  3. Generator-local imports remain as relative paths

The transformation of import { FirstComponent } from './first-component.ts' to import { FirstComponent } from '%testGeneratorImports' is a critical validation of the import resolution mechanism.

Comment on lines +1 to +478
import type { ResolverFactory } from 'oxc-resolver';

import { TemplateFileExtractorTestUtils } from '@halfdomelabs/sync';
import { vol } from 'memfs';
import path from 'node:path';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { TS_TEMPLATE_TYPE } from '../templates/types.js';
import { TsTemplateFileExtractor } from './ts-template-file-extractor.js';

vi.mock('node:fs/promises');
vi.mock('node:fs');

beforeEach(() => {
vol.reset();
vi.clearAllMocks();
});

function createMockResolver(): ResolverFactory {
return {
async: vi.fn().mockImplementation((folder: string, source: string) =>
Promise.resolve({
path: source.startsWith('./')
? path.join(folder, source.slice(2))
: source,
error: null,
}),
),
sync: vi.fn(),
} as unknown as ResolverFactory;
}

describe('TsTemplateFileExtractor', () => {
it('should extract TS template file, replace variables, remove hoisted, and clean imports', async () => {
const context =
TemplateFileExtractorTestUtils.createTestTemplateFileExtractorContext();
const mockResolver = createMockResolver();
const extractor = new TsTemplateFileExtractor(context, {
pathResolver: mockResolver,
});

const inputFilePath =
TemplateFileExtractorTestUtils.outputPath('my-component.ts');
const templatePath = 'my-component.ts'; // Relative path for metadata/output

vol.fromJSON({
[inputFilePath]: `
import { A, B, C, D } from 'external-package';
import { Z } from './unused-import.ts';

/* HOISTED:HELPER_FN:START */
function helper() {
console.log('This should be removed');
}
/* HOISTED:HELPER_FN:END */

export function /* TPL_COMPONENT_NAME:START */MyComponent/* TPL_COMPONENT_NAME:END */() {
const msg = /* TPL_MESSAGE:START */'hello'/* TPL_MESSAGE:END */;
const x: A = new A();
const y: B = { prop: /* TPL_PROP_VALUE:START */123/* TPL_PROP_VALUE:END */ };
return \`\${msg} \${x} \${y}\`;
}

// Another hoisted block
/* HOISTED:ANOTHER:START */
const removedVar = 1;
/* HOISTED:ANOTHER:END */
`,
});

await extractor.extractTemplateFiles([
{
path: inputFilePath,
metadata: {
name: 'myComponentTemplate', // Camelcase name for the template object
type: TS_TEMPLATE_TYPE,
generator: TemplateFileExtractorTestUtils.TEST_GENERATOR_NAME,
template: templatePath, // Path relative to templates dir
variables: {
TPL_COMPONENT_NAME: {},
TPL_MESSAGE: {},
TPL_PROP_VALUE: {},
},
},
},
]);

const result = vol.toJSON();
const generatedTemplatePath =
TemplateFileExtractorTestUtils.templatePath(templatePath);
const generatedDefinitionPath =
TemplateFileExtractorTestUtils.generatedPath('ts-templates.ts');

// 1. Check the generated template file content
expect(result[generatedTemplatePath]).toBeDefined();
expect(result[generatedTemplatePath]).toContain('TPL_COMPONENT_NAME');
expect(result[generatedTemplatePath]).toContain('TPL_MESSAGE');
expect(result[generatedTemplatePath]).toContain('TPL_PROP_VALUE');
expect(result[generatedTemplatePath]).not.toContain('/* HOISTED:');
expect(result[generatedTemplatePath]).not.toContain('helper()');
expect(result[generatedTemplatePath]).not.toContain('unused-import'); // Import should be removed
expect(result[generatedTemplatePath]).not.toContain(' C, D'); // Unused named import C
expect(result[generatedTemplatePath]).toContain(' A, B '); // Used named imports A and B

// Snapshot the template file for detailed verification
expect(result[generatedTemplatePath]).toMatchInlineSnapshot(`
"// @ts-nocheck

import { A, B } from 'external-package';

export function TPL_COMPONENT_NAME() {
const msg = TPL_MESSAGE;
const x: A = new A();
const y: B = { prop: TPL_PROP_VALUE };
return \`\${msg} \${x} \${y}\`;
}

// Another hoisted block
"
`);

// 2. Check the generated definition file content
expect(result[generatedDefinitionPath]).toBeDefined();
expect(result[generatedDefinitionPath]).toMatchInlineSnapshot(`
"import { createTsTemplateFile } from '@halfdomelabs/core-generators';

const myComponentTemplate = createTsTemplateFile({
name: 'myComponentTemplate',
source: { path: 'my-component.ts' },
variables: { TPL_COMPONENT_NAME: {}, TPL_MESSAGE: {}, TPL_PROP_VALUE: {} },
projectExports: {},
});

export const TEST_GENERATOR_TS_TEMPLATES = { myComponentTemplate };
"
`);
});

it('should generate import maps file for project exports', async () => {
const context =
TemplateFileExtractorTestUtils.createTestTemplateFileExtractorContext();
const mockResolver = createMockResolver();
const extractor = new TsTemplateFileExtractor(context, {
pathResolver: mockResolver,
});
const inputFilePath = TemplateFileExtractorTestUtils.outputPath(
'components/test-component.ts',
);

vol.fromJSON({
[inputFilePath]: `
export const TestComponent = () => {};
export type TestComponentProps = {};
`,
});

await extractor.extractTemplateFiles([
{
path: inputFilePath,
metadata: {
type: TS_TEMPLATE_TYPE,
name: 'testComponent',
generator: 'test-package#test-generator',
template: 'test-component.ts',
variables: {},
projectExports: {
TestComponent: { isTypeOnly: false },
TestComponentProps: { isTypeOnly: true },
},
},
},
]);

const result = vol.toJSON();
const generatedImportsPath =
TemplateFileExtractorTestUtils.generatedPath('ts-import-maps.ts');

// Check that the import maps file was generated
expect(result[generatedImportsPath]).toBeDefined();
expect(result[generatedImportsPath]).toContain(
'testGeneratorImportsSchema',
);
expect(result[generatedImportsPath]).toContain(
'TestGeneratorImportsProvider',
);
expect(result[generatedImportsPath]).toContain(
'testGeneratorImportsProvider',
);
expect(result[generatedImportsPath]).toContain(
'createTestGeneratorImports',
);

// Check that the exports are included
expect(result[generatedImportsPath]).toContain('TestComponent: {}');
expect(result[generatedImportsPath]).toContain(
'TestComponentProps: { isTypeOnly: true }',
);

// Check the path mapping
expect(result[generatedImportsPath]).toContain(
"TestComponent: path.join(importBase, 'test-component.js')",
);
expect(result[generatedImportsPath]).toContain(
"TestComponentProps: path.join(importBase, 'test-component.js')",
);

// Snapshot the imports file for detailed verification
expect(result[generatedImportsPath]).toMatchInlineSnapshot(`
"import type { TsImportMapProviderFromSchema } from '@halfdomelabs/core-generators';

import {
createTsImportMapProvider,
createTsImportMapSchema,
} from '@halfdomelabs/core-generators';
import { createReadOnlyProviderType } from '@halfdomelabs/sync';
import path from 'node:path/posix';

const testGeneratorImportsSchema = createTsImportMapSchema({
TestComponent: {},
TestComponentProps: { isTypeOnly: true },
});

type TestGeneratorImportsProvider = TsImportMapProviderFromSchema<
typeof testGeneratorImportsSchema
>;

export const testGeneratorImportsProvider =
createReadOnlyProviderType<TestGeneratorImportsProvider>(
'test-generator-imports',
);

export function createTestGeneratorImports(
importBase: string,
): TestGeneratorImportsProvider {
if (!importBase.startsWith('@/')) {
throw new Error('importBase must start with @/');
}

return createTsImportMapProvider(testGeneratorImportsSchema, {
TestComponent: path.join(importBase, 'test-component.js'),
TestComponentProps: path.join(importBase, 'test-component.js'),
});
}
"
`);
});

it('should handle import provider resolution across multiple generators', async () => {
const context =
TemplateFileExtractorTestUtils.createTestTemplateFileExtractorContext();
const mockResolver = createMockResolver();
const extractor = new TsTemplateFileExtractor(context, {
pathResolver: mockResolver,
});

// Set up first generator files
const firstGeneratorName =
TemplateFileExtractorTestUtils.TEST_GENERATOR_NAME;
const firstComponentPath = TemplateFileExtractorTestUtils.outputPath(
'components/first-component.ts',
);
const firstUtilPath = TemplateFileExtractorTestUtils.outputPath(
'components/first-util.ts',
);

vol.fromJSON({
[firstComponentPath]: `
import { FirstUtil } from './first-util.ts';

export function FirstComponent() {
return FirstUtil();
}
`,
[firstUtilPath]: `
export function FirstUtil() {
return 'first';
}
`,
});

// Set up second generator files
const secondGeneratorName =
TemplateFileExtractorTestUtils.TEST_GENERATOR_2_NAME;
const secondComponentPath = TemplateFileExtractorTestUtils.outputPath(
'components/second-component.ts',
);
const secondUtilPath = TemplateFileExtractorTestUtils.outputPath(
'components/second-util.ts',
);

vol.fromJSON({
[secondComponentPath]: `
import { SecondUtil } from './second-util.ts';
import { FirstComponent } from './first-component.ts';

export function SecondComponent() {
return FirstComponent() + SecondUtil();
}
`,
[secondUtilPath]: `
export function SecondUtil() {
return 'second';
}
`,
});

// Extract files from both generators
await extractor.extractTemplateFiles([
{
path: firstComponentPath,
metadata: {
type: TS_TEMPLATE_TYPE,
name: 'firstComponent',
generator: firstGeneratorName,
template: 'first-component.ts',
variables: {},
projectExports: {
FirstComponent: { isTypeOnly: false },
},
},
},
{
path: firstUtilPath,
metadata: {
type: TS_TEMPLATE_TYPE,
name: 'firstUtil',
generator: firstGeneratorName,
template: 'first-util.ts',
variables: {},
projectExports: {
FirstUtil: { isTypeOnly: false },
},
},
},
{
path: secondComponentPath,
metadata: {
type: TS_TEMPLATE_TYPE,
name: 'secondComponent',
generator: secondGeneratorName,
template: 'second-component.ts',
variables: {},
projectExports: {
SecondComponent: { isTypeOnly: false },
},
},
},
{
path: secondUtilPath,
metadata: {
type: TS_TEMPLATE_TYPE,
name: 'secondUtil',
generator: secondGeneratorName,
template: 'second-util.ts',
variables: {},
projectExports: {
SecondUtil: { isTypeOnly: false },
},
},
},
]);

const result = vol.toJSON();
const firstGeneratorImportsPath =
TemplateFileExtractorTestUtils.generatedPath(
'ts-import-maps.ts',
firstGeneratorName,
);
const secondGeneratorImportsPath =
TemplateFileExtractorTestUtils.generatedPath(
'ts-import-maps.ts',
secondGeneratorName,
);

// Check that import maps were generated for both generators
expect(result[firstGeneratorImportsPath]).toBeDefined();
expect(result[secondGeneratorImportsPath]).toBeDefined();

// Check first generator imports
expect(result[firstGeneratorImportsPath]).toContain('FirstComponent');
expect(result[firstGeneratorImportsPath]).toContain('FirstUtil');

// Check second generator imports
expect(result[secondGeneratorImportsPath]).toContain('SecondComponent');
expect(result[secondGeneratorImportsPath]).toContain('SecondUtil');

expect(result[firstGeneratorImportsPath]).toMatchInlineSnapshot(`
"import type { TsImportMapProviderFromSchema } from '@halfdomelabs/core-generators';

import {
createTsImportMapProvider,
createTsImportMapSchema,
} from '@halfdomelabs/core-generators';
import { createReadOnlyProviderType } from '@halfdomelabs/sync';
import path from 'node:path/posix';

const testGeneratorImportsSchema = createTsImportMapSchema({
FirstComponent: {},
FirstUtil: {},
});

type TestGeneratorImportsProvider = TsImportMapProviderFromSchema<
typeof testGeneratorImportsSchema
>;

export const testGeneratorImportsProvider =
createReadOnlyProviderType<TestGeneratorImportsProvider>(
'test-generator-imports',
);

export function createTestGeneratorImports(
importBase: string,
): TestGeneratorImportsProvider {
if (!importBase.startsWith('@/')) {
throw new Error('importBase must start with @/');
}

return createTsImportMapProvider(testGeneratorImportsSchema, {
FirstComponent: path.join(importBase, 'first-component.js'),
FirstUtil: path.join(importBase, 'first-util.js'),
});
}
"
`);

// Check that the generated template files have the correct imports
const firstComponentTemplatePath =
TemplateFileExtractorTestUtils.templatePath(
'first-component.ts',
firstGeneratorName,
);
const secondComponentTemplatePath =
TemplateFileExtractorTestUtils.templatePath(
'second-component.ts',
secondGeneratorName,
);

expect(result[firstComponentTemplatePath]).toContain(
"import { FirstUtil } from './first-util.ts'",
);
expect(result[secondComponentTemplatePath]).toContain(
"import { SecondUtil } from './second-util.ts'",
);
expect(result[secondComponentTemplatePath]).toContain(
"import { FirstComponent } from '%testGeneratorImports'",
);

expect(result[secondComponentTemplatePath]).toMatchInlineSnapshot(`
"// @ts-nocheck

import { FirstComponent } from '%testGeneratorImports';

import { SecondUtil } from './second-util.ts';

export function SecondComponent() {
return FirstComponent() + SecondUtil();
}
"
`);

// Check that the template definitions are correct
const firstGeneratorTemplatesPath =
TemplateFileExtractorTestUtils.generatedPath(
'ts-templates.ts',
firstGeneratorName,
);
const secondGeneratorTemplatesPath =
TemplateFileExtractorTestUtils.generatedPath(
'ts-templates.ts',
secondGeneratorName,
);

expect(result[firstGeneratorTemplatesPath]).toContain('firstComponent');
expect(result[firstGeneratorTemplatesPath]).toContain('firstUtil');
expect(result[secondGeneratorTemplatesPath]).toContain('secondComponent');
expect(result[secondGeneratorTemplatesPath]).toContain('secondUtil');
});
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error case tests.

The test suite thoroughly covers the happy path, but lacks tests for error conditions that could occur in real usage. Adding tests for the following scenarios would improve robustness:

  1. Duplicate export names across files
  2. Invalid template variable syntax
  3. Missing required metadata fields
  4. Import resolution failures
  5. Circular dependencies between generators
it('should throw error when detecting duplicate export names', async () => {
  const context = TemplateFileExtractorTestUtils.createTestTemplateFileExtractorContext();
  const extractor = new TsTemplateFileExtractor(context, {
    pathResolver: createMockResolver(),
  });
  
  // Set up files with duplicate export names
  const file1Path = TemplateFileExtractorTestUtils.outputPath('file1.ts');
  const file2Path = TemplateFileExtractorTestUtils.outputPath('file2.ts');
  
  vol.fromJSON({
    [file1Path]: `export const DuplicateExport = () => {};`,
    [file2Path]: `export const DuplicateExport = () => {};`,
  });
  
  // Expect the extraction to throw due to duplicate export names
  await expect(extractor.extractTemplateFiles([
    {
      path: file1Path,
      metadata: {
        type: TS_TEMPLATE_TYPE,
        name: 'file1',
        generator: TemplateFileExtractorTestUtils.TEST_GENERATOR_NAME,
        template: 'file1.ts',
        variables: {},
        projectExports: { DuplicateExport: { isTypeOnly: false } },
      },
    },
    {
      path: file2Path,
      metadata: {
        type: TS_TEMPLATE_TYPE,
        name: 'file2',
        generator: TemplateFileExtractorTestUtils.TEST_GENERATOR_NAME,
        template: 'file2.ts',
        variables: {},
        projectExports: { DuplicateExport: { isTypeOnly: false } },
      },
    },
  ])).rejects.toThrow(/Duplicate project export/);
});

@kingston kingston merged commit e544158 into main Apr 15, 2025
7 checks passed
@kingston kingston deleted the kingston/eng-612-add-typescript-template-extractor branch April 15, 2025 17:00
@github-actions github-actions bot mentioned this pull request Apr 15, 2025
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