Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(cli/init): deduplicate asset creation logic #16294

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
File renamed without changes.
File renamed without changes.
97 changes: 65 additions & 32 deletions src/cli/init_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,57 @@ pub const InitCommand = struct {
}
}

const default_gitignore = @embedFile("gitignore-for-init");
const default_tsconfig = @embedFile("tsconfig-for-init.json");
const README = @embedFile("README-for-init.md");
const Assets = struct {
// "known" assets
const @".gitignore" = @embedFile("init/gitignore.default");
const @"tsconfig.json" = @embedFile("init/tsconfig.default.json");
const @"README.md" = @embedFile("init/README.default.md");

/// Create a new asset file, overriding anything that already exists. Known
/// assets will have their contents pre-populated; otherwise the file will be empty.
fn create(comptime asset_name: []const u8, args: anytype) !void {
const is_template = comptime (@TypeOf(args) != @TypeOf(null)) and @typeInfo(@TypeOf(args)).Struct.fields.len > 0;
return createFull(asset_name, asset_name, "", is_template, args);
}

fn createNew(filename: []const u8, contents: []const u8) !void {
var file = try std.fs.cwd().createFile(filename, .{ .truncate = true });
defer file.close();
try file.writeAll(contents);

Output.prettyln(" + <r><d>{s}<r>", .{filename});
Output.flush();
}

fn createFull(
/// name of possibly-existing asset
comptime asset_name: []const u8,
/// name of asset file to create
filename: []const u8,
/// optionally add a suffix to the end of the `+ filename` message. Must have a leading space.
comptime message_suffix: []const u8,
/// Treat the asset as a format string, using `args` to populate it. Only applies to known assets.
comptime is_template: bool,
/// Format arguments
args: anytype,
) !void {
var file = try std.fs.cwd().createFile(filename, .{ .truncate = true });
defer file.close();

// Write contents of known assets to the new file. Template assets get formatted.
if (comptime @hasDecl(Assets, asset_name)) {
const asset = @field(Assets, asset_name);
if (comptime is_template) {
try file.writer().print(asset, args);
} else {
try file.writeAll(asset);
}
}

Output.prettyln(" + <r><d>{s}{s}<r>", .{ filename, message_suffix });
Output.flush();
}
};

// TODO: unicode case folding
fn normalizePackageName(allocator: std.mem.Allocator, input: []const u8) ![]const u8 {
Expand Down Expand Up @@ -381,21 +429,15 @@ pub const InitCommand = struct {
}
}

var entry = try cwd.createFile(fields.entry_point, .{ .truncate = true });
entry.writeAll("console.log(\"Hello via Bun!\");") catch {};
entry.close();
Output.prettyln(" + <r><d>{s}<r>", .{fields.entry_point});
Output.flush();
Assets.createNew(fields.entry_point, "console.log(\"Hello via Bun!\");") catch {
// suppress
};
}

if (steps.write_gitignore) {
brk: {
var file = std.fs.cwd().createFileZ(".gitignore", .{ .truncate = true }) catch break :brk;
defer file.close();
file.writeAll(default_gitignore) catch break :brk;
Output.prettyln(" + <r><d>.gitignore<r>", .{});
Output.flush();
}
Assets.create(".gitignore", .{}) catch {
// suppressed
};
}

if (steps.write_tsconfig) {
Expand All @@ -406,27 +448,18 @@ pub const InitCommand = struct {
"tsconfig.json"
else
"jsconfig.json";
var file = std.fs.cwd().createFileZ(filename, .{ .truncate = true }) catch break :brk;
defer file.close();
file.writeAll(default_tsconfig) catch break :brk;
Output.prettyln(" + <r><d>{s}<r><d> (for editor auto-complete)<r>", .{filename});
Output.flush();
Assets.createFull("tsconfig.json", filename, " (for editor autocomplete)", false, .{}) catch break :brk;
}
}

if (steps.write_readme) {
brk: {
const filename = "README.md";
var file = std.fs.cwd().createFileZ(filename, .{ .truncate = true }) catch break :brk;
defer file.close();
file.writer().print(README, .{
.name = fields.name,
.bunVersion = Environment.version_string,
.entryPoint = fields.entry_point,
}) catch break :brk;
Output.prettyln(" + <r><d>{s}<r>", .{filename});
Output.flush();
}
Assets.create("README.md", .{
.name = fields.name,
.bunVersion = Environment.version_string,
.entryPoint = fields.entry_point,
}) catch {
// suppressed
};
}

if (fields.entry_point.len > 0) {
Expand Down
Loading