Skip to content

feat(core): Native import Syntax Support via NestForge Transpiler #24

@vernonthedev

Description

@vernonthedev

Area

core

NestForge Version

1.6.0

Rust Version

1.87

Summary

To achieve 1:1 parity with the NestJS developer experience, NestForge will implement a source-to-source transpiler. This allows developers to use the exact import { ... } from "..." syntax.

Since import is not a valid Rust keyword, the nestforge-cli will intercept these files and rewrite them into valid Rust use statements before compilation.


Technical Spec

API Shape

The developer writes pure TypeScript-style imports. The transpiler handles the conversion to Rust module paths.

Input (User Code):

import { Module, Controller, Get, Post, Inject } from "nestforge/common";
import { UsersService } from "./users.service";
import { CreateUserDto } from "./dto";

Output (Transpiled Rust):

use nestforge::common::{Module, Controller, Get, Post, Inject};
use self::users_service::UsersService;
use self::dto::CreateUserDto;

Crate Boundaries

  • nestforge-cli
    Contains the regex-based lexer and the file-system watcher. It handles the "shadow build" process.

  • nestforge-core
    Exposes the common module with PascalCase aliases to support the transpiled symbols.


Implementation Details

1. Regex Transformation Logic

The CLI uses the following transformation logic to map TypeScript patterns to Rust paths:

"nestforge/common" -> nestforge::common
"./file.service"   -> self::file_service
"../folder/file"   -> super::folder::file

2. Shadow Build Process

  • The CLI scans the src/ directory for any file containing the import keyword.
  • It transpiles the code and writes it to a hidden .nestforge/cache directory.
  • It automatically generates the necessary pub mod declarations in parent modules to ensure the Rust compiler can find the newly "imported" files.
  • It invokes cargo build pointing to the transpiled entry point.

3. Automatic Case Conversion

To stay consistent with Rust naming conventions while keeping NestJS-style file names, the transpiler automatically converts kebab-case or dot-notated filenames to snake_case for the use paths:

users.service   -> users_service
auth-controller -> auth_controller

Breaking Change Analysis

Impact: High

  • This transition moves NestForge from a library to a transpiled dialect.
  • Standard cargo commands will fail on files using import.
  • Developers must use nestforge start or nestforge dev to trigger the transpilation layer.

Performance Impact

Scope: Build-time only

The transpilation step adds negligible overhead (milliseconds) during the pre-compile phase.
Because the final output is standard Rust code, there is zero runtime overhead.


Alternatives Considered

  • Standard Rust use:

    • Reason for Rejection: It fails to meet the primary goal of providing a familiar environment for developers migrating from TypeScript. The requirement for manual mod declarations and lowercase symbols creates a high barrier to entry that NestForge aims to eliminate.
  • Procedural Macros (import! { ... }):

    • Reason for Rejection: While technically possible within standard Rust, this requires the ! suffix (e.g., import!). This "macro-style" syntax still feels like Rust and does not achieve the exact import { ... } from "..." naming convention required for a true NestJS-like experience.
  • Rust Compiler Plugins:

    • Reason for Rejection: These are highly unstable, require the Nightly Rust toolchain, and frequently break with new compiler releases. A CLI-level transpiler is a more robust and stable solution for a production-grade framework.
  • Manual mod.rs Re-exports (Barrels):

    • Reason for Rejection: Requiring developers to manually maintain pub mod and pub use statements in every folder is redundant and error-prone. The transpiler automates this "boring work" by dynamically generating the module graph during the build process.
  • Attribute-based Imports:

    • Reason for Rejection: Attempting to use attributes like #[import(path)] on structs is syntactically messy and does not support the grouping of multiple symbols (DTOs, Services, Guards) in a single, clean block at the top of the file.

Metadata

Metadata

Assignees

Labels

Projects

Status

In Development

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions