Last active
May 17, 2025 18:31
-
-
Save adamscott/aaa94b8f722c97c1f50f7ae3e3164889 to your computer and use it in GitHub Desktop.
Get file with macro processed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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