UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

337 lines (320 loc) 9.01 kB
/* eslint-disable @typescript-eslint/no-floating-promises */ require("reflect-metadata"); import { CommandClasses } from "@zwave-js/core"; import { num2hex } from "@zwave-js/shared"; import * as c from "ansi-colors"; import * as clipboard from "clipboardy"; import * as fs from "fs-extra"; import * as path from "path"; import * as yargs from "yargs"; const ccRegex = /^@commandClass\(CommandClasses(?:\.|\[")(.+?)(?:"\])?\)/m; const versionRegex = /^@implementedVersion\((\d+)\)/m; const apiRegex = /^@API\(CommandClasses(?:\.|\[)(.+?)(?:\])?\)/m; const noApiRegex = /^\/\/ @noAPI/m; // This comment marks a CC that needs no API const setValueApiRegex = /^\tprotected \[SET_VALUE\]/m; const noSetValueApiRegex = /^\/\/ @noSetValueAPI/m; // This comment marks a CC that needs no setValue API const interviewRegex = /^\tpublic async interview/m; const noInterviewRegex = /^\/\/ @noInterview/m; // This comment marks a CC that needs no interview procedure const pollValueApiRegex = /^\tprotected \[POLL_VALUE\]/m; const noPollValueApiRegex = /^\/\/ @noPollValueAPI/m; // This comment marks a CC that needs no pollValue API const argv = yargs.parseSync(); const onlyIncomplete = !!argv.onlyIncomplete; function getSafeLength(str: string): number { return c.stripColor(str).length; } function padEnd(str: string, len: number): string { return str + " ".repeat(len - getSafeLength(str)); } interface CCInfo { version: number; API: boolean; setValue: boolean; pollValue: boolean; interview: boolean; } (async () => { const ccDir = path.join(__dirname, "../..", "cc/src/cc"); const ccFiles = (await fs.readdir(ccDir)) .filter((file) => file.endsWith(".ts") && !file.endsWith("test.ts")) .map((file) => path.join(ccDir, file)); const allCCs = new Map<string, CCInfo>( Object.keys(CommandClasses) .filter((cc) => Number.isNaN(+cc)) .map((name) => [ name, { version: 0, API: false, setValue: false, pollValue: false, interview: false, }, ]), ); for (const ccFile of ccFiles) { const fileContent = await fs.readFile(ccFile, "utf8"); try { const ccName = ccRegex.exec(fileContent)![1]; const ccVersion = +versionRegex.exec(fileContent)![1]; const hasAPI = apiRegex.test(fileContent) || noApiRegex.test(fileContent); const setValue = (hasAPI && setValueApiRegex.test(fileContent)) || noApiRegex.test(fileContent) || noSetValueApiRegex.test(fileContent); const pollValue = (hasAPI && pollValueApiRegex.test(fileContent)) || noApiRegex.test(fileContent) || noPollValueApiRegex.test(fileContent); const interview = interviewRegex.test(fileContent) || noInterviewRegex.test(fileContent); allCCs.set(ccName, { version: ccVersion, API: hasAPI, setValue, pollValue, interview, }); } catch { /* ok */ } } const headers = [ "", "CC name", "Version", "Interview?", "API?", "setValue?", "pollValue?", ]; const rows: string[][] = []; for (const [ name, { version, interview, API, setValue, pollValue }, ] of allCCs.entries()) { const { version: latest, deprecated, obsolete, } = getLatestVersion(name); if (obsolete) continue; const implementationStatus = version === latest && interview && API && setValue ? "done" : version > 0 ? "in progress" : "none"; const overallColor = implementationStatus === "done" ? c.green : implementationStatus === "in progress" ? c.yellow : deprecated ? c.reset : c.red; const versionColor = version === latest ? c.green : version > 0 ? c.yellow : deprecated ? c.reset : c.red; const implementedVersion = versionColor( version > 0 ? version.toString() : "-", ); const hasInterview = interview ? c.green(" ✔ ") : c.red(" ❌ "); const hasAPI = API ? c.green(" ✔ ") : c.red(" ❌ "); const hasSetValue = setValue ? c.green(" ✔ ") : c.red(" ❌ "); const hasPollValue = pollValue ? c.green(" ✔ ") : c.red(" ❌ "); const prefix = implementationStatus === "done" ? "✔" : implementationStatus === "in progress" ? "✍🏻" : "❌"; const postfix = deprecated ? " " + c.reset("(deprecated)") : ""; if (implementationStatus !== "done" || !onlyIncomplete) { rows.push([ overallColor(prefix), overallColor(name + postfix), `${implementedVersion} (${latest})`, hasInterview, hasAPI, hasSetValue, hasPollValue, ]); } } writeTable( [headers, ...rows], argv.flavor === "github" ? "github" : "console", ); })(); function writeTable(rows: string[][], flavor: "console" | "github"): void { const numColumns = rows[0].length; if (flavor === "console") { const columnLenghts: number[] = []; for (let col = 0; col < numColumns; col++) { columnLenghts.push( Math.max(...rows.map((row) => getSafeLength(row[col]))), ); } const HR = "|-" + columnLenghts.map((len) => "-".repeat(len)).join("-|-") + "-|"; console.log(HR); for (let i = 0; i < rows.length; i++) { const row = "| " + rows[i] .map((r, ri) => padEnd(r, columnLenghts[ri])) .join(" | ") + " |"; console.log(row); if (i === 0) console.log(HR); } console.log(HR); } /*if (flavor === "github")*/ else { let output = ""; let HR = "|"; for (let i = 0; i < numColumns; i++) HR += " --- |"; for (let i = 0; i < rows.length; i++) { const row = "| " + rows[i].join(" | ") + " |"; output += row + "\n"; if (i === 0) output += HR + "\n"; } console.log(output); if (!process.env.CI) { clipboard.write(c.stripColor(output)); console.log(c.green("The table was copied to the clipboard!")); } } } // Taken from SDS13548 const ccVersions: Record< string, | { version: string | number; deprecated?: boolean; obsolete?: boolean } | undefined > = { "0x9C": { version: 1, deprecated: true }, "0x9D": { version: 1 }, "0x5D": { version: 3 }, "0x7e": { version: 1 }, "0x22": { version: 1 }, "0x85": { version: 3 }, "0x9B": { version: 1 }, "0x59": { version: 3 }, "0xA1": { version: 1 }, "0xA2": { version: 1 }, "0x66": { version: 1 }, "0x20": { version: 2 }, "0x36": { version: 1 }, "0x80": { version: 3 }, "0x30": { version: 2, deprecated: true }, "0x25": { version: 2 }, "0x46": { version: 1, deprecated: true }, "0x5B": { version: 3 }, "0x81": { version: 1 }, "0x33": { version: 3 }, "0x70": { version: 4 }, "0x21": { version: 1 }, "0x56": { version: 1, deprecated: true }, "0x3A": { version: 1 }, "0x3B": { version: 1 }, "0x5A": { version: 1 }, "0x62": { version: 4 }, "0x4C": { version: 1 }, "0x90": { version: 1 }, "0x6F": { version: 1 }, "0x7A": { version: 7 }, "0xA3": { version: 1 }, "0x8C": { version: 1 }, "0x7B": { version: 1, deprecated: true }, "0x37": { version: 1 }, "0x39": { version: 1 }, "0x6D": { version: 2 }, "0x6E": { version: 1 }, "0x64": { version: 2 }, "0x74": { version: 1 }, "0x87": { version: 4 }, "0x5C": { version: 1 }, "0xA0": { version: 1 }, "0x6B": { version: 1 }, "0x89": { version: 1 }, "0x76": { version: 1, deprecated: true }, "0x69": { version: 2 }, "0x91": { version: 1 }, "0x72": { version: 2 }, "0x32": { version: 6 }, "0x3C": { version: 1 }, "0x3D": { version: 3 }, "0x3E": { version: 1 }, "0x60": { version: 4 }, "0x8E": { version: 4 }, "0x8F": { version: 1 }, "0x31": { version: 11 }, "0x26": { version: 4 }, "0x29": { version: 1, deprecated: true }, "0x4D": { version: 2 }, "0x34": { version: 3 }, "0x67": { version: 2 }, "0x52": { version: 3 }, "0x00": { version: 1 }, "0x77": { version: 1 }, "0x78": { version: 1 }, "0x71": { version: 8 }, "0x73": { version: 1 }, "0x3F": { version: 1 }, "0x41": { version: 1 }, "0x88": { version: 1, deprecated: true }, "0x75": { version: 2 }, "0x35": { version: 1, deprecated: true }, "0x48": { version: 1 }, "0x49": { version: 1 }, "0x2B": { version: 1 }, "0x2C": { version: 1 }, "0x2D": { version: 1 }, "0x53": { version: 4 }, "0x4E": { version: 3, deprecated: true }, "0x93": { version: 2 }, "0x92": { version: 2 }, "0x98": { version: 1 }, "0x9F": { version: 1 }, "0x94": { version: 4 }, "0x79": { version: 2 }, "0x6C": { version: 2 }, "0x4A": { version: 1 }, "0x4B": { version: 1 }, "0x44": { version: 5 }, "0x45": { version: 2 }, "0x40": { version: 3 }, "0x42": { version: 2 }, "0x47": { version: 1 }, "0x43": { version: 3 }, "0x8A": { version: 2 }, "0x8B": { version: 1 }, "0x55": { version: 2 }, "0x63": { version: 2 }, "0x86": { version: 3 }, "0x84": { version: 3 }, "0x6A": { version: 1 }, "0x23": { version: 4 }, "0x4F": { version: 1 }, "0x5F": { version: 1 }, "0x68": { version: 1 }, "0x58": { version: 1 }, "0x61": { version: 1 }, "0x5E": { version: 2 }, }; function getLatestVersion(ccName: string) { const cc = CommandClasses[ccName as any] as any as number; const version = ccVersions[num2hex(cc, true)]; if (version == undefined) { return { version: 0, obsolete: true }; } return version; }