add formatter

This commit is contained in:
Hare Sudhan 2024-02-24 22:59:51 -05:00
parent c4e7c41a6e
commit ce30989adc
693 changed files with 51226 additions and 26671 deletions

View file

@ -12,19 +12,22 @@
/* eslint no-console: ["off"] */
import path from "path";
import fs from "fs";
import fs from "fs";
import process from "process";
import * as Ops from "../../operations/index.mjs";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: generateConfig.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/generateConfig.mjs");
console.log(
"Error: generateConfig.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/generateConfig.mjs",
);
process.exit(1);
}
const operationConfig = {},
modules = {};
@ -35,33 +38,30 @@ for (const opObj in Ops) {
const op = new Ops[opObj]();
operationConfig[op.name] = {
module: op.module,
module: op.module,
description: op.description,
infoURL: op.infoURL,
inputType: op.inputType,
outputType: op.presentType,
infoURL: op.infoURL,
inputType: op.inputType,
outputType: op.presentType,
flowControl: op.flowControl,
manualBake: op.manualBake,
args: op.args,
checks: op.checks
manualBake: op.manualBake,
args: op.args,
checks: op.checks,
};
if (!(op.module in modules))
modules[op.module] = {};
if (!(op.module in modules)) modules[op.module] = {};
modules[op.module][op.name] = opObj;
}
/**
* Write OperationConfig.
*/
fs.writeFileSync(
path.join(dir, "OperationConfig.json"),
JSON.stringify(operationConfig, null, 4)
JSON.stringify(operationConfig, null, 4),
);
console.log("Written OperationConfig.json");
/**
* Write modules.
*/
@ -98,14 +98,10 @@ OpModules.${module} = {
export default OpModules;
`;
fs.writeFileSync(
path.join(dir, `modules/${module}.mjs`),
code
);
fs.writeFileSync(path.join(dir, `modules/${module}.mjs`), code);
console.log(`Written ${module} module`);
}
/**
* Write OpModules wrapper.
*/
@ -140,8 +136,5 @@ opModulesCode += `);
export default OpModules;
`;
fs.writeFileSync(
path.join(dir, "modules/OpModules.mjs"),
opModulesCode
);
fs.writeFileSync(path.join(dir, "modules/OpModules.mjs"), opModulesCode);
console.log("Written OpModules.mjs");

View file

@ -10,20 +10,24 @@
/* eslint no-console: ["off"] */
import path from "path";
import fs from "fs";
import fs from "fs";
import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: generateOpsIndex.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs");
console.log(
"Error: generateOpsIndex.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs",
);
process.exit(1);
}
// Find all operation files
const opObjs = [];
fs.readdirSync(path.join(dir, "../operations")).forEach(file => {
fs.readdirSync(path.join(dir, "../operations")).forEach((file) => {
if (!file.endsWith(".mjs") || file === "index.mjs") return;
opObjs.push(file.split(".mjs")[0]);
});
@ -38,7 +42,7 @@ let code = `/**
*/
`;
opObjs.forEach(obj => {
opObjs.forEach((obj) => {
code += `import ${obj} from "./${obj}.mjs";\n`;
});
@ -46,15 +50,12 @@ code += `
export {
`;
opObjs.forEach(obj => {
opObjs.forEach((obj) => {
code += ` ${obj},\n`;
});
code += "};\n";
// Write file
fs.writeFileSync(
path.join(dir, "../operations/index.mjs"),
code
);
fs.writeFileSync(path.join(dir, "../operations/index.mjs"), code);
console.log("Written operation index.");

View file

@ -11,51 +11,62 @@
import prompt from "prompt";
import colors from "colors";
import path from "path";
import fs from "fs";
import fs from "fs";
import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newMinorVersion.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs");
console.log(
"Error: newMinorVersion.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs",
);
process.exit(1);
}
let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8");
const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/);
let changelogData = fs.readFileSync(
path.join(process.cwd(), "CHANGELOG.md"),
"utf8",
);
const lastVersion = changelogData.match(
/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/,
);
const newVersion = [
parseInt(lastVersion[1], 10),
parseInt(lastVersion[2], 10) + 1,
0
0,
];
let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm);
knownContributors = knownContributors.map(c => c.slice(2, -1));
knownContributors = knownContributors.map((c) => c.slice(2, -1));
const date = (new Date()).toISOString().split("T")[0];
const date = new Date().toISOString().split("T")[0];
const schema = {
properties: {
message: {
description: "A short but descriptive summary of a feature in this version",
description:
"A short but descriptive summary of a feature in this version",
example: "Added 'Op name' operation",
prompt: "Feature description",
type: "string",
required: true,
},
author: {
description: "The author of the feature (only one supported, edit manually to add more)",
description:
"The author of the feature (only one supported, edit manually to add more)",
example: "n1474335",
prompt: "Author",
type: "string",
default: "n1474335"
default: "n1474335",
},
id: {
description: "The PR number or full commit hash for this feature.",
example: "1200",
prompt: "Pull request or commit ID",
type: "string"
type: "string",
},
another: {
description: "y/n",
@ -63,14 +74,19 @@ const schema = {
prompt: "Add another feature?",
type: "string",
pattern: /^[yn]$/,
}
}
},
},
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
p.description =
"\n" +
colors.white(p.description) +
colors.cyan("\nExample: " + p.example) +
"\n" +
colors.green(p.prompt);
}
prompt.message = "";
@ -83,7 +99,7 @@ const commitIDs = [];
prompt.start();
const getFeature = function() {
const getFeature = function () {
prompt.get(schema, (err, result) => {
if (err) {
console.log("\nExiting script.");
@ -97,46 +113,75 @@ const getFeature = function() {
} else {
let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`;
features.forEach(feature => {
const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id;
features.forEach((feature) => {
const id =
feature.id.length > 10
? feature.id.slice(0, 7)
: "#" + feature.id;
message += `- ${feature.message} [@${feature.author}] | [${id}]\n`;
if (!knownContributors.includes(feature.author)) {
authors.push(`[@${feature.author}]: https://github.com/${feature.author}`);
authors.push(
`[@${feature.author}]: https://github.com/${feature.author}`,
);
}
if (feature.id.length > 10) {
commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`);
commitIDs.push(
`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`,
);
} else {
prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`);
prIDs.push(
`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`,
);
}
});
// Message
changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n");
changelogData = changelogData.replace(
/## Details\n\n/,
"## Details\n\n" + message + "\n",
);
// Tag
const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`;
changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1");
changelogData = changelogData.replace(
/\n\n(\[\d+\.\d+\.\d+\]: https)/,
"\n\n" + newTag + "$1",
);
// Author
authors.forEach(author => {
changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n");
authors.forEach((author) => {
changelogData = changelogData.replace(
/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/,
"$1" + author + "\n\n",
);
});
// Commit IDs
commitIDs.forEach(commitID => {
changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n");
commitIDs.forEach((commitID) => {
changelogData = changelogData.replace(
/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/,
"$1" + commitID + "\n\n",
);
});
// PR IDs
prIDs.forEach(prID => {
changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n");
prIDs.forEach((prID) => {
changelogData = changelogData.replace(
/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/,
"$1" + prID + "\n\n",
);
});
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
fs.writeFileSync(
path.join(process.cwd(), "CHANGELOG.md"),
changelogData,
);
console.log("Written CHANGELOG.md\nCommit changes and then run `npm version minor`.");
console.log(
"Written CHANGELOG.md\nCommit changes and then run `npm version minor`.",
);
}
});
};

View file

@ -15,16 +15,27 @@ import fs from "fs";
import path from "path";
import EscapeString from "../../operations/EscapeString.mjs";
const dir = path.join(process.cwd() + "/src/core/operations/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newOperation.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newOperation.mjs");
console.log(
"Example> node --experimental-modules src/core/config/scripts/newOperation.mjs",
);
process.exit(1);
}
const ioTypes = ["string", "byteArray", "number", "html", "ArrayBuffer", "BigNumber", "JSON", "File", "List<File>"];
const ioTypes = [
"string",
"byteArray",
"number",
"html",
"ArrayBuffer",
"BigNumber",
"JSON",
"File",
"List<File>",
];
const schema = {
properties: {
@ -35,7 +46,8 @@ const schema = {
type: "string",
pattern: /^[\w\s-/().]+$/,
required: true,
message: "Operation names should consist of letters, numbers or the following symbols: _-/()."
message:
"Operation names should consist of letters, numbers or the following symbols: _-/().",
},
module: {
description: `Modules are used to group operations that rely on large libraries. Any operation that is not in the Default module will be loaded in dynamically when it is first called. All operations in the same module will also be loaded at this time. This system prevents the CyberChef web app from getting too bloated and taking a long time to load initially.
@ -44,69 +56,89 @@ If your operation does not rely on a library, just leave this blank and it will
prompt: "Module",
type: "string",
pattern: /^[A-Z][A-Za-z\d]+$/,
message: "Module names should start with a capital letter and not contain any spaces or symbols.",
default: "Default"
message:
"Module names should start with a capital letter and not contain any spaces or symbols.",
default: "Default",
},
description: {
description: "The description should explain what the operation is and how it works. It can describe how the arguments should be entered and give examples of expected input and output. HTML markup is supported. Use <code> tags for examples. The description is scanned during searches, so include terms that are likely to be searched for when someone is looking for your operation.",
example: "Converts URI/URL percent-encoded characters back to their raw values.<br><br>e.g. <code>%3d</code> becomes <code>=</code>",
description:
"The description should explain what the operation is and how it works. It can describe how the arguments should be entered and give examples of expected input and output. HTML markup is supported. Use <code> tags for examples. The description is scanned during searches, so include terms that are likely to be searched for when someone is looking for your operation.",
example:
"Converts URI/URL percent-encoded characters back to their raw values.<br><br>e.g. <code>%3d</code> becomes <code>=</code>",
prompt: "Description",
type: "string"
type: "string",
},
infoURL: {
description: "An optional URL for an external site can be added to give more information about the operation. Wikipedia links are often suitable. If linking to Wikipedia, use an international link (e.g. https://wikipedia.org/...) rather than a localised link (e.g. https://en.wikipedia.org/...).",
description:
"An optional URL for an external site can be added to give more information about the operation. Wikipedia links are often suitable. If linking to Wikipedia, use an international link (e.g. https://wikipedia.org/...) rather than a localised link (e.g. https://en.wikipedia.org/...).",
example: "https://wikipedia.org/wiki/Percent-encoding",
prompt: "Information URL",
type: "string",
},
inputType: {
description: `The input type defines how the input data will be presented to your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(", ")}.`,
description: `The input type defines how the input data will be presented to your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(
", ",
)}.`,
example: "string",
prompt: "Input type",
type: "string",
pattern: new RegExp(`^(${ioTypes.join("|")})$`),
required: true,
message: `The input type should be one of: ${ioTypes.join(", ")}.`
message: `The input type should be one of: ${ioTypes.join(", ")}.`,
},
outputType: {
description: `The output type tells CyberChef what sort of data you are returning from your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(", ")}.`,
description: `The output type tells CyberChef what sort of data you are returning from your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(
", ",
)}.`,
example: "string",
prompt: "Output type",
type: "string",
pattern: new RegExp(`^(${ioTypes.join("|")})$`),
required: true,
message: `The output type should be one of: ${ioTypes.join(", ")}.`
message: `The output type should be one of: ${ioTypes.join(", ")}.`,
},
highlight: {
description: "If your operation does not change the length of the input in any way, we can enable highlighting. If it does change the length in a predictable way, we may still be able to enable highlighting and calculate the correct offsets. If this is not possible, we will disable highlighting for this operation.",
description:
"If your operation does not change the length of the input in any way, we can enable highlighting. If it does change the length in a predictable way, we may still be able to enable highlighting and calculate the correct offsets. If this is not possible, we will disable highlighting for this operation.",
example: "true/false",
prompt: "Enable highlighting",
type: "boolean",
default: "false",
message: "Enter true or false to specify if highlighting should be enabled."
message:
"Enter true or false to specify if highlighting should be enabled.",
},
authorName: {
description: "Your name or username will be added to the @author tag for this operation.",
description:
"Your name or username will be added to the @author tag for this operation.",
example: "n1474335",
prompt: "Username",
type: "string"
type: "string",
},
authorEmail: {
description: "Your email address will also be added to the @author tag for this operation.",
description:
"Your email address will also be added to the @author tag for this operation.",
example: "n1474335@gmail.com",
prompt: "Email",
type: "string"
}
}
type: "string",
},
},
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
p.description =
"\n" +
colors.white(p.description) +
colors.cyan("\nExample: " + p.example) +
"\n" +
colors.green(p.prompt);
}
console.log("\n\nThis script will generate a new operation template based on the information you provide. These values can be changed manually later.".yellow);
console.log(
"\n\nThis script will generate a new operation template based on the information you provide. These values can be changed manually later."
.yellow,
);
prompt.message = "";
prompt.delimiter = ":".green;
@ -119,14 +151,15 @@ prompt.get(schema, (err, result) => {
process.exit(0);
}
const moduleName = result.opName.replace(/\w\S*/g, txt => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
}).replace(/[\s-()./]/g, "");
const moduleName = result.opName
.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
})
.replace(/[\s-()./]/g, "");
const template = `/**
* @author ${result.authorName} [${result.authorEmail}]
* @copyright Crown Copyright ${(new Date()).getFullYear()}
* @copyright Crown Copyright ${new Date().getFullYear()}
* @license Apache-2.0
*/
@ -146,7 +179,10 @@ class ${moduleName} extends Operation {
this.name = "${result.opName}";
this.module = "${result.module}";
this.description = "${(new EscapeString).run(result.description, ["Special chars", "Double"])}";
this.description = "${new EscapeString().run(result.description, [
"Special chars",
"Double",
])}";
this.infoURL = "${result.infoURL}";
this.inputType = "${result.inputType}";
this.outputType = "${result.outputType}";
@ -176,7 +212,9 @@ class ${moduleName} extends Operation {
throw new OperationError("Test");
}
${result.highlight ? `
${
result.highlight
? `
/**
* Highlight ${result.opName}
*
@ -202,7 +240,9 @@ ${result.highlight ? `
highlightReverse(pos, args) {
return pos;
}
` : ""}
`
: ""
}
}
export default ${moduleName};
@ -212,7 +252,9 @@ export default ${moduleName};
const filename = path.join(dir, `./${moduleName}.mjs`);
if (fs.existsSync(filename)) {
console.log(`${filename} already exists. It has NOT been overwritten.`.red);
console.log(
`${filename} already exists. It has NOT been overwritten.`.red,
);
console.log("Choose a different operation name to avoid conflicts.");
process.exit(0);
}
@ -225,6 +267,4 @@ export default ${moduleName};
3. Write tests in ${colors.green("tests/operations/tests/")}
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
});