summary refs log tree commit diff
path: root/scripts
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-12-17 11:00:51 +0100
committerRory& <root@rory.gay>2025-12-17 11:01:27 +0100
commit491c0de845a886954262e3ddb24959ba37a014b6 (patch)
treec0251f3779a5cd2842320e1278232b48fbea0390 /scripts
parentPre-commit: use spaces for formatting, regenerate schemas if changed (diff)
downloadserver-ts-491c0de845a886954262e3ddb24959ba37a014b6.tar.xz
lintstagedrc: regenerate schemas/openapi if schemas changed
Diffstat (limited to 'scripts')
-rw-r--r--scripts/genIndex.js24
-rw-r--r--scripts/license.js54
-rw-r--r--scripts/openapi.js374
-rw-r--r--scripts/schema.js568
-rw-r--r--scripts/schemaExclusions.json822
-rw-r--r--scripts/stress/identify.js72
-rw-r--r--scripts/stress/login.js18
-rw-r--r--scripts/stress/users.js32
-rw-r--r--scripts/syncronise.js10
-rw-r--r--scripts/test.js36
-rw-r--r--scripts/util/getRouteDescriptions.js86
-rw-r--r--scripts/util/walk.js28
12 files changed, 1065 insertions, 1059 deletions
diff --git a/scripts/genIndex.js b/scripts/genIndex.js

