mirror of
https://github.com/ziex-dev/ziex.git
synced 2026-07-19 10:09:36 -06:00
feat: addTranslateZx to allow component library
This commit is contained in:
parent
d732718bc0
commit
48e29b9d2f
55
build.zig
55
build.zig
@ -311,51 +311,24 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn createModule(
|
||||
b: *std.Build,
|
||||
opts: std.Build.Module.CreateOptions,
|
||||
) *std.Build.Module {
|
||||
const root_src_file = opts.root_source_file orelse unreachable;
|
||||
pub const TranslatedZx = @import("src/build/TranslatedZx.zig");
|
||||
|
||||
/// Transpile a `.zx` component file into a `TranslatedZx`, mirroring
|
||||
/// `std.Build.addTranslateC`. Call `.createModule()` / `.addModule(name)` on the
|
||||
/// result to get a module, then bind `zx` afterwards — typically via the
|
||||
/// `ZiexBuild` returned by `init`, which owns the app's canonical zx module:
|
||||
///
|
||||
/// const tzx = ziex.addTranslateZx(b, .{ .root_source_file = b.path("icons.zx") });
|
||||
/// const icons = tzx.createModule();
|
||||
/// icons.addImport("zx", zx.module); // `zx` from `ziex.init`
|
||||
///
|
||||
/// The host transpiler CLI is resolved with the host target so it can execute
|
||||
/// during the build; it never enters the runtime module graph.
|
||||
pub fn addTranslateZx(b: *std.Build, opts: TranslatedZx.Options) *TranslatedZx {
|
||||
const zx_host_dep = b.dependencyFromBuildZig(@This(), .{
|
||||
// .optimize = options.cli.optimize, // Always in release mode for faster transpilation
|
||||
// No target = host target, so zx CLI can execute during build
|
||||
.@"exclude-lsp" = true, // Skip LSP for faster build-time transpilation
|
||||
});
|
||||
|
||||
const transpiler_exe = zx_host_dep.artifact("zx");
|
||||
const transpile_cmd = b.addRunArtifact(transpiler_exe);
|
||||
|
||||
transpile_cmd.setName("zx transpile");
|
||||
transpile_cmd.addArg("transpile");
|
||||
transpile_cmd.addDirectoryArg(root_src_file);
|
||||
transpile_cmd.addArg("--outdir");
|
||||
const transpiler_mod_path = transpile_cmd.addOutputDirectoryArg("components_gen");
|
||||
// transpile_cmd.addArg("--rootdir");
|
||||
// transpile_cmd.addDirectoryArg(static_lazypath);
|
||||
transpile_cmd.addArg("--dep-file");
|
||||
_ = transpile_cmd.addDepFileOutputArg("transpile.d");
|
||||
// if (opts.copy_embedded_sources) {
|
||||
// transpile_cmd.addArg("--copy-embedded-sources");
|
||||
// }
|
||||
// if (opts.base_path) |bp| {
|
||||
// transpile_cmd.addArgs(&.{ "--base-path", bp });
|
||||
// }
|
||||
// Always generate inlined sourcemaps so dev mode can remap errors to .zx files
|
||||
transpile_cmd.addArgs(&.{ "--map", "inline" });
|
||||
const cache_path_arg = b.pathJoin(&.{ b.cache_root.path orelse ".zig-cache", "zx_transpile" });
|
||||
transpile_cmd.addArgs(&.{ "--cache-dir", cache_path_arg });
|
||||
transpile_cmd.expectExitCode(0);
|
||||
|
||||
// _ = try transpile_cmd.step.addDirectoryWatchInput(opts.site_path);
|
||||
|
||||
var transpiled_mod_opts = opts;
|
||||
const root_src_basename = root_src_file.basename(b, &transpile_cmd.step);
|
||||
const root_src_ext = std.fs.path.extension(root_src_basename);
|
||||
const transpiled_src_name = b.fmt("{s}.zig", .{root_src_basename[0 .. root_src_basename.len - root_src_ext.len]});
|
||||
|
||||
transpiled_mod_opts.root_source_file = transpiler_mod_path.path(b, transpiled_src_name);
|
||||
return b.createModule(transpiled_mod_opts);
|
||||
return TranslatedZx.create(b, zx_host_dep.artifact("zx"), opts);
|
||||
}
|
||||
|
||||
pub const info = .{
|
||||
|
||||
10
pkg/ui/build.zig
Normal file
10
pkg/ui/build.zig
Normal file
@ -0,0 +1,10 @@
|
||||
const std = @import("std");
|
||||
const ziex = @import("ziex");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const tzx = ziex.addTranslateZx(b, .{
|
||||
.root_source_file = b.path("component/root.zx"),
|
||||
});
|
||||
const ui_mod = tzx.addModule("ui");
|
||||
_ = ui_mod;
|
||||
}
|
||||
84
pkg/ui/build.zig.zon
Normal file
84
pkg/ui/build.zig.zon
Normal file
@ -0,0 +1,84 @@
|
||||
.{
|
||||
// This is the default name used by packages depending on this one. For
|
||||
// example, when a user runs `zig fetch --save <url>`, this field is used
|
||||
// as the key in the `dependencies` table. Although the user can choose a
|
||||
// different name, most users will stick with this provided value.
|
||||
//
|
||||
// It is redundant to include "zig" in this name because it is already
|
||||
// within the Zig package namespace.
|
||||
.name = .ui,
|
||||
// This is a [Semantic Version](https://semver.org/).
|
||||
// In a future version of Zig it will be used for package deduplication.
|
||||
.version = "0.0.0",
|
||||
// Together with name, this represents a globally unique package
|
||||
// identifier. This field is generated by the Zig toolchain when the
|
||||
// package is first created, and then *never changes*. This allows
|
||||
// unambiguous detection of one package being an updated version of
|
||||
// another.
|
||||
//
|
||||
// When forking a Zig project, this id should be regenerated (delete the
|
||||
// field and run `zig build`) if the upstream project is still maintained.
|
||||
// Otherwise, the fork is *hostile*, attempting to take control over the
|
||||
// original project's identity. Thus it is recommended to leave the comment
|
||||
// on the following line intact, so that it shows up in code reviews that
|
||||
// modify the field.
|
||||
.fingerprint = 0x27ff46b0392d653b, // Changing this has security and trust implications.
|
||||
// Tracks the earliest Zig version that the package considers to be a
|
||||
// supported use case.
|
||||
.minimum_zig_version = "0.16.0",
|
||||
// This field is optional.
|
||||
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||
// Once all dependencies are fetched, `zig build` no longer requires
|
||||
// internet connectivity.
|
||||
.dependencies = .{
|
||||
.ziex = .{
|
||||
.path = "../../",
|
||||
},
|
||||
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
||||
//.example = .{
|
||||
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||
// // the new URL. If the contents of a URL change this will result in a hash mismatch
|
||||
// // which will prevent zig from using it.
|
||||
// .url = "https://example.com/foo.tar.gz",
|
||||
//
|
||||
// // This is computed from the file contents of the directory of files that is
|
||||
// // obtained after fetching `url` and applying the inclusion rules given by
|
||||
// // `paths`.
|
||||
// //
|
||||
// // This field is the source of truth; packages do not come from a `url`; they
|
||||
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
||||
// // obtain a package matching this `hash`.
|
||||
// //
|
||||
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
||||
// .hash = "...",
|
||||
//
|
||||
// // When this is provided, the package is found in a directory relative to the
|
||||
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||
// // computed. This field and `url` are mutually exclusive.
|
||||
// .path = "foo",
|
||||
//
|
||||
// // When this is set to `true`, a package is declared to be lazily
|
||||
// // fetched. This makes the dependency only get fetched if it is
|
||||
// // actually used.
|
||||
// .lazy = false,
|
||||
//},
|
||||
},
|
||||
// Specifies the set of files and directories that are included in this package.
|
||||
// Only files and directories listed here are included in the `hash` that
|
||||
// is computed for this package. Only files listed here will remain on disk
|
||||
// when using the zig package manager. As a rule of thumb, one should list
|
||||
// files required for compilation plus any license(s).
|
||||
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
||||
// the build root itself.
|
||||
// A directory listed here means that all files within, recursively, are included.
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// For example...
|
||||
//"LICENSE",
|
||||
//"README.md",
|
||||
},
|
||||
}
|
||||
9
pkg/ui/component/icon.zx
Normal file
9
pkg/ui/component/icon.zx
Normal file
@ -0,0 +1,9 @@
|
||||
pub fn GitHub(allocator: zx.Allocator) zx.Component {
|
||||
return (
|
||||
<svg @{allocator} width="20" height="20" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
const zx = @import("zx");
|
||||
1
pkg/ui/component/root.zx
Normal file
1
pkg/ui/component/root.zx
Normal file
@ -0,0 +1 @@
|
||||
pub const icon = @import("icon.zx");
|
||||
@ -1 +0,0 @@
|
||||
pub const Icons = @import("pages/components/icons.zx");
|
||||
@ -1,3 +1,7 @@
|
||||
const component = @import("component");
|
||||
const icon = @import("icon");
|
||||
const ui = @import("ui");
|
||||
|
||||
pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {
|
||||
const path = ctx.request.pathname;
|
||||
const description = "A full-stack web framework for Zig. Write declarative UI components using familiar JSX patterns, transpiled to efficient Zig code.";
|
||||
@ -80,6 +84,12 @@ pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="display:none">
|
||||
<component.icon.GitHub />
|
||||
<ui.icon.GitHub />
|
||||
<icon.GitHub />
|
||||
</div>
|
||||
|
||||
<GtmBody />
|
||||
{children}
|
||||
</body>
|
||||
|
||||
@ -114,11 +114,11 @@ pub fn build(b: *std.Build) !void {
|
||||
app_exe.step.dependOn(&install_pg.step); // Playground disabled
|
||||
|
||||
// --- ZX setup: wires dependencies and adds `zx`/`dev` build steps --- //
|
||||
_ = try ziex.init(b, app_exe, .{
|
||||
var zx = try ziex.init(b, app_exe, .{
|
||||
.app = .{
|
||||
// .path = b.path("app"),
|
||||
// .base_path = "/test",
|
||||
.copy_embedded_sources = true,
|
||||
// .copy_embedded_sources = true,
|
||||
.features = .{
|
||||
.sqlite = .enabled,
|
||||
},
|
||||
@ -130,10 +130,17 @@ pub fn build(b: *std.Build) !void {
|
||||
.cli = .{ .optimize = optimize },
|
||||
});
|
||||
|
||||
const component_mod = ziex.createModule(b, .{
|
||||
.root_source_file = b.path("app/components.zx"),
|
||||
});
|
||||
app_exe.root_module.addImport("components", component_mod);
|
||||
// --- ZX Components --- //
|
||||
// Single File
|
||||
const icons_mod = zx.addComponent(.{ .root_source_file = b.path("component/icon.zx") });
|
||||
zx.app.module.addImport("icon", icons_mod);
|
||||
// multifile
|
||||
zx.addComponentImport("component", .{ .root_source_file = b.path("component/main.zx") });
|
||||
// from deps
|
||||
const ui_dep = b.dependency("ui", .{});
|
||||
const ui_mod = ui_dep.module("ui");
|
||||
ui_mod.addImport("zx", zx.zx_module);
|
||||
zx.addImport("ui", ui_mod);
|
||||
|
||||
const tailwindcss_b = tailwindcss.addBuild(b, .{
|
||||
.config = .{
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
.bunjs = .{ .path = "../pkg/plugin-bun" },
|
||||
.esbuild = .{ .path = "../pkg/plugin-esbuild" },
|
||||
.tailwindcss = .{ .path = "../pkg/plugin-tailwindcss" },
|
||||
.ui = .{ .path = "../pkg/ui" },
|
||||
},
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
|
||||
9
site/component/icon.zx
Normal file
9
site/component/icon.zx
Normal file
@ -0,0 +1,9 @@
|
||||
pub fn GitHub(allocator: zx.Allocator) zx.Component {
|
||||
return (
|
||||
<svg @{allocator} width="20" height="20" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
const zx = @import("zx");
|
||||
1
site/component/main.zx
Normal file
1
site/component/main.zx
Normal file
@ -0,0 +1 @@
|
||||
pub const icon = @import("icon.zx");
|
||||
70
src/build/TranslatedZx.zig
Normal file
70
src/build/TranslatedZx.zig
Normal file
@ -0,0 +1,70 @@
|
||||
const TranslatedZx = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
owner: *std.Build,
|
||||
run: *std.Build.Step.Run,
|
||||
output_dir: std.Build.LazyPath,
|
||||
out_basename: []const u8,
|
||||
mod_opts: std.Build.Module.CreateOptions,
|
||||
|
||||
pub const Options = struct {
|
||||
/// The `.zx` source file to transpile.
|
||||
root_source_file: std.Build.LazyPath,
|
||||
target: ?std.Build.ResolvedTarget = null,
|
||||
optimize: ?std.builtin.OptimizeMode = null,
|
||||
};
|
||||
|
||||
/// Create a `TranslatedZx` by running the host `zx transpile` CLI over
|
||||
/// `opts.root_source_file`.
|
||||
pub fn create(
|
||||
b: *std.Build,
|
||||
transpiler_exe: *std.Build.Step.Compile,
|
||||
opts: Options,
|
||||
) *TranslatedZx {
|
||||
const self = b.allocator.create(TranslatedZx) catch @panic("OOM");
|
||||
|
||||
const run = b.addRunArtifact(transpiler_exe);
|
||||
run.addArg("transpile");
|
||||
run.addDirectoryArg(opts.root_source_file);
|
||||
run.addArg("--outdir");
|
||||
const output_dir = run.addOutputDirectoryArg("components_gen");
|
||||
run.addArg("--dep-file");
|
||||
_ = run.addDepFileOutputArg("transpile.d");
|
||||
run.addArgs(&.{ "--map", "inline" });
|
||||
|
||||
const basename = opts.root_source_file.basename(b, &run.step);
|
||||
const ext = std.fs.path.extension(basename);
|
||||
const out_basename = b.fmt("{s}.zig", .{basename[0 .. basename.len - ext.len]});
|
||||
|
||||
run.setName(b.fmt("translate-zx {s}", .{basename}));
|
||||
|
||||
self.* = .{
|
||||
.owner = b,
|
||||
.run = run,
|
||||
.output_dir = output_dir,
|
||||
.out_basename = out_basename,
|
||||
.mod_opts = .{
|
||||
.root_source_file = output_dir.path(b, out_basename),
|
||||
.target = opts.target,
|
||||
.optimize = opts.optimize,
|
||||
},
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
/// The translated root `.zig` source file.
|
||||
pub fn getOutput(self: *TranslatedZx) std.Build.LazyPath {
|
||||
return self.output_dir.path(self.owner, self.out_basename);
|
||||
}
|
||||
|
||||
/// Create a private module from the translated source. The module has no `zx`
|
||||
/// import — add it afterwards, e.g. `mod.addImport("zx", zx_module)`.
|
||||
pub fn createModule(self: *TranslatedZx) *std.Build.Module {
|
||||
return self.owner.createModule(self.mod_opts);
|
||||
}
|
||||
|
||||
/// Like `createModule`, but exposes the module to dependent packages under `name`.
|
||||
pub fn addModule(self: *TranslatedZx, name: []const u8) *std.Build.Module {
|
||||
return self.owner.addModule(name, self.mod_opts);
|
||||
}
|
||||
@ -1,15 +1,14 @@
|
||||
const std = @import("std");
|
||||
const html_util = @import("../util/html.zig");
|
||||
const build_zig = @import("../../build.zig");
|
||||
pub const InitOptions = @import("init/InitOptions.zig");
|
||||
|
||||
const LazyPath = std.Build.LazyPath;
|
||||
const AddElementOptions = @import("../Build.zig").AddElementOptions;
|
||||
|
||||
pub const InitOptions = @import("init/InitOptions.zig");
|
||||
|
||||
pub fn init(b: *std.Build, exe: *std.Build.Step.Compile, options: InitOptions) !Build {
|
||||
const target = exe.root_module.resolved_target;
|
||||
const optimize = exe.root_module.optimize;
|
||||
const build_zig = @import("../../build.zig");
|
||||
const wasm_target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none });
|
||||
|
||||
const zx_dep = b.dependencyFromBuildZig(build_zig, .{
|
||||
@ -48,7 +47,6 @@ pub fn init(b: *std.Build, exe: *std.Build.Step.Compile, options: InitOptions) !
|
||||
.cli_path = null,
|
||||
.site_outdir = null,
|
||||
.steps = .default,
|
||||
.copy_embedded_sources = false,
|
||||
.client = options.client,
|
||||
.static_path = options.static_path,
|
||||
.ziex_js_dep = ziex_js_dep,
|
||||
@ -58,7 +56,6 @@ pub fn init(b: *std.Build, exe: *std.Build.Step.Compile, options: InitOptions) !
|
||||
|
||||
if (options.app) |site_opts| {
|
||||
opts.site_path = site_opts.path orelse opts.site_path;
|
||||
opts.copy_embedded_sources = site_opts.copy_embedded_sources;
|
||||
opts.base_path = site_opts.base_path;
|
||||
opts.features = site_opts.features;
|
||||
}
|
||||
@ -88,7 +85,6 @@ const InitInnerOptions = struct {
|
||||
cli_path: ?LazyPath,
|
||||
site_outdir: ?LazyPath,
|
||||
steps: InitOptions.CliOptions.Steps,
|
||||
copy_embedded_sources: bool,
|
||||
features: InitOptions.AppOptions.FeatureOptions = .default,
|
||||
client: InitOptions.ClientOptions,
|
||||
static_path: ?LazyPath,
|
||||
@ -303,9 +299,6 @@ pub fn initInner(
|
||||
transpile_cmd.addDirectoryArg(static_lazypath);
|
||||
transpile_cmd.addArg("--dep-file");
|
||||
_ = transpile_cmd.addDepFileOutputArg("transpile.d");
|
||||
if (opts.copy_embedded_sources) {
|
||||
transpile_cmd.addArg("--copy-embedded-sources");
|
||||
}
|
||||
if (opts.base_path) |bp| {
|
||||
transpile_cmd.addArgs(&.{ "--base-path", bp });
|
||||
}
|
||||
@ -623,6 +616,8 @@ pub fn initInner(
|
||||
|
||||
return .{
|
||||
.build = b,
|
||||
.zx_module = zx_module,
|
||||
.app = .{ .exe = exe, .module = app_module },
|
||||
.cmd = .{
|
||||
.transpile = transpile_cmd,
|
||||
},
|
||||
@ -661,6 +656,11 @@ pub const Build = struct {
|
||||
transpile: *std.Build.Step.Run,
|
||||
};
|
||||
|
||||
pub const App = struct {
|
||||
exe: *std.Build.Step.Compile,
|
||||
module: *std.Build.Module,
|
||||
};
|
||||
|
||||
/// Output transformer: injects elements into the generated output
|
||||
pub const Transformer = struct {
|
||||
b: *std.Build,
|
||||
@ -674,6 +674,13 @@ pub const Build = struct {
|
||||
|
||||
build: *std.Build,
|
||||
|
||||
/// The app's canonical `zx` module. Component modules created via
|
||||
/// `addComponent` are bound to this so the whole app shares one zx graph.
|
||||
zx_module: *std.Build.Module,
|
||||
|
||||
/// The app's root executable and generated `app` module.
|
||||
app: App,
|
||||
|
||||
cmd: BuildCommand,
|
||||
|
||||
outdir: LazyPath,
|
||||
@ -682,6 +689,32 @@ pub const Build = struct {
|
||||
cli: BuildZiex,
|
||||
|
||||
transformer: Transformer,
|
||||
|
||||
/// Transpile a `.zx` component file and return a Zig module wired to this
|
||||
/// app's canonical `zx` module.
|
||||
pub fn addComponent(self: Build, opts: build_zig.TranslatedZx.Options) *std.Build.Module {
|
||||
var component_opts = opts;
|
||||
// Inherit the app's target/optimize unless the caller overrode them.
|
||||
if (component_opts.target == null) component_opts.target = self.zx_module.resolved_target;
|
||||
if (component_opts.optimize == null) component_opts.optimize = self.zx_module.optimize;
|
||||
|
||||
const mod = build_zig.addTranslateZx(self.build, component_opts).createModule();
|
||||
mod.addImport("zx", self.zx_module);
|
||||
return mod;
|
||||
}
|
||||
|
||||
/// Like `addComponent`, but also imports the resulting module onto the app's
|
||||
/// root module and generated `app` module under `name`.
|
||||
pub fn addComponentImport(self: Build, name: []const u8, opts: build_zig.TranslatedZx.Options) void {
|
||||
const mod = self.addComponent(opts);
|
||||
self.addImport(name, mod);
|
||||
}
|
||||
|
||||
/// Add an import to app's root module and generated `app` module under `name`.
|
||||
pub fn addImport(self: Build, name: []const u8, mod: *std.Build.Module) void {
|
||||
self.app.exe.root_module.addImport(name, mod);
|
||||
self.app.module.addImport(name, mod);
|
||||
}
|
||||
};
|
||||
|
||||
const ServerOnlyStubMode = enum {
|
||||
|
||||
@ -79,18 +79,6 @@ pub const AppOptions = struct {
|
||||
/// If `null`, defaults to root path ("/").
|
||||
base_path: ?[]const u8 = null,
|
||||
|
||||
/// Copy embedded `.zx` source files to the transpile output directory.
|
||||
///
|
||||
/// When enabled, any `.zx` files referenced via `@embedFile` in your templates
|
||||
/// will be copied to the output directory alongside the generated `.zig` files,
|
||||
/// and the `@embedFile` paths will be updated to reference the local copies.
|
||||
///
|
||||
/// This is useful when you want to display source code examples in your app
|
||||
/// and need the files accessible within the package boundary.
|
||||
///
|
||||
/// Default: `false`
|
||||
copy_embedded_sources: bool = false,
|
||||
|
||||
/// Features that can be optionally enabled
|
||||
features: FeatureOptions = .default,
|
||||
};
|
||||
|
||||
@ -68,7 +68,7 @@ var g_dev_shutting_down: bool = false;
|
||||
fn onDevShutdown() void {
|
||||
if (g_dev_shutting_down) return;
|
||||
g_dev_shutting_down = true;
|
||||
std.debug.print("\n{s}Stopping dev server...{s}\n", .{ Colors.gray, Colors.reset });
|
||||
std.debug.print("\n{s}Stopping dev server...{s}", .{ Colors.gray, Colors.reset });
|
||||
if (comptime builtin.os.tag != .windows) {
|
||||
if (runner) |r| if (r.id) |pid| std.posix.kill(pid, std.posix.SIG.KILL) catch {};
|
||||
if (builder) |b| if (b.id) |pid| std.posix.kill(pid, std.posix.SIG.KILL) catch {};
|
||||
|
||||
@ -32,13 +32,6 @@ const map_flag = zli.Flag{
|
||||
.default_value = .{ .String = "none" },
|
||||
};
|
||||
|
||||
const copy_embedded_sources_flag = zli.Flag{
|
||||
.name = "copy-embedded-sources",
|
||||
.description = "Copy embedded .zx source files to output directory and rewrite paths",
|
||||
.type = .Bool,
|
||||
.default_value = .{ .Bool = false },
|
||||
};
|
||||
|
||||
const rootdir_flag = zli.Flag{
|
||||
.name = "rootdir",
|
||||
.description = "Root directory for the generated meta file (e.g., static dir)",
|
||||
@ -77,7 +70,6 @@ pub fn register(writer: *std.Io.Writer, reader: *std.Io.Reader, allocator: std.m
|
||||
try cmd.addFlag(copy_only_flag);
|
||||
try cmd.addFlag(flags.verbose_flag);
|
||||
try cmd.addFlag(map_flag);
|
||||
try cmd.addFlag(copy_embedded_sources_flag);
|
||||
try cmd.addFlag(rootdir_flag);
|
||||
try cmd.addFlag(depfile_flag);
|
||||
try cmd.addFlag(cachedir_flag);
|
||||
@ -96,7 +88,6 @@ fn transpile(ctx: zli.CommandContext) !void {
|
||||
const copy_only = ctx.flag("copy-only", bool);
|
||||
const verbose = ctx.flag("verbose", bool);
|
||||
const sourcemap_str = ctx.flag("map", []const u8);
|
||||
const copy_embedded_sources = ctx.flag("copy-embedded-sources", bool);
|
||||
const rootdir_str = ctx.flag("rootdir", []const u8);
|
||||
const rootdir: ?[]const u8 = if (rootdir_str.len > 0) rootdir_str else null;
|
||||
const depfile_str = ctx.flag("dep-file", []const u8);
|
||||
@ -145,7 +136,6 @@ fn transpile(ctx: zli.CommandContext) !void {
|
||||
.outdir = outdir,
|
||||
.verbose = verbose,
|
||||
.map = map,
|
||||
.copy_embedded_sources = copy_embedded_sources,
|
||||
.rootdir = rootdir,
|
||||
.dep_file = dep_file,
|
||||
.cache_dir = cache_dir,
|
||||
@ -230,7 +220,6 @@ fn transpile(ctx: zli.CommandContext) !void {
|
||||
.outdir = outdir,
|
||||
.verbose = verbose,
|
||||
.map = map,
|
||||
.copy_embedded_sources = copy_embedded_sources,
|
||||
.rootdir = rootdir,
|
||||
.dep_file = dep_file,
|
||||
.cache_dir = cache_dir,
|
||||
@ -269,46 +258,184 @@ fn writeDepFile(allocator: std.mem.Allocator, path: []const u8, target: []const
|
||||
try f.writePositionalAll(io, buf.items, 0);
|
||||
}
|
||||
|
||||
/// Scan source for `@embedFile("...")` references and add resolved paths as dependencies.
|
||||
// TODO: collect @import(...), only add .zig files to deps that are actually imported
|
||||
// TODO: also we should be able to collect the .zx dependancy tree and transpile the ones that is only used,
|
||||
// however that will make multi threading hard but we may do this in the future just to save transpilation time
|
||||
// currently transpilation takes ms for files in hundreds, but for larger project we may need to optimize this by only transpiling the used files
|
||||
fn collectEmbedFileDeps(
|
||||
/// Walk the transpiled Zig AST and, for each `@embedFile("...")` whose target
|
||||
/// exists on disk (relative to `source_dir`), copy it into the output dir at the
|
||||
/// same relative spelling (so the emitted `@embedFile` resolves at compile time)
|
||||
/// and record its absolute source path in `input_files` for the dep file.
|
||||
fn collectEmbedFiles(
|
||||
allocator: std.mem.Allocator,
|
||||
input_files: *std.array_list.Managed([]const u8),
|
||||
source: []const u8,
|
||||
ast: *const std.zig.Ast,
|
||||
source_dir: []const u8,
|
||||
out_dir: []const u8,
|
||||
) !void {
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
|
||||
for (0..ast.nodes.len) |i| {
|
||||
const node: std.zig.Ast.Node.Index = @enumFromInt(i);
|
||||
switch (ast.nodeTag(node)) {
|
||||
.builtin_call_two, .builtin_call_two_comma => {},
|
||||
else => continue,
|
||||
}
|
||||
if (!std.mem.eql(u8, ast.tokenSlice(ast.nodeMainToken(node)), "@embedFile")) continue;
|
||||
|
||||
const arg = ast.nodeData(node).opt_node_and_opt_node[0].unwrap() orelse continue;
|
||||
if (ast.nodeTag(arg) != .string_literal) continue;
|
||||
const raw = ast.tokenSlice(ast.nodeMainToken(arg));
|
||||
const embed_path = std.zig.string_literal.parseAlloc(allocator, raw) catch continue;
|
||||
defer allocator.free(embed_path);
|
||||
|
||||
const src = std.fs.path.join(allocator, &.{ source_dir, embed_path }) catch continue;
|
||||
defer allocator.free(src);
|
||||
|
||||
// Only act on embeds that exist as real source files on disk.
|
||||
if (std.Io.Dir.cwd().statFile(io, src, .{})) |_| {} else |_| continue;
|
||||
|
||||
// Copy into the output dir at the embed's relative spelling.
|
||||
const dst = std.fs.path.join(allocator, &.{ out_dir, embed_path }) catch continue;
|
||||
defer allocator.free(dst);
|
||||
if (std.fs.path.dirname(dst)) |parent| {
|
||||
std.Io.Dir.cwd().createDirPath(io, parent) catch {};
|
||||
}
|
||||
std.Io.Dir.cwd().copyFile(src, std.Io.Dir.cwd(), dst, io, .{}) catch |err| {
|
||||
std.debug.print("Warning: Could not copy embedded file {s}: {}\n", .{ src, err });
|
||||
};
|
||||
|
||||
const abs = std.fs.path.resolve(allocator, &.{src}) catch continue;
|
||||
input_files.append(abs) catch allocator.free(abs);
|
||||
}
|
||||
}
|
||||
|
||||
/// Re-run the `@embedFile` copy for a cached `.zx`/`.mdzx` whose transpilation was
|
||||
/// skipped. On a cache hit `transpileFile` (and thus `collectEmbedFiles`) never runs
|
||||
fn copyEmbedsForCached(
|
||||
allocator: std.mem.Allocator,
|
||||
input_files: *std.array_list.Managed([]const u8),
|
||||
zig_path: []const u8,
|
||||
source_dir: []const u8,
|
||||
out_dir: []const u8,
|
||||
) !void {
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
const zig_src = try std.Io.Dir.cwd().readFileAlloc(
|
||||
io,
|
||||
zig_path,
|
||||
allocator,
|
||||
std.Io.Limit.limited(std.math.maxInt(usize)),
|
||||
);
|
||||
defer allocator.free(zig_src);
|
||||
|
||||
const zig_src_z = try allocator.dupeSentinel(u8, zig_src, 0);
|
||||
defer allocator.free(zig_src_z);
|
||||
|
||||
var ast = try std.zig.Ast.parse(allocator, zig_src_z, .zig);
|
||||
defer ast.deinit(allocator);
|
||||
|
||||
try collectEmbedFiles(allocator, input_files, &ast, source_dir, out_dir);
|
||||
}
|
||||
|
||||
/// Walk the transpiled Zig AST (`ast`, already produced by `core_lang.Ast.parse`)
|
||||
/// and append each `@import("...")` target that resolves to an existing
|
||||
/// `.zx`/`.mdzx` source (relative to `source_dir`) to `out`.
|
||||
fn collectZxImports(
|
||||
allocator: std.mem.Allocator,
|
||||
out: *std.array_list.Managed([]const u8),
|
||||
ast: *const std.zig.Ast,
|
||||
source_dir: []const u8,
|
||||
) !void {
|
||||
const needle = "@embedFile(\"";
|
||||
var pos: usize = 0;
|
||||
while (std.mem.indexOfPos(u8, source, pos, needle)) |start| {
|
||||
const path_start = start + needle.len;
|
||||
const path_end = std.mem.indexOfPos(u8, source, path_start, "\"") orelse break;
|
||||
const embed_path = source[path_start..path_end];
|
||||
pos = path_end + 1;
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
|
||||
const resolved = std.fs.path.join(allocator, &.{ source_dir, embed_path }) catch continue;
|
||||
defer allocator.free(resolved);
|
||||
for (0..ast.nodes.len) |i| {
|
||||
const node: std.zig.Ast.Node.Index = @enumFromInt(i);
|
||||
switch (ast.nodeTag(node)) {
|
||||
.builtin_call_two, .builtin_call_two_comma => {},
|
||||
else => continue,
|
||||
}
|
||||
|
||||
const abs_path = std.fs.path.resolve(allocator, &.{resolved}) catch continue;
|
||||
const main_tok = ast.nodeMainToken(node);
|
||||
if (!std.mem.eql(u8, ast.tokenSlice(main_tok), "@import")) continue;
|
||||
|
||||
// Only record embeds that actually exist on disk. .zx files often
|
||||
// @embedFile() the transpiled .zig output of a sibling .zx — that
|
||||
// file doesn't exist as a source and listing it in the dep file
|
||||
// makes the build harness fail with FileNotFound.
|
||||
const io_local = std.Io.Threaded.global_single_threaded.io();
|
||||
if (std.Io.Dir.cwd().statFile(io_local, abs_path, .{})) |_| {
|
||||
input_files.append(abs_path) catch {
|
||||
allocator.free(abs_path);
|
||||
// First argument: the import path string literal.
|
||||
const arg = ast.nodeData(node).opt_node_and_opt_node[0].unwrap() orelse continue;
|
||||
if (ast.nodeTag(arg) != .string_literal) continue;
|
||||
const raw = ast.tokenSlice(ast.nodeMainToken(arg));
|
||||
const import_path = std.zig.string_literal.parseAlloc(allocator, raw) catch continue;
|
||||
defer allocator.free(import_path);
|
||||
|
||||
// Map the rewritten `.zig` target back to its `.zx`/`.mdzx` source. Plain
|
||||
// `@import("std")` / module imports have no extension and are skipped.
|
||||
const stem = if (std.mem.endsWith(u8, import_path, ".zig"))
|
||||
import_path[0 .. import_path.len - ".zig".len]
|
||||
else if (std.mem.endsWith(u8, import_path, ".zx"))
|
||||
import_path[0 .. import_path.len - ".zx".len]
|
||||
else if (std.mem.endsWith(u8, import_path, ".mdzx"))
|
||||
import_path[0 .. import_path.len - ".mdzx".len]
|
||||
else
|
||||
continue;
|
||||
|
||||
for ([_][]const u8{ ".zx", ".mdzx" }) |ext| {
|
||||
const cand = std.fmt.allocPrint(allocator, "{s}{s}", .{ stem, ext }) catch continue;
|
||||
const resolved = std.fs.path.join(allocator, &.{ source_dir, cand }) catch {
|
||||
allocator.free(cand);
|
||||
continue;
|
||||
};
|
||||
} else |_| {
|
||||
allocator.free(abs_path);
|
||||
defer allocator.free(resolved);
|
||||
if (std.Io.Dir.cwd().statFile(io, resolved, .{})) |_| {
|
||||
// Return the import spelling relative to source_dir (e.g. `icon.zx`).
|
||||
out.append(cand) catch allocator.free(cand);
|
||||
break;
|
||||
} else |_| allocator.free(cand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transpile `source_path` into `output_path`, then recursively transpile every
|
||||
/// `.zx`/`.mdzx` file it `@import`s (resolved relative to the importing file)
|
||||
/// into the same `outdir`.
|
||||
fn transpileFileRecursive(
|
||||
allocator: std.mem.Allocator,
|
||||
global_components: *std.array_list.Managed(ClientComponentSerializable),
|
||||
opts: TranspileOptions,
|
||||
source_path: []const u8,
|
||||
output_path: []const u8,
|
||||
visited: *std.StringHashMap(void),
|
||||
input_files: *std.array_list.Managed([]const u8),
|
||||
) !void {
|
||||
const abs_source = std.fs.path.resolve(allocator, &.{source_path}) catch
|
||||
try allocator.dupe(u8, source_path);
|
||||
if (visited.contains(abs_source)) {
|
||||
allocator.free(abs_source);
|
||||
return;
|
||||
}
|
||||
// `visited` owns abs_source; also record it as a dep file input.
|
||||
try visited.put(abs_source, {});
|
||||
try input_files.append(try allocator.dupe(u8, abs_source));
|
||||
|
||||
// Transpile this file, collecting its `.zx` imports from the parsed AST.
|
||||
var imports = std.array_list.Managed([]const u8).init(allocator);
|
||||
defer {
|
||||
for (imports.items) |p| allocator.free(p);
|
||||
imports.deinit();
|
||||
}
|
||||
try transpileFile(allocator, global_components, opts, source_path, output_path, &imports, input_files);
|
||||
|
||||
const source_dir = std.fs.path.dirname(source_path) orelse ".";
|
||||
const out_dir = std.fs.path.dirname(output_path) orelse opts.outdir;
|
||||
|
||||
for (imports.items) |rel| {
|
||||
const dep_source = try std.fs.path.join(allocator, &.{ source_dir, rel });
|
||||
defer allocator.free(dep_source);
|
||||
|
||||
const ext_len: usize = if (std.mem.endsWith(u8, rel, ".mdzx")) ".mdzx".len else ".zx".len;
|
||||
const out_rel = try std.mem.concat(allocator, u8, &.{ rel[0 .. rel.len - ext_len], ".zig" });
|
||||
defer allocator.free(out_rel);
|
||||
|
||||
const dep_output = try std.fs.path.join(allocator, &.{ out_dir, out_rel });
|
||||
defer allocator.free(dep_output);
|
||||
|
||||
try transpileFileRecursive(allocator, global_components, opts, dep_source, dep_output, visited, input_files);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Component Cache (per-file incremental) ---- //
|
||||
|
||||
fn writeComponentCache(
|
||||
@ -1292,6 +1419,8 @@ fn transpileFile(
|
||||
opts: TranspileOptions,
|
||||
source_path: []const u8,
|
||||
output_path: []const u8,
|
||||
imports_out: ?*std.array_list.Managed([]const u8),
|
||||
input_files: *std.array_list.Managed([]const u8),
|
||||
) !void {
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
const source = try std.Io.Dir.cwd().readFileAlloc(
|
||||
@ -1326,6 +1455,16 @@ fn transpileFile(
|
||||
});
|
||||
defer result.deinit(allocator);
|
||||
|
||||
const ast_source_dir = std.fs.path.dirname(source_path) orelse ".";
|
||||
if (imports_out) |out| {
|
||||
try collectZxImports(allocator, out, &result.zig_ast, ast_source_dir);
|
||||
}
|
||||
// Auto-copy any files this component `@embedFile`s into the output dir.
|
||||
{
|
||||
const ast_out_dir = std.fs.path.dirname(output_path) orelse opts.outdir;
|
||||
try collectEmbedFiles(allocator, input_files, &result.zig_ast, ast_source_dir, ast_out_dir);
|
||||
}
|
||||
|
||||
// Extract route from source path
|
||||
const component_route = try extractRouteFromPath(allocator, relative_source_path);
|
||||
defer allocator.free(component_route);
|
||||
@ -1525,18 +1664,12 @@ fn transpileDirectory(
|
||||
const output_path = try std.fs.path.join(allocator, &.{ opts.outdir, output_rel_path });
|
||||
defer allocator.free(output_path);
|
||||
|
||||
// Track this input for the dep file (absolute path for Make format)
|
||||
// Track this input for the dep file (absolute path for Make format).
|
||||
// Embedded-file deps are collected by `transpileFile` via the AST.
|
||||
const abs_input = std.fs.path.resolve(allocator, &.{input_path}) catch
|
||||
try allocator.dupe(u8, input_path);
|
||||
try input_files.append(abs_input);
|
||||
|
||||
// Scan for @embedFile references and track them as dependencies
|
||||
const source_dir = std.fs.path.dirname(input_path) orelse ".";
|
||||
if (std.Io.Dir.cwd().readFileAlloc(io, input_path, allocator, std.Io.Limit.limited(4 * 1024 * 1024))) |source| {
|
||||
defer allocator.free(source);
|
||||
try collectEmbedFileDeps(allocator, input_files, source, source_dir);
|
||||
} else |_| {}
|
||||
|
||||
const cache_base = opts.cache_dir orelse opts.outdir;
|
||||
const cache_out_path = try std.fs.path.join(allocator, &.{ cache_base, output_rel_path });
|
||||
defer allocator.free(cache_out_path);
|
||||
@ -1565,10 +1698,19 @@ fn transpileDirectory(
|
||||
std.debug.print("Warning: Failed to copy cached file {s} to {s}: {}\n", .{ cache_out_path, output_path, err });
|
||||
};
|
||||
}
|
||||
// Transpilation was skipped, so `collectEmbedFiles` never ran for
|
||||
// this file. Replay the `@embedFile` copy from the cached `.zig`
|
||||
{
|
||||
const embed_src_dir = std.fs.path.dirname(input_path) orelse ".";
|
||||
const embed_out_dir = std.fs.path.dirname(output_path) orelse opts.outdir;
|
||||
copyEmbedsForCached(allocator, input_files, cache_out_path, embed_src_dir, embed_out_dir) catch |err| {
|
||||
std.debug.print("Warning: Failed to copy embedded files for cached {s}: {}\n", .{ input_path, err });
|
||||
};
|
||||
}
|
||||
if (opts.verbose) std.debug.print("Skipped (up-to-date): {s}\n", .{input_path});
|
||||
} else {
|
||||
const components_before = global_components.items.len;
|
||||
transpileFile(allocator, global_components, opts, input_path, output_path) catch |err| {
|
||||
transpileFile(allocator, global_components, opts, input_path, output_path, null, input_files) catch |err| {
|
||||
global_components.items.len = components_before;
|
||||
std.debug.print("Error transpiling {s}: {}\n", .{ input_path, err });
|
||||
continue;
|
||||
@ -1587,28 +1729,6 @@ fn transpileDirectory(
|
||||
std.debug.print("Warning: Failed to write component cache for {s}: {}\n", .{ input_path, err });
|
||||
};
|
||||
}
|
||||
|
||||
// Also copy the original .zx file if copy_embedded_sources is enabled
|
||||
if (opts.copy_embedded_sources) {
|
||||
const zx_output_path = try std.fs.path.join(allocator, &.{ opts.outdir, entry.path });
|
||||
defer allocator.free(zx_output_path);
|
||||
|
||||
if (std.fs.path.dirname(zx_output_path)) |parent| {
|
||||
std.Io.Dir.cwd().createDirPath(io, parent) catch |err| switch (err) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => {
|
||||
std.debug.print("Error creating directory {s}: {}\n", .{ parent, err });
|
||||
continue;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
std.Io.Dir.cwd().copyFile(input_path, std.Io.Dir.cwd(), zx_output_path, io, .{}) catch |err| {
|
||||
std.debug.print("Warning: Could not copy .zx source {s}: {}\n", .{ input_path, err });
|
||||
continue;
|
||||
};
|
||||
if (opts.verbose) std.debug.print("Copied source: {s} -> {s}\n", .{ input_path, zx_output_path });
|
||||
}
|
||||
} else {
|
||||
// Copy all non-.zx files from the site directory, excluding reserved files
|
||||
const basename = getBasename(entry.path);
|
||||
@ -1666,7 +1786,6 @@ const TranspileOptions = struct {
|
||||
outdir: []const u8,
|
||||
verbose: bool,
|
||||
map: core_lang.Ast.ParseOptions.MapMode = .none,
|
||||
copy_embedded_sources: bool = false,
|
||||
rootdir: ?[]const u8 = null,
|
||||
dep_file: ?[]const u8 = null,
|
||||
cache_dir: ?[]const u8 = null,
|
||||
@ -1738,7 +1857,13 @@ fn transpileCommand(allocator: std.mem.Allocator, opts: TranspileOptions) !void
|
||||
const outpath = try std.fs.path.join(allocator, &.{ opts.outdir, output_rel_path });
|
||||
defer allocator.free(outpath);
|
||||
|
||||
try transpileFile(allocator, &all_client_cmps, opts, opts.path, outpath);
|
||||
var visited = std.StringHashMap(void).init(allocator);
|
||||
defer {
|
||||
var it = visited.keyIterator();
|
||||
while (it.next()) |k| allocator.free(k.*);
|
||||
visited.deinit();
|
||||
}
|
||||
try transpileFileRecursive(allocator, &all_client_cmps, opts, opts.path, outpath, &visited, &input_files);
|
||||
task.completeOne();
|
||||
},
|
||||
else => {
|
||||
@ -1755,8 +1880,9 @@ fn transpileCommand(allocator: std.mem.Allocator, opts: TranspileOptions) !void
|
||||
}
|
||||
|
||||
// Generate routes
|
||||
genRoutes(allocator, opts.outdir, opts.rootdir, opts.base_path, opts.verbose) catch |err| {
|
||||
std.debug.print("Warning: Failed to generate meta.zig: {}\n", .{err});
|
||||
genRoutes(allocator, opts.outdir, opts.rootdir, opts.base_path, opts.verbose) catch |err| switch (err) {
|
||||
error.NoPagesOrRoutes => {}, // No routes to generate is not an error
|
||||
else => std.debug.print("Warning: Failed to generate meta.zig: {}\n", .{err}),
|
||||
};
|
||||
|
||||
// --- @rendering -> Client Side Rendering Related Files Generation --- //
|
||||
|
||||
@ -63,7 +63,8 @@ pub fn parse(gpa: std.mem.Allocator, zx_source: [:0]const u8, options: ParseOpti
|
||||
errdefer diagnostics.deinit();
|
||||
|
||||
const render_result = try parse_result.renderAlloc(arena, .{ .mode = .zig, .sourcemap = options.map.enabled(), .path = options.path });
|
||||
var zig_ast = try std.zig.Ast.parse(gpa, try arena.dupeSentinel(u8, render_result.source, 0), .zig);
|
||||
const zx_sourcez = try gpa.dupeSentinel(u8, render_result.source, 0);
|
||||
var zig_ast = try std.zig.Ast.parse(gpa, zx_sourcez, .zig);
|
||||
const zig_sourcez = try arena.dupeSentinel(u8, if (zig_ast.errors.len == 0) try zig_ast.renderAlloc(arena) else render_result.source, 0);
|
||||
|
||||
var components = std.ArrayList(ClientComponentMetadata).empty;
|
||||
@ -86,7 +87,7 @@ pub fn parse(gpa: std.mem.Allocator, zx_source: [:0]const u8, options: ParseOpti
|
||||
|
||||
return ParseResult{
|
||||
.zig_ast = zig_ast,
|
||||
.zx_source = try gpa.dupeSentinel(u8, render_result.source, 0),
|
||||
.zx_source = zx_sourcez,
|
||||
.zig_source = try gpa.dupeSentinel(u8, zig_sourcez, 0),
|
||||
.client_components = components,
|
||||
.sourcemap = result_sourcemap,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user