85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
/*!
|
|
* This script generates the interface `CCAPIs` in `src/lib/commandclass/API.ts`
|
|
* which is used to strongly-type the simplified API exposed via
|
|
* `ZWaveNode.commandClasses.xyz`
|
|
*/
|
|
|
|
import { formatWithDprint } from "@zwave-js/maintenance";
|
|
import esMain from "es-main";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
const apiRegex = /^@API\(CommandClasses(?:\.|\[)(.+?)(?:\])?\)/m;
|
|
const valuesDefinitionRegex = /export const ([^\s]+CCValues) =/;
|
|
const ccDir = path.join(__dirname, "..", "src/cc");
|
|
const libDir = path.join(__dirname, "..", "src/lib");
|
|
const valuesFile = path.join(libDir, "Values.ts");
|
|
|
|
const startTokenInterface = "\t// AUTO GENERATION BELOW";
|
|
const endTokenInterface = "}";
|
|
|
|
process.on("unhandledRejection", (r) => {
|
|
throw r;
|
|
});
|
|
|
|
export async function generateCCValuesInterface(): Promise<void> {
|
|
const ccFiles = (await fs.readdir(ccDir)).filter(
|
|
(file) => file.endsWith(".ts") && !file.endsWith("test.ts"),
|
|
);
|
|
|
|
const CCsWithValues: { name: string; className: string; file: string }[] =
|
|
[];
|
|
|
|
for (const ccFile of ccFiles) {
|
|
const fileContent = await fs.readFile(path.join(ccDir, ccFile), "utf8");
|
|
// Extract the CC name from e.g. `@API(CommandClasses["Binary Sensor"])`
|
|
const apiMatch = apiRegex.exec(fileContent);
|
|
// Extract the class name from e.g. `export class BasicCCAPI extends CCAPI`
|
|
const classMatch = valuesDefinitionRegex.exec(fileContent);
|
|
if (apiMatch && classMatch) {
|
|
CCsWithValues.push({
|
|
file: ccFile.replace(/\.ts$/, ".js"),
|
|
name: apiMatch[1],
|
|
className: classMatch[1],
|
|
});
|
|
}
|
|
}
|
|
|
|
console.log(`Found ${CCsWithValues.length} CC value definitions...`);
|
|
|
|
const originalValuesFileContent = await fs.readFile(valuesFile, "utf8");
|
|
let valuesFileContent = originalValuesFileContent;
|
|
|
|
// Generate interface
|
|
const startTokenEnd = valuesFileContent.indexOf(startTokenInterface)
|
|
+ startTokenInterface.length;
|
|
const endTokenStart = valuesFileContent.indexOf(
|
|
endTokenInterface,
|
|
startTokenEnd,
|
|
);
|
|
valuesFileContent = valuesFileContent.slice(0, startTokenEnd)
|
|
+ "\n"
|
|
+ CCsWithValues.map(
|
|
({ name, className, file }) =>
|
|
`\t${name}: typeof import("${
|
|
path
|
|
.relative(libDir, ccDir)
|
|
.replaceAll("\\", "/")
|
|
}/${file}").${className};`,
|
|
).join("\n")
|
|
+ "\n"
|
|
+ valuesFileContent.slice(endTokenStart);
|
|
|
|
valuesFileContent = formatWithDprint(valuesFile, valuesFileContent);
|
|
// Only update file if necessary - this reduces build time
|
|
if (valuesFileContent !== originalValuesFileContent) {
|
|
console.log("API interface changed");
|
|
await fs.writeFile(valuesFile, valuesFileContent, "utf8");
|
|
}
|
|
}
|
|
|
|
if (esMain(import.meta)) void generateCCValuesInterface();
|