index c1b68227..e4601f3e 100644 --- a/scripts/genIndex.js +++ b/scripts/genIndex.js
@@ -41,29 +41,29 @@ let content = `/* // node scripts/genIndex.js /path/to/dir const targetDir = process.argv[2]; if (!targetDir) { - console.error("Please provide a target directory."); - process.exit(1); + console.error("Please provide a target directory."); + process.exit(1); } if (fs.existsSync(path.join(targetDir, "index.js")) || fs.existsSync(path.join(targetDir, "index.ts"))) { - console.error("index.js or index.ts already exists in the target directory."); - process.exit(1); + console.error("index.js or index.ts already exists in the target directory."); + process.exit(1); } const dirs = fs.readdirSync(targetDir).filter((f) => fs.statSync(path.join(targetDir, f)).isDirectory()); for (const dir of dirs) { - content += `export * from "./${dir}";\n`; + content += `export * from "./${dir}";\n`; } const files = fs.readdirSync(targetDir).filter((f) => f.endsWith(".js") || f.endsWith(".ts")); for (const file of files) { - const filePath = path.join(targetDir, file); - const stat = fs.statSync(filePath); - if (stat.isFile()) { - const ext = path.extname(file); - const base = path.basename(file, ext); - content += `export * from "./${base}";\n`; - } + const filePath = path.join(targetDir, file); + const stat = fs.statSync(filePath); + if (stat.isFile()) { + const ext = path.extname(file); + const base = path.basename(file, ext); + content += `export * from "./${base}";\n`; + } } fs.writeFileSync(path.join(targetDir, "index.ts"), content); diff --git a/scripts/license.js b/scripts/license.js
index 380a3ed6..0cc9b094 100644 --- a/scripts/license.js +++ b/scripts/license.js
@@ -12,43 +12,43 @@ const walk = require("./util/walk"); const SPACEBAR_SOURCE_DIR = Path.join(__dirname, "..", "src"); const SPACEBAR_SCRIPTS_DIR = Path.join(__dirname); const SPACEBAR_LICENSE_PREAMBLE = fs - .readFileSync(Path.join(__dirname, "util", "licensePreamble.txt")) - .toString() - .split("\r") // remove windows bs - .join("") // ^ - .split("\n") - .map((x) => `\t${x}`) - .join("\n"); + .readFileSync(Path.join(__dirname, "util", "licensePreamble.txt")) + .toString() + .split("\r") // remove windows bs + .join("") // ^ + .split("\n") + .map((x) => `\t${x}`) + .join("\n"); const languageCommentStrings = { - js: ["/*", "*/"], - ts: ["/*", "*/"], + js: ["/*", "*/"], + ts: ["/*", "*/"], }; const addToDir = (dir) => { - const files = walk(dir, Object.keys(languageCommentStrings)); + const files = walk(dir, Object.keys(languageCommentStrings)); - for (let path of files) { - const file = fs.readFileSync(path).toString().split("\r").join(""); - const fileType = path.slice(path.lastIndexOf(".") + 1); - const commentStrings = languageCommentStrings[fileType]; - if (!commentStrings) continue; + for (let path of files) { + const file = fs.readFileSync(path).toString().split("\r").join(""); + const fileType = path.slice(path.lastIndexOf(".") + 1); + const commentStrings = languageCommentStrings[fileType]; + if (!commentStrings) continue; - const preamble = commentStrings[0] + "\n" + SPACEBAR_LICENSE_PREAMBLE + "\n" + commentStrings[1]; + const preamble = commentStrings[0] + "\n" + SPACEBAR_LICENSE_PREAMBLE + "\n" + commentStrings[1]; - if (file.startsWith(preamble)) { - continue; - } + if (file.startsWith(preamble)) { + continue; + } - // This is kind of lame. - if (file.includes("@fc-license-skip") && path != __filename) { - console.log(`skipping ${path} as it has a different license.`); - continue; - } + // This is kind of lame. + if (file.includes("@fc-license-skip") && path != __filename) { + console.log(`skipping ${path} as it has a different license.`); + continue; + } - console.log(`writing to ${path}`); - fs.writeFileSync(path, preamble + "\n\n" + file); - } + console.log(`writing to ${path}`); + fs.writeFileSync(path, preamble + "\n\n" + file); + } }; addToDir(SPACEBAR_SOURCE_DIR); diff --git a/scripts/openapi.js b/scripts/openapi.js
index 39396d8d..5afee152 100644 --- a/scripts/openapi.js +++ b/scripts/openapi.js
@@ -32,227 +32,227 @@ const SchemaPath = path.join(__dirname, "..", "assets", "schemas.json"); const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" })); let specification = { - openapi: "3.1.0", - info: { - title: "Spacebar Server", - description: - "Spacebar is a Discord.com server implementation and extension, with the goal of complete feature parity with Discord.com, all while adding some additional goodies, security, privacy, and configuration options.", - license: { - name: "AGPLV3", - url: "https://www.gnu.org/licenses/agpl-3.0.en.html", - }, - version: "1.0.0", - }, - externalDocs: { - description: "Spacebar Docs", - url: "https://docs.spacebar.chat", - }, - servers: [ - { - url: "https://old.server.spacebar.chat/api/", - description: "Official Spacebar Instance", - }, - ], - components: { - securitySchemes: { - bearer: { - type: "http", - scheme: "bearer", - description: "Bearer/Bot prefixes are not required.", - bearerFormat: "JWT", - in: "header", - }, - }, - }, - tags: [], - paths: {}, + openapi: "3.1.0", + info: { + title: "Spacebar Server", + description: + "Spacebar is a Discord.com server implementation and extension, with the goal of complete feature parity with Discord.com, all while adding some additional goodies, security, privacy, and configuration options.", + license: { + name: "AGPLV3", + url: "https://www.gnu.org/licenses/agpl-3.0.en.html", + }, + version: "1.0.0", + }, + externalDocs: { + description: "Spacebar Docs", + url: "https://docs.spacebar.chat", + }, + servers: [ + { + url: "https://old.server.spacebar.chat/api/", + description: "Official Spacebar Instance", + }, + ], + components: { + securitySchemes: { + bearer: { + type: "http", + scheme: "bearer", + description: "Bearer/Bot prefixes are not required.", + bearerFormat: "JWT", + in: "header", + }, + }, + }, + tags: [], + paths: {}, }; const schemaRegEx = new RegExp(/^[\w.]+$/); function combineSchemas(schemas) { - let definitions = {}; + let definitions = {}; - for (const name in schemas) { - definitions = { - ...definitions, - ...schemas[name].definitions, - [name]: { - ...schemas[name], - definitions: undefined, - $schema: undefined, - }, - }; - } + for (const name in schemas) { + definitions = { + ...definitions, + ...schemas[name].definitions, + [name]: { + ...schemas[name], + definitions: undefined, + $schema: undefined, + }, + }; + } - for (const key in definitions) { - if (!schemaRegEx.test(key)) { - console.error(` \x1b[5m${bgRedBright("ERROR")}\x1b[25m Invalid schema name: ${key}, context:`, definitions[key]); - continue; - } - specification.components = specification.components || {}; - specification.components.schemas = specification.components.schemas || {}; - specification.components.schemas[key] = definitions[key]; - delete definitions[key].additionalProperties; - delete definitions[key].$schema; - const definition = definitions[key]; + for (const key in definitions) { + if (!schemaRegEx.test(key)) { + console.error(` \x1b[5m${bgRedBright("ERROR")}\x1b[25m Invalid schema name: ${key}, context:`, definitions[key]); + continue; + } + specification.components = specification.components || {}; + specification.components.schemas = specification.components.schemas || {}; + specification.components.schemas[key] = definitions[key]; + delete definitions[key].additionalProperties; + delete definitions[key].$schema; + const definition = definitions[key]; - if (typeof definition.properties === "object") { - for (const property of Object.values(definition.properties)) { - if (Array.isArray(property.type)) { - if (property.type.includes("null")) { - property.type = property.type.find((x) => x !== "null"); - property.nullable = true; - } - } - } - } - } + if (typeof definition.properties === "object") { + for (const property of Object.values(definition.properties)) { + if (Array.isArray(property.type)) { + if (property.type.includes("null")) { + property.type = property.type.find((x) => x !== "null"); + property.nullable = true; + } + } + } + } + } - return definitions; + return definitions; } function getTag(key) { - return key.match(/\/([\w-]+)/)[1]; + return key.match(/\/([\w-]+)/)[1]; } function apiRoutes(missingRoutes) { - const routes = getRouteDescriptions(); + const routes = getRouteDescriptions(); - // populate tags - const tags = Array.from(routes.keys()) - .map((x) => getTag(x)) - .sort((a, b) => a.localeCompare(b)); - specification.tags = [...new Set(tags)].map((x) => ({ name: x })); + // populate tags + const tags = Array.from(routes.keys()) + .map((x) => getTag(x)) + .sort((a, b) => a.localeCompare(b)); + specification.tags = [...new Set(tags)].map((x) => ({ name: x })); - routes.forEach((route, pathAndMethod) => { - const [p, method] = pathAndMethod.split("|"); - const path = p.replace(/:(\w+)/g, "{$1}"); + routes.forEach((route, pathAndMethod) => { + const [p, method] = pathAndMethod.split("|"); + const path = p.replace(/:(\w+)/g, "{$1}"); - let obj = specification.paths[path]?.[method] || {}; - obj["x-right-required"] = route.right; - obj["x-permission-required"] = route.permission; - obj["x-fires-event"] = route.event; + let obj = specification.paths[path]?.[method] || {}; + obj["x-right-required"] = route.right; + obj["x-permission-required"] = route.permission; + obj["x-fires-event"] = route.event; - if ( - !NO_AUTHORIZATION_ROUTES.some((x) => { - if (typeof x === "string") return (method.toUpperCase() + " " + path).startsWith(x); - return x.test(method.toUpperCase() + " " + path); - }) - ) { - obj.security = [{ bearer: [] }]; - } + if ( + !NO_AUTHORIZATION_ROUTES.some((x) => { + if (typeof x === "string") return (method.toUpperCase() + " " + path).startsWith(x); + return x.test(method.toUpperCase() + " " + path); + }) + ) { + obj.security = [{ bearer: [] }]; + } - if (route.description) obj.description = route.description; - if (route.summary) obj.summary = route.summary; - if (route.deprecated) obj.deprecated = route.deprecated; + if (route.description) obj.description = route.description; + if (route.summary) obj.summary = route.summary; + if (route.deprecated) obj.deprecated = route.deprecated; - if (route.requestBody) { - obj.requestBody = { - required: true, - content: { - "application/json": { - schema: { - $ref: `#/components/schemas/${route.requestBody}`, - }, - }, - }, - }; - } + if (route.requestBody) { + obj.requestBody = { + required: true, + content: { + "application/json": { + schema: { + $ref: `#/components/schemas/${route.requestBody}`, + }, + }, + }, + }; + } - if (route.responses) { - obj.responses = {}; + if (route.responses) { + obj.responses = {}; - for (const [k, v] of Object.entries(route.responses)) { - if (v.body) - obj.responses[k] = { - description: obj?.responses?.[k]?.description || "", - content: { - "application/json": { - schema: { - $ref: `#/components/schemas/${v.body}`, - }, - }, - }, - }; - else - obj.responses[k] = { - description: obj?.responses?.[k]?.description || "No description available", - }; - } - } else { - obj.responses = { - default: { - description: "No description available", - }, - }; - } + for (const [k, v] of Object.entries(route.responses)) { + if (v.body) + obj.responses[k] = { + description: obj?.responses?.[k]?.description || "", + content: { + "application/json": { + schema: { + $ref: `#/components/schemas/${v.body}`, + }, + }, + }, + }; + else + obj.responses[k] = { + description: obj?.responses?.[k]?.description || "No description available", + }; + } + } else { + obj.responses = { + default: { + description: "No description available", + }, + }; + } - // handles path parameters - if (p.includes(":")) { - obj.parameters = p.match(/:\w+/g)?.map((x) => ({ - name: x.replace(":", ""), - in: "path", - required: true, - schema: { type: "string" }, - description: x.replace(":", ""), - })); - } + // handles path parameters + if (p.includes(":")) { + obj.parameters = p.match(/:\w+/g)?.map((x) => ({ + name: x.replace(":", ""), + in: "path", + required: true, + schema: { type: "string" }, + description: x.replace(":", ""), + })); + } - if (route.query) { - // map to array - const query = Object.entries(route.query).map(([k, v]) => ({ - name: k, - in: "query", - required: v.required, - schema: { type: v.type }, - description: v.description, - })); + if (route.query) { + // map to array + const query = Object.entries(route.query).map(([k, v]) => ({ + name: k, + in: "query", + required: v.required, + schema: { type: v.type }, + description: v.description, + })); - obj.parameters = [...(obj.parameters || []), ...query]; - } + obj.parameters = [...(obj.parameters || []), ...query]; + } - obj.tags = [...new Set([...(obj.tags || []), getTag(p)])]; + obj.tags = [...new Set([...(obj.tags || []), getTag(p)])]; - if (missingRoutes.additional.includes(path.replace(/\/$/, ""))) { - obj["x-badges"] = [ - { - label: "Spacebar-only", - color: "red", - }, - ]; - } + if (missingRoutes.additional.includes(path.replace(/\/$/, ""))) { + obj["x-badges"] = [ + { + label: "Spacebar-only", + color: "red", + }, + ]; + } - specification.paths[path] = Object.assign(specification.paths[path] || {}, { - [method]: obj, - }); - }); + specification.paths[path] = Object.assign(specification.paths[path] || {}, { + [method]: obj, + }); + }); } async function main() { - console.log("Generating OpenAPI Specification..."); + console.log("Generating OpenAPI Specification..."); - const routesRes = await fetch("https://github.com/spacebarchat/missing-routes/raw/main/missing.json", { - headers: { - Accept: "application/json", - }, - }); - const missingRoutes = await routesRes.json(); + const routesRes = await fetch("https://github.com/spacebarchat/missing-routes/raw/main/missing.json", { + headers: { + Accept: "application/json", + }, + }); + const missingRoutes = await routesRes.json(); - combineSchemas(schemas); - apiRoutes(missingRoutes); + combineSchemas(schemas); + apiRoutes(missingRoutes); - fs.writeFileSync(openapiPath, JSON.stringify(specification, null, 4).replaceAll("#/definitions", "#/components/schemas").replaceAll("bigint", "number")); - console.log("Wrote OpenAPI specification to", openapiPath); - const elapsedMs = Number(totalSw.elapsed().totalMilliseconds + "." + totalSw.elapsed().microseconds); - console.log( - "Specification contains", - Object.keys(specification.paths).length, - "paths and", - Object.keys(specification.components.schemas).length, - "schemas in", - elapsedMs, - "ms.", - ); + fs.writeFileSync(openapiPath, JSON.stringify(specification, null, 4).replaceAll("#/definitions", "#/components/schemas").replaceAll("bigint", "number")); + console.log("Wrote OpenAPI specification to", openapiPath); + const elapsedMs = Number(totalSw.elapsed().totalMilliseconds + "." + totalSw.elapsed().microseconds); + console.log( + "Specification contains", + Object.keys(specification.paths).length, + "paths and", + Object.keys(specification.components.schemas).length, + "schemas in", + elapsedMs, + "ms.", + ); } main(); diff --git a/scripts/schema.js b/scripts/schema.js
index 1779c8d6..67c5563c 100644 --- a/scripts/schema.js +++ b/scripts/schema.js
@@ -24,10 +24,10 @@ const totalSw = Stopwatch.startNew(); const conWarn = console.warn; console.warn = (...args) => { - // silence some expected warnings - if (args[0] === "initializer is expression for property id") return; - if (args[0].startsWith("unknown initializer for property ") && args[0].endsWith("[object Object]")) return; - conWarn(...args); + // silence some expected warnings + if (args[0] === "initializer is expression for property id") return; + if (args[0].startsWith("unknown initializer for property ") && args[0].endsWith("[object Object]")) return; + conWarn(...args); }; const path = require("path"); @@ -41,27 +41,27 @@ const exclusionList = JSON.parse(fs.readFileSync(path.join(__dirname, "schemaExc // @type {TJS.PartialArgs} const settings = { - required: true, - ignoreErrors: true, - excludePrivate: true, - defaultNumberType: "integer", - noExtraProps: true, - defaultProps: false, - useTypeOfKeyword: true, // should help catch functions? + required: true, + ignoreErrors: true, + excludePrivate: true, + defaultNumberType: "integer", + noExtraProps: true, + defaultProps: false, + useTypeOfKeyword: true, // should help catch functions? }; const baseClassProperties = [ - // BaseClass methods - "toJSON", - "hasId", - "save", - "remove", - "softRemove", - "recover", - "reload", - "assign", - "_do_validate", // ? - "hasId", // ? + // BaseClass methods + "toJSON", + "hasId", + "save", + "remove", + "softRemove", + "recover", + "reload", + "assign", + "_do_validate", // ? + "hasId", // ? ]; const ExcludeAndWarn = [...exclusionList.manualWarn, ...exclusionList.manualWarnRe.map((r) => new RegExp(r))]; @@ -69,315 +69,315 @@ const Excluded = [...exclusionList.manual, ...exclusionList.manualRe.map((r) => const Included = [...exclusionList.include, ...exclusionList.includeRe.map((r) => new RegExp(r))]; const excludedLambdas = [ - (n, s) => { - // attempt to import - if (JSON.stringify(s).includes(`#/definitions/import(`)) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it attempted to use import().`); - exclusionList.auto.push({ value: n, reason: "Uses import()" }); - return true; - } - }, - (n, s) => { - if (JSON.stringify(s).includes(process.cwd())) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it leaked $PWD.`); - exclusionList.auto.push({ value: n, reason: "Leaked $PWD" }); - return true; - } - }, - (n, s) => { - if (JSON.stringify(s).includes(process.env.HOME)) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it leaked a $HOME path.`); - exclusionList.auto.push({ value: n, reason: "Leaked $HOME" }); - return true; - } - }, - (n, s) => { - if (s["$ref"] === `#/definitions/${n}`) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it is a self-reference only schema.`); - exclusionList.auto.push({ value: n, reason: "Self-reference only schema" }); - // fs.writeFileSync(`fucked/${n}.json`, JSON.stringify(s, null, 4)); - return true; - } - }, - (n, s) => { - if (s.description?.match(/Smithy/)) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it appears to be an AWS Smithy schema.`); - exclusionList.auto.push({ value: n, reason: "AWS Smithy schema" }); - return true; - } - }, - (n, s) => { - if (s.description?.startsWith("<p>")) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as we don't use HTML paragraphs for descriptions.`); - exclusionList.auto.push({ value: n, reason: "HTML paragraph in description" }); - return true; - } - }, - (n, s) => { - if (s.properties && Object.keys(s.properties).every((x) => x[0] === x[0].toUpperCase())) { - console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as all its properties have uppercase characters.`); - exclusionList.auto.push({ value: n, reason: "Schema with only uppercase properties" }); - return true; - } - }, - // (n, s) => { - // if (JSON.stringify(s).length <= 300) { - // console.log({n, s}); - // } - // } + (n, s) => { + // attempt to import + if (JSON.stringify(s).includes(`#/definitions/import(`)) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it attempted to use import().`); + exclusionList.auto.push({ value: n, reason: "Uses import()" }); + return true; + } + }, + (n, s) => { + if (JSON.stringify(s).includes(process.cwd())) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it leaked $PWD.`); + exclusionList.auto.push({ value: n, reason: "Leaked $PWD" }); + return true; + } + }, + (n, s) => { + if (JSON.stringify(s).includes(process.env.HOME)) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it leaked a $HOME path.`); + exclusionList.auto.push({ value: n, reason: "Leaked $HOME" }); + return true; + } + }, + (n, s) => { + if (s["$ref"] === `#/definitions/${n}`) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it is a self-reference only schema.`); + exclusionList.auto.push({ value: n, reason: "Self-reference only schema" }); + // fs.writeFileSync(`fucked/${n}.json`, JSON.stringify(s, null, 4)); + return true; + } + }, + (n, s) => { + if (s.description?.match(/Smithy/)) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as it appears to be an AWS Smithy schema.`); + exclusionList.auto.push({ value: n, reason: "AWS Smithy schema" }); + return true; + } + }, + (n, s) => { + if (s.description?.startsWith("<p>")) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as we don't use HTML paragraphs for descriptions.`); + exclusionList.auto.push({ value: n, reason: "HTML paragraph in description" }); + return true; + } + }, + (n, s) => { + if (s.properties && Object.keys(s.properties).every((x) => x[0] === x[0].toUpperCase())) { + console.log(`\r${redBright("[WARN]")} Omitting schema ${n} as all its properties have uppercase characters.`); + exclusionList.auto.push({ value: n, reason: "Schema with only uppercase properties" }); + return true; + } + }, + // (n, s) => { + // if (JSON.stringify(s).length <= 300) { + // console.log({n, s}); + // } + // } ]; function includesMatch(haystack, needles, log = false) { - for (const needle of needles) { - const match = needle instanceof RegExp ? needle.test(haystack) : haystack === needle; - if (match) { - if (log) console.warn(redBright("[WARN]:"), "Excluding schema", haystack, "due to match with", needle); - return needle; - } - } - return null; + for (const needle of needles) { + const match = needle instanceof RegExp ? needle.test(haystack) : haystack === needle; + if (match) { + if (log) console.warn(redBright("[WARN]:"), "Excluding schema", haystack, "due to match with", needle); + return needle; + } + } + return null; } async function main() { - const stepSw = Stopwatch.startNew(); + const stepSw = Stopwatch.startNew(); - process.stdout.write("Loading program... "); - const program = TJS.programFromConfig(path.join(__dirname, "..", "tsconfig.json"), walk(path.join(__dirname, "..", "src", "schemas"))); - const generator = TJS.buildGenerator(program, settings); - if (!generator || !program) { - console.log(redBright("Failed to create schema generator.")); - return; - } + process.stdout.write("Loading program... "); + const program = TJS.programFromConfig(path.join(__dirname, "..", "tsconfig.json"), walk(path.join(__dirname, "..", "src", "schemas"))); + const generator = TJS.buildGenerator(program, settings); + if (!generator || !program) { + console.log(redBright("Failed to create schema generator.")); + return; + } - const elapsedLoad = stepSw.getElapsedAndReset(); - process.stdout.write("Done in " + yellowBright(elapsedLoad.totalMilliseconds + "." + elapsedLoad.microseconds) + " ms\n"); + const elapsedLoad = stepSw.getElapsedAndReset(); + process.stdout.write("Done in " + yellowBright(elapsedLoad.totalMilliseconds + "." + elapsedLoad.microseconds) + " ms\n"); - process.stdout.write("Generating schema list... "); - let schemas = generator.getUserSymbols().filter((x) => { - return ( - (x.endsWith("Schema") || x.endsWith("Response") || x.startsWith("API")) && - // !ExcludeAndWarn.some((exc) => { - // const match = exc instanceof RegExp ? exc.test(x) : x === exc; - // if (match) console.warn("Warning: Excluding schema", x); - // return match; - // }) && - // !Excluded.some((exc) => (exc instanceof RegExp ? exc.test(x) : x === exc)) - (includesMatch(x, Included) || (!includesMatch(x, ExcludeAndWarn, true) && !includesMatch(x, Excluded))) - ); - }); - //.sort((a,b) => a.localeCompare(b)); + process.stdout.write("Generating schema list... "); + let schemas = generator.getUserSymbols().filter((x) => { + return ( + (x.endsWith("Schema") || x.endsWith("Response") || x.startsWith("API")) && + // !ExcludeAndWarn.some((exc) => { + // const match = exc instanceof RegExp ? exc.test(x) : x === exc; + // if (match) console.warn("Warning: Excluding schema", x); + // return match; + // }) && + // !Excluded.some((exc) => (exc instanceof RegExp ? exc.test(x) : x === exc)) + (includesMatch(x, Included) || (!includesMatch(x, ExcludeAndWarn, true) && !includesMatch(x, Excluded))) + ); + }); + //.sort((a,b) => a.localeCompare(b)); - const elapsedList = stepSw.getElapsedAndReset(); - process.stdout.write("Done in " + yellowBright(elapsedList.totalMilliseconds + "." + elapsedList.microseconds) + " ms\n"); - console.log("Found", yellowBright(schemas.length), "schemas to process."); + const elapsedList = stepSw.getElapsedAndReset(); + process.stdout.write("Done in " + yellowBright(elapsedList.totalMilliseconds + "." + elapsedList.microseconds) + " ms\n"); + console.log("Found", yellowBright(schemas.length), "schemas to process."); - let definitions = {}; - let nestedDefinitions = {}; - let writePromises = []; + let definitions = {}; + let nestedDefinitions = {}; + let writePromises = []; - if (process.env.WRITE_SCHEMA_DIR === "true") { - fs.rmSync("schemas_orig", { recursive: true, force: true }); - fs.mkdirSync("schemas_orig"); + if (process.env.WRITE_SCHEMA_DIR === "true") { + fs.rmSync("schemas_orig", { recursive: true, force: true }); + fs.mkdirSync("schemas_orig"); - fs.rmSync("schemas_nested", { recursive: true, force: true }); - fs.mkdirSync("schemas_nested"); + fs.rmSync("schemas_nested", { recursive: true, force: true }); + fs.mkdirSync("schemas_nested"); - fs.rmSync("schemas_final", { recursive: true, force: true }); - fs.mkdirSync("schemas_final"); - } + fs.rmSync("schemas_final", { recursive: true, force: true }); + fs.mkdirSync("schemas_final"); + } - const schemaSw = Stopwatch.startNew(); - for (const name of schemas) { - process.stdout.write(`Processing schema ${name}... `); - const part = TJS.generateSchema(program, name, settings, [], generator); - if (!part) continue; + const schemaSw = Stopwatch.startNew(); + for (const name of schemas) { + process.stdout.write(`Processing schema ${name}... `); + const part = TJS.generateSchema(program, name, settings, [], generator); + if (!part) continue; - if (definitions[name]) { - process.stdout.write(yellow(` [ERROR] Duplicate schema name detected: ${name}. Overwriting previous schema.`)); - } + if (definitions[name]) { + process.stdout.write(yellow(` [ERROR] Duplicate schema name detected: ${name}. Overwriting previous schema.`)); + } - if (!includesMatch(name, Included) && excludedLambdas.some((fn) => fn(name, part))) { - continue; - } + if (!includesMatch(name, Included) && excludedLambdas.some((fn) => fn(name, part))) { + continue; + } - if (process.env.WRITE_SCHEMA_DIR === "true") writePromises.push(async () => await fsp.writeFile(path.join("schemas_orig", `${name}.json`), JSON.stringify(part, null, 4))); + if (process.env.WRITE_SCHEMA_DIR === "true") writePromises.push(async () => await fsp.writeFile(path.join("schemas_orig", `${name}.json`), JSON.stringify(part, null, 4))); - // testing: - function mergeDefs(schemaName, schema) { - if (schema.definitions) { - // schema["x-sb-defs"] = Object.keys(schema.definitions); - process.stdout.write(cyanBright("Processing nested... ")); - for (const defKey in schema.definitions) { - if (definitions[defKey] && deepEqual(definitions[defKey], schema.definitions[defKey])) { - // console.log("Definition", defKey, "from schema", schemaName, "is identical to existing definition, skipping."); - schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); - process.stdout.write(greenBright("T")); - } else if (!nestedDefinitions[defKey]) { - nestedDefinitions[defKey] = schema.definitions[defKey]; - schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); - // console.log("Tracking sub-definition", defKey, "from schema", schemaName); - process.stdout.write(green("N")); - } else if (!deepEqual(nestedDefinitions[defKey], schema.definitions[defKey])) { - console.log(redBright("[ERROR]"), "Conflicting nested definition for", defKey, "found in schema", schemaName); - console.log(columnizedObjectDiff(nestedDefinitions[defKey], schema.definitions[defKey], true)); - } else { - // console.log("Definition", defKey, "from schema", schemaName, "is identical to existing definition, skipping."); - schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); - process.stdout.write(greenBright("M")); - } - } - if (Object.keys(schema.definitions).length === 0) { - process.stdout.write(greenBright("✓ ")); - delete schema.definitions; - } else { - console.log("Remaining definitions in schema", schemaName, "after merge:", Object.keys(schema.definitions)); - } - } - } - mergeDefs(name, part); + // testing: + function mergeDefs(schemaName, schema) { + if (schema.definitions) { + // schema["x-sb-defs"] = Object.keys(schema.definitions); + process.stdout.write(cyanBright("Processing nested... ")); + for (const defKey in schema.definitions) { + if (definitions[defKey] && deepEqual(definitions[defKey], schema.definitions[defKey])) { + // console.log("Definition", defKey, "from schema", schemaName, "is identical to existing definition, skipping."); + schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); + process.stdout.write(greenBright("T")); + } else if (!nestedDefinitions[defKey]) { + nestedDefinitions[defKey] = schema.definitions[defKey]; + schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); + // console.log("Tracking sub-definition", defKey, "from schema", schemaName); + process.stdout.write(green("N")); + } else if (!deepEqual(nestedDefinitions[defKey], schema.definitions[defKey])) { + console.log(redBright("[ERROR]"), "Conflicting nested definition for", defKey, "found in schema", schemaName); + console.log(columnizedObjectDiff(nestedDefinitions[defKey], schema.definitions[defKey], true)); + } else { + // console.log("Definition", defKey, "from schema", schemaName, "is identical to existing definition, skipping."); + schema.definitions = Object.fromEntries(Object.entries(schema.definitions).filter(([k, v]) => k !== defKey)); + process.stdout.write(greenBright("M")); + } + } + if (Object.keys(schema.definitions).length === 0) { + process.stdout.write(greenBright("✓ ")); + delete schema.definitions; + } else { + console.log("Remaining definitions in schema", schemaName, "after merge:", Object.keys(schema.definitions)); + } + } + } + mergeDefs(name, part); - const elapsed = schemaSw.getElapsedAndReset(); - process.stdout.write( - "Done in " + yellowBright(elapsed.totalMilliseconds + "." + elapsed.microseconds) + " ms, " + yellowBright(JSON.stringify(part).length) + " bytes (unformatted) ", - ); - if (elapsed.totalMilliseconds >= 20) console.log(bgRedBright("\x1b[5m[SLOW]\x1b[25m")); - else console.log(); + const elapsed = schemaSw.getElapsedAndReset(); + process.stdout.write( + "Done in " + yellowBright(elapsed.totalMilliseconds + "." + elapsed.microseconds) + " ms, " + yellowBright(JSON.stringify(part).length) + " bytes (unformatted) ", + ); + if (elapsed.totalMilliseconds >= 20) console.log(bgRedBright("\x1b[5m[SLOW]\x1b[25m")); + else console.log(); - definitions = { ...definitions, [name]: { ...part } }; - } - console.log("Processed", Object.keys(definitions).length, "schemas in", Number(stepSw.elapsed().totalMilliseconds + "." + stepSw.elapsed().microseconds), "ms."); + definitions = { ...definitions, [name]: { ...part } }; + } + console.log("Processed", Object.keys(definitions).length, "schemas in", Number(stepSw.elapsed().totalMilliseconds + "." + stepSw.elapsed().microseconds), "ms."); - console.log("Merging nested definitions into main definitions..."); - let isNewLine = true; - for (const defKey in nestedDefinitions) { - if (!includesMatch(defKey, Included, false)) { - const bannedMatch = includesMatch(defKey, ExcludeAndWarn, false) ?? includesMatch(defKey, Excluded, false); - if (bannedMatch !== null) { - // console.log(yellowBright("\n[WARN]"), "Skipping nested definition", defKey, "as it matched a banned format."); - console.log((isNewLine ? "" : "\n") + redBright("WARNING") + " Excluding schema " + yellowBright(defKey) + " due to match with " + redBright(bannedMatch)); - isNewLine = true; - continue; - } - } + console.log("Merging nested definitions into main definitions..."); + let isNewLine = true; + for (const defKey in nestedDefinitions) { + if (!includesMatch(defKey, Included, false)) { + const bannedMatch = includesMatch(defKey, ExcludeAndWarn, false) ?? includesMatch(defKey, Excluded, false); + if (bannedMatch !== null) { + // console.log(yellowBright("\n[WARN]"), "Skipping nested definition", defKey, "as it matched a banned format."); + console.log((isNewLine ? "" : "\n") + redBright("WARNING") + " Excluding schema " + yellowBright(defKey) + " due to match with " + redBright(bannedMatch)); + isNewLine = true; + continue; + } + } - nestedDefinitions[defKey]["$schema"] = "http://json-schema.org/draft-07/schema#"; - if (definitions[defKey]) { - if (!deepEqual(definitions[defKey], nestedDefinitions[defKey])) { - if (Object.keys(definitions[defKey]).every((k) => k === "$ref" || k === "$schema")) { - definitions[defKey] = nestedDefinitions[defKey]; - console.log(yellowBright("\nWARNING"), "Overwriting definition for", defKey, "with nested definition (ref/schema only)."); - isNewLine = true; - } else { - console.log(redBright("\nERROR"), "Conflicting definition for", defKey, "found in main definitions."); - console.log(columnizedObjectDiff(definitions[defKey], nestedDefinitions[defKey], true)); - console.log("Keys:", Object.keys(definitions[defKey]), Object.keys(nestedDefinitions[defKey])); - isNewLine = true; - } - } else { - // console.log("Definition", defKey, "is identical to existing definition, skipping."); - } - } else { - definitions[defKey] = nestedDefinitions[defKey]; - if (isNewLine) { - process.stdout.write("Adding nested definitions to main definitions: "); - isNewLine = false; - } else process.stdout.write("\x1b[4D, "); - process.stdout.write(yellowBright(defKey) + "... "); - } - } + nestedDefinitions[defKey]["$schema"] = "http://json-schema.org/draft-07/schema#"; + if (definitions[defKey]) { + if (!deepEqual(definitions[defKey], nestedDefinitions[defKey])) { + if (Object.keys(definitions[defKey]).every((k) => k === "$ref" || k === "$schema")) { + definitions[defKey] = nestedDefinitions[defKey]; + console.log(yellowBright("\nWARNING"), "Overwriting definition for", defKey, "with nested definition (ref/schema only)."); + isNewLine = true; + } else { + console.log(redBright("\nERROR"), "Conflicting definition for", defKey, "found in main definitions."); + console.log(columnizedObjectDiff(definitions[defKey], nestedDefinitions[defKey], true)); + console.log("Keys:", Object.keys(definitions[defKey]), Object.keys(nestedDefinitions[defKey])); + isNewLine = true; + } + } else { + // console.log("Definition", defKey, "is identical to existing definition, skipping."); + } + } else { + definitions[defKey] = nestedDefinitions[defKey]; + if (isNewLine) { + process.stdout.write("Adding nested definitions to main definitions: "); + isNewLine = false; + } else process.stdout.write("\x1b[4D, "); + process.stdout.write(yellowBright(defKey) + "... "); + } + } - deleteOneOfKindUndefinedRecursive(definitions, "$"); - for (const defKey in definitions) { - filterSchema(definitions[defKey]); - } + deleteOneOfKindUndefinedRecursive(definitions, "$"); + for (const defKey in definitions) { + filterSchema(definitions[defKey]); + } - if (process.env.WRITE_SCHEMA_DIR === "true") { - await Promise.all(writePromises); - await Promise.all( - Object.keys(definitions).map(async (name) => { - await fsp.writeFile(path.join("schemas_final", `${name}.json`), JSON.stringify(definitions[name], null, 4)); - // console.log("Wrote schema", name, "to schemas/"); - }), - ); - await Promise.all( - Object.keys(nestedDefinitions).map(async (name) => { - await fsp.writeFile(path.join("schemas_nested", `${name}.json`), JSON.stringify(nestedDefinitions[name], null, 4)); - // console.log("Wrote schema", name, "to schemas_nested/"); - }), - ); - } + if (process.env.WRITE_SCHEMA_DIR === "true") { + await Promise.all(writePromises); + await Promise.all( + Object.keys(definitions).map(async (name) => { + await fsp.writeFile(path.join("schemas_final", `${name}.json`), JSON.stringify(definitions[name], null, 4)); + // console.log("Wrote schema", name, "to schemas/"); + }), + ); + await Promise.all( + Object.keys(nestedDefinitions).map(async (name) => { + await fsp.writeFile(path.join("schemas_nested", `${name}.json`), JSON.stringify(nestedDefinitions[name], null, 4)); + // console.log("Wrote schema", name, "to schemas_nested/"); + }), + ); + } - fs.writeFileSync(schemaPath, JSON.stringify(definitions, null, 4)); - fs.writeFileSync(__dirname + "/schemaExclusions.json", JSON.stringify(exclusionList, null, 4)); - const elapsedMs = Number(totalSw.elapsed().totalMilliseconds + "." + totalSw.elapsed().microseconds); - console.log("\nSuccessfully wrote", Object.keys(definitions).length, "schemas to", schemaPath, "in", elapsedMs, "ms,", fs.statSync(schemaPath).size, "bytes."); + fs.writeFileSync(schemaPath, JSON.stringify(definitions, null, 4)); + fs.writeFileSync(__dirname + "/schemaExclusions.json", JSON.stringify(exclusionList, null, 4)); + const elapsedMs = Number(totalSw.elapsed().totalMilliseconds + "." + totalSw.elapsed().microseconds); + console.log("\nSuccessfully wrote", Object.keys(definitions).length, "schemas to", schemaPath, "in", elapsedMs, "ms,", fs.statSync(schemaPath).size, "bytes."); } function deleteOneOfKindUndefinedRecursive(obj, path) { - if (obj?.type === "object" && obj?.properties?.oneofKind?.type === "undefined") return true; + if (obj?.type === "object" && obj?.properties?.oneofKind?.type === "undefined") return true; - for (const key in obj) { - if (typeof obj[key] === "object" && deleteOneOfKindUndefinedRecursive(obj[key], path + "." + key)) { - console.log("Deleting", path, key); - delete obj[key]; - } - } + for (const key in obj) { + if (typeof obj[key] === "object" && deleteOneOfKindUndefinedRecursive(obj[key], path + "." + key)) { + console.log("Deleting", path, key); + delete obj[key]; + } + } - return false; + return false; } function filterSchema(schema) { - // this is a hack. we may want to check if its a @column instead - if (schema.properties) { - for (let key in schema.properties) { - if (baseClassProperties.includes(key)) { - delete schema.properties[key]; - } - } - } + // this is a hack. we may want to check if its a @column instead + if (schema.properties) { + for (let key in schema.properties) { + if (baseClassProperties.includes(key)) { + delete schema.properties[key]; + } + } + } - if (schema.required) schema.required = schema.required.filter((x) => !baseClassProperties.includes(x)); + if (schema.required) schema.required = schema.required.filter((x) => !baseClassProperties.includes(x)); - // recurse into own definitions - if (schema.definitions) { - console.log(redBright("WARNING"), "Schema has own definitions, recursing into them to filter base class properties:", Object.keys(schema.definitions)); - for (const defKey in schema.definitions) { - filterSchema(schema.definitions[defKey]); - } - } + // recurse into own definitions + if (schema.definitions) { + console.log(redBright("WARNING"), "Schema has own definitions, recursing into them to filter base class properties:", Object.keys(schema.definitions)); + for (const defKey in schema.definitions) { + filterSchema(schema.definitions[defKey]); + } + } } function deepEqual(a, b) { - if (a === b) return true; + if (a === b) return true; - if (typeof a !== "object" || typeof b !== "object" || a == null || b == null) { - return false; - } + if (typeof a !== "object" || typeof b !== "object" || a == null || b == null) { + return false; + } - const keysA = Object.keys(a); - const keysB = Object.keys(b); + const keysA = Object.keys(a); + const keysB = Object.keys(b); - if (keysA.length !== keysB.length) return false; + if (keysA.length !== keysB.length) return false; - for (const key of keysA) { - if (!keysB.includes(key) || (typeof a[key] === typeof b[key] && !deepEqual(a[key], b[key]))) { - return false; - } - } + for (const key of keysA) { + if (!keysB.includes(key) || (typeof a[key] === typeof b[key] && !deepEqual(a[key], b[key]))) { + return false; + } + } - return true; + return true; } function columnizedObjectDiff(a, b, trackEqual = false) { - const diffs = { left: {}, right: {}, ...(trackEqual ? { equal: {} } : {}) }; - const keys = new Set([...Object.keys(a), ...Object.keys(b)]); - for (const key of keys) { - if (!deepEqual(a[key], b[key])) { - diffs.left[key] = a[key]; - diffs.right[key] = b[key]; - } else if (trackEqual) diffs.equal[key] = a[key]; - } - return diffs; + const diffs = { left: {}, right: {}, ...(trackEqual ? { equal: {} } : {}) }; + const keys = new Set([...Object.keys(a), ...Object.keys(b)]); + for (const key of keys) { + if (!deepEqual(a[key], b[key])) { + diffs.left[key] = a[key]; + diffs.right[key] = b[key]; + } else if (trackEqual) diffs.equal[key] = a[key]; + } + return diffs; } main(); diff --git a/scripts/schemaExclusions.json b/scripts/schemaExclusions.json
index 389cb4f5..64e2bbf0 100644 --- a/scripts/schemaExclusions.json +++ b/scripts/schemaExclusions.json
@@ -1,409 +1,415 @@ { - "include": ["MessageInteractionSchema"], - "includeRe": ["^MessageComponentType\\..*"], - "manual": [ - "DefaultSchema", - "Schema", - "EntitySchema", - "ReadableStream<any>", - "SomeJSONSchema", - "UncheckedPartialSchema", - "PartialSchema", - "UncheckedPropertiesSchema", - "PropertiesSchema", - "AsyncSchema", - "AnySchema", - "SMTPConnection.CustomAuthenticationResponse", - "TransportMakeRequestResponse", - "StaticSchema", - "CSVImportResponse", - "NewMultipleMembersResponse", - "EventsResponse", - "NotificationAPIResponse", - "MetricsAPIResponse", - "ValidationResponse", - "MultipleValidationJobsListResponse", - "UpdateRouteResponse", - "MessagesSendAPIResponse", - "APIWebhook", - "WebhookResponse", - "WebhookValidationResponse", - "MessageResponse", - "ConnectionSettingsResponse", - "UpdatedDKIMSelectorResponse", - "UpdatedWebPrefixResponse", - "APIResponse", - "APIErrorOptions", - "APIErrorType", - "ListTagsForResourceResponse", - "GetContactResponse", - "LibraryResponse", - "LibraryLocalResponse", - "SchemaTraits", - "TraitsSchema", - "AbuseIpDbCheckResponse", - "IpDataIpLookupResponse" - ], - "manualRe": [ - ".*\\.Response$", - "^(Http2Server|Server|Express|(Resolved|)Http|Client|_|)Response$", - ".*\\..*", - "^Axios.*", - "^Internal", - "^Record<", - "^Omit<", - "^ListContact(s|Lists)Response$", - "^APIKeyConfiguration\\..*", - "^AccountSetting\\..*", - "^BulkContactManagement\\..*", - "^Campaign.*", - "^Contact.*", - "^DNS\\..*", - "^Delete.*", - "^Destroy.*", - "^Template\\..*", - "^Webhook\\..*", - "^(BigDecimal|BigInteger|Blob|Boolean|Document|Error|LazyRequest|List|Map|Normalized|Numeric|StreamingBlob|TimestampDateTime|TimestampHttpDate|TimestampEpochSeconds|Simple)Schema", - "^((Create|Update)Contact(|List))Response$", - "^(T|Unt)agResourceResponse$", - "^Put", - "^Inbox", - "^Seed", - "^DomainTag", - "^IpPool", - "DomainTemplate", - "^\\$", - "^Suppression", - "^Mail(|ing)List", - "DomainTracking", - "UpdatedDomain", - "ConfigurationSet", - "ContactList", - "^IPR", - "^Job" - ], - "manualWarn": [], - "manualWarnRe": [".*<.*>$"], - "auto": [ - { - "value": "StringSchema", - "reason": "AWS Smithy schema" - }, - { - "value": "TimestampDefaultSchema", - "reason": "AWS Smithy schema" - }, - { - "value": "StaticSimpleSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StaticListSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StaticMapSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StaticStructureSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StaticErrorSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StaticOperationSchema", - "reason": "Self-reference only schema" - }, - { - "value": "UnitSchema", - "reason": "AWS Smithy schema" - }, - { - "value": "MemberSchema", - "reason": "Self-reference only schema" - }, - { - "value": "StructureSchema", - "reason": "Self-reference only schema" - }, - { - "value": "OperationSchema", - "reason": "Self-reference only schema" - }, - { - "value": "BatchGetMetricDataResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CancelExportJobResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateCustomVerificationEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateDedicatedIpPoolResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateDeliverabilityTestReportResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateEmailIdentityResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateEmailIdentityPolicyResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateExportJobResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateImportJobResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateMultiRegionEndpointResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateTenantResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "CreateTenantResourceAssociationResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetAccountResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetBlacklistReportsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetCustomVerificationEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDedicatedIpResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDedicatedIpPoolResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDedicatedIpsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDeliverabilityDashboardOptionsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDeliverabilityTestReportResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDomainDeliverabilityCampaignResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetDomainStatisticsReportResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetEmailIdentityResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetEmailIdentityPoliciesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetExportJobResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetImportJobResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetMessageInsightsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetMultiRegionEndpointResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetReputationEntityResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetSuppressedDestinationResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "GetTenantResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListCustomVerificationEmailTemplatesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListDedicatedIpPoolsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListDeliverabilityTestReportsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListDomainDeliverabilityCampaignsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListEmailIdentitiesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListEmailTemplatesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListExportJobsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListImportJobsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListMultiRegionEndpointsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListRecommendationsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListReputationEntitiesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListResourceTenantsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListSuppressedDestinationsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListTenantResourcesResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "ListTenantsResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "SendBulkEmailResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "SendCustomVerificationEmailResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "SendEmailResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "TestRenderEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdateCustomVerificationEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdateEmailIdentityPolicyResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdateEmailTemplateResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdateReputationEntityCustomerManagedStatusResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdateReputationEntityPolicyResponse", - "reason": "HTML paragraph in description" - }, - { - "value": "UpdatedDKIMAuthorityResponse", - "reason": "Uses import()" - }, - { - "value": "ListRecipientResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "TemplateResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "TemplateDetailContentResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "EventCallbackUrlResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "ParseRouteResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "SenderResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "MetaSenderResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "ApiKeyResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "MyProfileResponse", - "reason": "Schema with only uppercase properties" - }, - { - "value": "UserResponse", - "reason": "Schema with only uppercase properties" - } - ] -} + "include": [ + "MessageInteractionSchema" + ], + "includeRe": [ + "^MessageComponentType\\..*" + ], + "manual": [ + "DefaultSchema", + "Schema", + "EntitySchema", + "ReadableStream<any>", + "SomeJSONSchema", + "UncheckedPartialSchema", + "PartialSchema", + "UncheckedPropertiesSchema", + "PropertiesSchema", + "AsyncSchema", + "AnySchema", + "SMTPConnection.CustomAuthenticationResponse", + "TransportMakeRequestResponse", + "StaticSchema", + "CSVImportResponse", + "NewMultipleMembersResponse", + "EventsResponse", + "NotificationAPIResponse", + "MetricsAPIResponse", + "ValidationResponse", + "MultipleValidationJobsListResponse", + "UpdateRouteResponse", + "MessagesSendAPIResponse", + "APIWebhook", + "WebhookResponse", + "WebhookValidationResponse", + "MessageResponse", + "ConnectionSettingsResponse", + "UpdatedDKIMSelectorResponse", + "UpdatedWebPrefixResponse", + "APIResponse", + "APIErrorOptions", + "APIErrorType", + "ListTagsForResourceResponse", + "GetContactResponse", + "LibraryResponse", + "LibraryLocalResponse", + "SchemaTraits", + "TraitsSchema", + "AbuseIpDbCheckResponse", + "IpDataIpLookupResponse" + ], + "manualRe": [ + ".*\\.Response$", + "^(Http2Server|Server|Express|(Resolved|)Http|Client|_|)Response$", + ".*\\..*", + "^Axios.*", + "^Internal", + "^Record<", + "^Omit<", + "^ListContact(s|Lists)Response$", + "^APIKeyConfiguration\\..*", + "^AccountSetting\\..*", + "^BulkContactManagement\\..*", + "^Campaign.*", + "^Contact.*", + "^DNS\\..*", + "^Delete.*", + "^Destroy.*", + "^Template\\..*", + "^Webhook\\..*", + "^(BigDecimal|BigInteger|Blob|Boolean|Document|Error|LazyRequest|List|Map|Normalized|Numeric|StreamingBlob|TimestampDateTime|TimestampHttpDate|TimestampEpochSeconds|Simple)Schema", + "^((Create|Update)Contact(|List))Response$", + "^(T|Unt)agResourceResponse$", + "^Put", + "^Inbox", + "^Seed", + "^DomainTag", + "^IpPool", + "DomainTemplate", + "^\\$", + "^Suppression", + "^Mail(|ing)List", + "DomainTracking", + "UpdatedDomain", + "ConfigurationSet", + "ContactList", + "^IPR", + "^Job" + ], + "manualWarn": [], + "manualWarnRe": [ + ".*<.*>$" + ], + "auto": [ + { + "value": "StringSchema", + "reason": "AWS Smithy schema" + }, + { + "value": "TimestampDefaultSchema", + "reason": "AWS Smithy schema" + }, + { + "value": "StaticSimpleSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StaticListSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StaticMapSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StaticStructureSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StaticErrorSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StaticOperationSchema", + "reason": "Self-reference only schema" + }, + { + "value": "UnitSchema", + "reason": "AWS Smithy schema" + }, + { + "value": "MemberSchema", + "reason": "Self-reference only schema" + }, + { + "value": "StructureSchema", + "reason": "Self-reference only schema" + }, + { + "value": "OperationSchema", + "reason": "Self-reference only schema" + }, + { + "value": "BatchGetMetricDataResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CancelExportJobResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateCustomVerificationEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateDedicatedIpPoolResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateDeliverabilityTestReportResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateEmailIdentityResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateEmailIdentityPolicyResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateExportJobResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateImportJobResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateMultiRegionEndpointResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateTenantResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "CreateTenantResourceAssociationResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetAccountResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetBlacklistReportsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetCustomVerificationEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDedicatedIpResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDedicatedIpPoolResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDedicatedIpsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDeliverabilityDashboardOptionsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDeliverabilityTestReportResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDomainDeliverabilityCampaignResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetDomainStatisticsReportResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetEmailIdentityResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetEmailIdentityPoliciesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetExportJobResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetImportJobResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetMessageInsightsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetMultiRegionEndpointResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetReputationEntityResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetSuppressedDestinationResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "GetTenantResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListCustomVerificationEmailTemplatesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListDedicatedIpPoolsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListDeliverabilityTestReportsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListDomainDeliverabilityCampaignsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListEmailIdentitiesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListEmailTemplatesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListExportJobsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListImportJobsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListMultiRegionEndpointsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListRecommendationsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListReputationEntitiesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListResourceTenantsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListSuppressedDestinationsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListTenantResourcesResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "ListTenantsResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "SendBulkEmailResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "SendCustomVerificationEmailResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "SendEmailResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "TestRenderEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdateCustomVerificationEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdateEmailIdentityPolicyResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdateEmailTemplateResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdateReputationEntityCustomerManagedStatusResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdateReputationEntityPolicyResponse", + "reason": "HTML paragraph in description" + }, + { + "value": "UpdatedDKIMAuthorityResponse", + "reason": "Uses import()" + }, + { + "value": "ListRecipientResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "TemplateResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "TemplateDetailContentResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "EventCallbackUrlResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "ParseRouteResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "SenderResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "MetaSenderResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "ApiKeyResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "MyProfileResponse", + "reason": "Schema with only uppercase properties" + }, + { + "value": "UserResponse", + "reason": "Schema with only uppercase properties" + } + ] +} \ No newline at end of file diff --git a/scripts/stress/identify.js b/scripts/stress/identify.js
index 478643f5..08d8d5db 100644 --- a/scripts/stress/identify.js +++ b/scripts/stress/identify.js
@@ -8,45 +8,45 @@ const TOKEN = process.env.TOKEN; const TOTAL_ITERATIONS = process.env.ITER ? parseInt(process.env.ITER) : 500; const doTimedIdentify = () => - new Promise((resolve) => { - let start; - const ws = new WebSocket(ENDPOINT); - ws.on("message", (data) => { - const parsed = JSON.parse(data); + new Promise((resolve) => { + let start; + const ws = new WebSocket(ENDPOINT); + ws.on("message", (data) => { + const parsed = JSON.parse(data); - switch (parsed.op) { - case OPCODES.Hello: - // send identify - start = performance.now(); - ws.send( - JSON.stringify({ - op: OPCODES.Identify, - d: { - token: TOKEN, - properties: {}, - }, - }), - ); - break; - case OPCODES.Dispatch: - if (parsed.t == "READY") { - ws.close(); - return resolve(performance.now() - start); - } + switch (parsed.op) { + case OPCODES.Hello: + // send identify + start = performance.now(); + ws.send( + JSON.stringify({ + op: OPCODES.Identify, + d: { + token: TOKEN, + properties: {}, + }, + }), + ); + break; + case OPCODES.Dispatch: + if (parsed.t == "READY") { + ws.close(); + return resolve(performance.now() - start); + } - break; - } - }); - }); + break; + } + }); + }); (async () => { - const perfs = []; - while (perfs.length < TOTAL_ITERATIONS) { - const ret = await doTimedIdentify(); - perfs.push(ret); - // console.log(`${perfs.length}/${TOTAL_ITERATIONS} - this: ${Math.floor(ret)}ms`) - } + const perfs = []; + while (perfs.length < TOTAL_ITERATIONS) { + const ret = await doTimedIdentify(); + perfs.push(ret); + // console.log(`${perfs.length}/${TOTAL_ITERATIONS} - this: ${Math.floor(ret)}ms`) + } - const avg = perfs.reduce((prev, curr) => prev + curr) / (perfs.length - 1); - console.log(`Average identify time: ${Math.floor(avg * 100) / 100}ms`); + const avg = perfs.reduce((prev, curr) => prev + curr) / (perfs.length - 1); + console.log(`Average identify time: ${Math.floor(avg * 100) / 100}ms`); })(); diff --git a/scripts/stress/login.js b/scripts/stress/login.js
index 5cb254d1..830d6a48 100644 --- a/scripts/stress/login.js +++ b/scripts/stress/login.js
@@ -1,16 +1,16 @@ const ENDPOINT = process.env.API || "http://localhost:3001"; async function main() { - const ret = await fetch(`${ENDPOINT}/api/auth/login`, { - method: "POST", - body: JSON.stringify({ - login: process.argv[2], - password: process.argv[3], - }), - headers: { "content-type": "application/json " }, - }); + const ret = await fetch(`${ENDPOINT}/api/auth/login`, { + method: "POST", + body: JSON.stringify({ + login: process.argv[2], + password: process.argv[3], + }), + headers: { "content-type": "application/json " }, + }); - console.log((await ret.json()).token); + console.log((await ret.json()).token); } main(); diff --git a/scripts/stress/users.js b/scripts/stress/users.js
index 67fa3ec8..2fc41eae 100644 --- a/scripts/stress/users.js +++ b/scripts/stress/users.js
@@ -21,22 +21,22 @@ const count = Number(process.env.COUNT) || 50; const endpoint = process.env.API || "http://localhost:3001"; async function main() { - for (let i = 0; i < count; i++) { - fetch(`${endpoint}/api/auth/register`, { - method: "POST", - body: JSON.stringify({ - fingerprint: `${i}.wR8vi8lGlFBJerErO9LG5NViJFw`, - username: `test${i}`, - invite: null, - consent: true, - date_of_birth: "2000-01-01", - gift_code_sku_id: null, - captcha_key: null, - }), - headers: { "content-type": "application/json" }, - }); - console.log(i); - } + for (let i = 0; i < count; i++) { + fetch(`${endpoint}/api/auth/register`, { + method: "POST", + body: JSON.stringify({ + fingerprint: `${i}.wR8vi8lGlFBJerErO9LG5NViJFw`, + username: `test${i}`, + invite: null, + consent: true, + date_of_birth: "2000-01-01", + gift_code_sku_id: null, + captcha_key: null, + }), + headers: { "content-type": "application/json" }, + }); + console.log(i); + } } main(); diff --git a/scripts/syncronise.js b/scripts/syncronise.js
index 1f3ed112..58c18029 100644 --- a/scripts/syncronise.js +++ b/scripts/syncronise.js
@@ -30,9 +30,9 @@ require("dotenv").config({ quiet: true }); const { initDatabase } = require(".."); (async () => { - const db = await initDatabase(); - console.log("synchronising"); - await db.synchronize(); - console.log("done"); - db.destroy(); + const db = await initDatabase(); + console.log("synchronising"); + await db.synchronize(); + console.log("done"); + db.destroy(); })(); diff --git a/scripts/test.js b/scripts/test.js
index c79e336f..3f944138 100644 --- a/scripts/test.js +++ b/scripts/test.js
@@ -29,34 +29,34 @@ const cfgFile = path.join(__dirname, "test_config.json"); process.env.CONFIG_PATH = cfgFile; fs.writeFileSync( - cfgFile, - JSON.stringify({ - api: { endpointPublic: "http://localhost:3001/api/v9/" }, - cdn: { endpointPublic: "http://localhost:3001/", endpointPrivate: "http://localhost:3001/" }, - gateway: { endpointPublic: "ws://localhost:3001/" }, - }), + cfgFile, + JSON.stringify({ + api: { endpointPublic: "http://localhost:3001/api/v9/" }, + cdn: { endpointPublic: "http://localhost:3001/", endpointPrivate: "http://localhost:3001/" }, + gateway: { endpointPublic: "ws://localhost:3001/" }, + }), ); const server = spawn("node", [path.join(__dirname, "..", "dist", "bundle", "start.js")]); server.stdout.on("data", (data) => { - process.stdout.write(data); + process.stdout.write(data); - if (data.toString().toLowerCase().includes("listening")) { - // we good :) - console.log("we good"); - server.kill(); - process.exit(); - } + if (data.toString().toLowerCase().includes("listening")) { + // we good :) + console.log("we good"); + server.kill(); + process.exit(); + } }); server.stderr.on("data", (err) => { - process.stdout.write(err); - // we bad :( - process.kill(1); + process.stdout.write(err); + // we bad :( + process.kill(1); }); server.on("close", (code) => { - console.log("closed with code", code); - process.exit(code); + console.log("closed with code", code); + process.exit(code); }); diff --git a/scripts/util/getRouteDescriptions.js b/scripts/util/getRouteDescriptions.js
index 1f27141e..87f1d4eb 100644 --- a/scripts/util/getRouteDescriptions.js +++ b/scripts/util/getRouteDescriptions.js
@@ -15,24 +15,24 @@ let currentPath = ""; */ function colorizeMethod(method) { - switch (method.toLowerCase()) { - case "get": - return greenBright(method.toUpperCase()); - case "post": - return yellowBright(method.toUpperCase()); - case "put": - return blueBright(method.toUpperCase()); - case "delete": - return redBright(method.toUpperCase()); - case "patch": - return yellowBright(method.toUpperCase()); - default: - return method.toUpperCase(); - } + switch (method.toLowerCase()) { + case "get": + return greenBright(method.toUpperCase()); + case "post": + return yellowBright(method.toUpperCase()); + case "put": + return blueBright(method.toUpperCase()); + case "delete": + return redBright(method.toUpperCase()); + case "patch": + return yellowBright(method.toUpperCase()); + default: + return method.toUpperCase(); + } } function formatPath(path) { - return path.replace(/:(\w+)/g, underline(":$1")).replace(/#(\w+)/g, underline("#$1")); + return path.replace(/:(\w+)/g, underline(":$1")).replace(/#(\w+)/g, underline("#$1")); } /** @@ -43,45 +43,45 @@ function formatPath(path) { * @param args */ function proxy(file, apiMethod, apiPathPrefix, apiPath, ...args) { - const opts = args.find((x) => x?.prototype?.OPTS_MARKER == true); - if (!opts) - return console.error( - ` \x1b[5m${bgRedBright("ERROR")}\x1b[25m ${file.replace(path.resolve(__dirname, "..", "..", "dist"), "/src")} has route without route() description middleware: ${colorizeMethod(apiMethod)} ${formatPath(apiPath)}`, - ); + const opts = args.find((x) => x?.prototype?.OPTS_MARKER == true); + if (!opts) + return console.error( + ` \x1b[5m${bgRedBright("ERROR")}\x1b[25m ${file.replace(path.resolve(__dirname, "..", "..", "dist"), "/src")} has route without route() description middleware: ${colorizeMethod(apiMethod)} ${formatPath(apiPath)}`, + ); - console.log(`${colorizeMethod(apiMethod).padStart("DELETE".length + 10)} ${formatPath(apiPathPrefix + apiPath)}`); - opts.file = file.replace("/dist/", "/src/").replace(".js", ".ts"); - routes.set(apiPathPrefix + apiPath + "|" + apiMethod, opts()); + console.log(`${colorizeMethod(apiMethod).padStart("DELETE".length + 10)} ${formatPath(apiPathPrefix + apiPath)}`); + opts.file = file.replace("/dist/", "/src/").replace(".js", ".ts"); + routes.set(apiPathPrefix + apiPath + "|" + apiMethod, opts()); } express.Router = () => { - return Object.fromEntries(methods.map((method) => [method, proxy.bind(null, currentFile, method, currentPath)])); + return Object.fromEntries(methods.map((method) => [method, proxy.bind(null, currentFile, method, currentPath)])); }; RouteUtility.route = (opts) => { - const func = function () { - return opts; - }; - func.prototype.OPTS_MARKER = true; - return func; + const func = function () { + return opts; + }; + func.prototype.OPTS_MARKER = true; + return func; }; module.exports = function getRouteDescriptions() { - const root = path.join(__dirname, "..", "..", "dist", "api", "routes", "/"); - traverseDirectory({ dirname: root, recursive: true }, (file) => { - currentFile = file; + const root = path.join(__dirname, "..", "..", "dist", "api", "routes", "/"); + traverseDirectory({ dirname: root, recursive: true }, (file) => { + currentFile = file; - currentPath = file.replace(root.slice(0, -1), ""); - currentPath = currentPath.split(".").slice(0, -1).join("."); // truncate .js/.ts file extension of path - currentPath = currentPath.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes - if (currentPath.endsWith("/index")) currentPath = currentPath.slice(0, "/index".length * -1); // delete index from path + currentPath = file.replace(root.slice(0, -1), ""); + currentPath = currentPath.split(".").slice(0, -1).join("."); // truncate .js/.ts file extension of path + currentPath = currentPath.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes + if (currentPath.endsWith("/index")) currentPath = currentPath.slice(0, "/index".length * -1); // delete index from path - try { - require(file); - } catch (e) { - console.error(e); - } - }); + try { + require(file); + } catch (e) { + console.error(e); + } + }); - return routes; + return routes; }; diff --git a/scripts/util/walk.js b/scripts/util/walk.js
index be59023d..06543315 100644 --- a/scripts/util/walk.js +++ b/scripts/util/walk.js
@@ -20,18 +20,18 @@ const fs = require("fs"); /** dir: string. types: string[] ( file types ) */ module.exports = function walk(dir, types = ["ts"]) { - var results = []; - var list = fs.readdirSync(dir); - list.forEach(function (file) { - file = dir + "/" + file; - var stat = fs.statSync(file); - if (stat && stat.isDirectory()) { - /* Recurse into a subdirectory */ - results = results.concat(walk(file, types)); - } else { - if (!types.find((x) => file.endsWith(x))) return; - results.push(file); - } - }); - return results; + var results = []; + var list = fs.readdirSync(dir); + list.forEach(function (file) { + file = dir + "/" + file; + var stat = fs.statSync(file); + if (stat && stat.isDirectory()) { + /* Recurse into a subdirectory */ + results = results.concat(walk(file, types)); + } else { + if (!types.find((x) => file.endsWith(x))) return; + results.push(file); + } + }); + return results; };