fluent-transpiler
Version:
Transpile Fluent (ftl) files into optimized, tree-shakable, JavaScript EcmaScript Modules (esm).
93 lines (88 loc) • 2.43 kB
JavaScript
// Copyright 2026 will Farrell, and fluent-transpiler contributors.
// SPDX-License-Identifier: MIT
import { stat, writeFile } from "node:fs/promises";
import { Command, Option } from "commander";
import { compileFiles } from "./index.js";
const fileExists = async (filepath) => {
const stats = await stat(filepath);
if (!stats.isFile()) {
throw new Error(`${filepath} is not a file`);
}
};
new Command()
.name("ftl")
.description("Compile Fluent (.ftl) files to JavaScript (.js or .mjs)")
.argument(
"<inputs...>",
"Paths to the Fluent file(s) to compile. Multiple files are joined in order; ids must be unique across the set.",
)
.requiredOption(
"--locale <locale...>",
"What locale(s) to be used. Multiple can be set to allow for fallback. i.e. en-CA",
)
.addOption(
new Option("--comments", "Include comments in output file.").preset(true),
)
.addOption(
new Option(
"--include-key <includeMessageKey...>",
"Allowed messages to be included. Default to include all.",
),
)
.addOption(
new Option(
"--exclude-key <excludeMessageKey...>",
"Ignored messages to be excluded. Default to exclude none.",
),
)
.addOption(
new Option(
"--exclude-value <excludeMessageValue>",
"Set message to an empty string when it contains this value. Default to not allowing empty strings.",
),
)
.addOption(
new Option(
"--variable-notation <variableNotation>",
"What variable notation to use with exports",
)
.choices(["camelCase", "pascalCase", "constantCase", "snakeCase"])
.default("camelCase"),
)
.addOption(
new Option(
"--disable-minify",
"If disabled, all exported messages will have the same interface `(params) => ({value, attributes})`.",
).preset(true),
)
.addOption(
new Option(
"--use-isolating",
"Wrap placeable with \\u2068 and \\u2069.",
).preset(true),
)
.addOption(
new Option(
"-o, --output <output>",
"Path to store the resulting JavaScript file. Will be in ESM.",
),
)
.action(async (inputs, options) => {
options.comments = options.comments ?? false;
try {
for (const input of inputs) {
await fileExists(input);
}
const js = await compileFiles(inputs, options);
if (options.output) {
await writeFile(options.output, js, "utf8");
} else {
console.log(js);
}
} catch (e) {
console.error(`Error: ${e.message}`);
process.exit(1);
}
})
.parse();