Skip to content

Instantly share code, notes, and snippets.

@adamscott
Last active May 17, 2025 18:31
Show Gist options
  • Save adamscott/aaa94b8f722c97c1f50f7ae3e3164889 to your computer and use it in GitHub Desktop.
Save adamscott/aaa94b8f722c97c1f50f7ae3e3164889 to your computer and use it in GitHub Desktop.
Get file with macro processed
import { existsSync } from "node:fs";
import { open, writeFile } from "node:fs/promises";
import * as path from "node:path";
import { parseArgs } from "node:util";
import { runInContext, createContext } from "node:vm";
const VERSION = "0.0.1";
const EMSCRIPTEN_INTERPOLATION_REGEX = /\{\{\{(.+?)\}\}\}/msu;
/** @type {import("node:util").ParseArgsOptionsConfig} */
const argOptions = {
help: {
type: "boolean",
default: false,
short: "h",
description: "Summons help",
},
version: {
type: "boolean",
default: false,
short: "v",
description: "Returns the version number",
},
verbose: {
type: "boolean",
default: false,
short: "V",
description: "Enable verbosity",
},
"emscripten-path": {
type: "string",
default: undefined,
description: "Emscripten path",
},
"emscripten-settings": {
type: "string",
description: "Enable emscripten interpolation support",
},
file: {
type: "string",
},
};
/** @type {() => ReturnType<typeof parseArgs>} */
function getArgs() {
return parseArgs({
args: process.args,
options: argOptions,
strict: true,
allowPositionals: true,
});
}
/** @type {(args: ReturnType<typeof parseArgs>) => void} */
function processArgs(args) {
const processBasename = path.basename(path.resolve(import.meta.url));
const printArgName = (name, short = null) => {
let printValue = "";
if (short != null) {
printValue += `-${short}, `;
}
printValue += `--${name}`;
return printValue;
};
const printVersion = () => {
console.log(`${processBasename} ${VERSION}`);
};
// Version.
if (args.values.version) {
printVersion();
process.exit(0);
}
// Help.
if (args.values.help) {
printVersion();
const positionals = Object.entries(argOptions).filter(
([_key, value]) => !("default" in value),
);
let command = processBasename;
for (const [key, _value] of positionals) {
command += ` <${key}>`;
}
console.log(command);
const nonPositionals = Object.entries(argOptions).filter(
([_key, value]) => "default" in value,
);
for (const [key, value] of nonPositionals) {
console.log(
`${printArgName(key, value.short)}: ${value.description}`,
);
}
process.exit(0);
}
// Check positional args.
const numberOfPositionalArgs = Object.entries(argOptions).filter(
([_key, value]) => !("default" in value),
).length;
if (args.positionals.length != numberOfPositionalArgs) {
if (args.positionals.length == 0) {
console.error("Positional argument <emscripten-settings> missing.");
} else if (args.positionals.length == 1) {
console.error("Positional argument <file> missing.");
} else {
console.error("Too many positional arguments.");
}
process.exit(1);
}
}
/** @type {(options: { settings: string, file: string, emscriptenPath?: string, emscriptenSettings?: string }) => Promise<void>} */
async function parseFile(options) {
let { file, emscriptenPath, emscriptenSettings } = options;
if (!existsSync(file)) {
console.error(`"${file}" doesn't exist.`);
process.exit(1);
}
const fileHandle = await open(file, "r");
const fileContents = await fileHandle.readFile({ encoding: "utf-8" });
await fileHandle.close();
if (emscriptenPath == null) {
console.error("--emscripten-path has not been set.");
process.exit(1);
}
emscriptenPath = emscriptenPath.replace("~", process.env.HOME);
const { loadDefaultSettings, addToCompileTimeContext } = await import(
path.resolve(emscriptenPath, "src/utility.mjs")
);
loadDefaultSettings();
const { processMacros, preprocess } = await import(
path.resolve(emscriptenPath, "src/parseTools.mjs")
);
const settingsHandle = await open(emscriptenSettings, "r");
const settingsContents = await settingsHandle.readFile({
encoding: "utf-8",
});
const settingsJson = JSON.parse(settingsContents);
addToCompileTimeContext(settingsJson);
const processedMacrosFileContents = processMacros(fileContents, file);
const fileExt = path.extname(file);
const fileDir = path.dirname(file);
const fileName = path.basename(file, fileExt);
const preprocessedFile = path.resolve(
fileDir,
`${fileName}.preprocessed${fileExt}`,
);
await writeFile(preprocessedFile, processedMacrosFileContents, {
encoding: "utf-8",
});
const preprocessedFileContents = preprocess(preprocessedFile);
console.log(preprocessedFileContents);
process.exit(0);
}
/** @type {() => Promise<void>} */
async function main() {
const args = getArgs();
processArgs(args);
await parseFile({
emscriptenSettings: args.positionals[0],
file: args.positionals[1],
emscriptenPath: args.values["emscripten-path"],
});
}
try {
await main();
} catch (err) {
console.error(err);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment