isaacscript
Version:
A command line tool for managing Isaac mods written in TypeScript.
82 lines • 3.93 kB
JavaScript
import { Ajv } from "ajv";
import chalk from "chalk";
import { assertObject, isObject } from "complete-common";
import { fatalError, getJSONC } from "complete-node";
import { ISAACSCRIPT_SCHEMA_PATH, PROJECT_NAME, TSCONFIG_JSON, TSCONFIG_JSON_PATH, } from "./constants.js";
const ADVICE = `Try copying the "${TSCONFIG_JSON}" from a brand new ${PROJECT_NAME} project.`;
const isaacScriptSchema = await getJSONC(ISAACSCRIPT_SCHEMA_PATH);
assertObject(isaacScriptSchema, `The IsaacScript schema was not an object: ${ISAACSCRIPT_SCHEMA_PATH}`);
const ajv = new Ajv();
const schemaValidate = ajv.compile(isaacScriptSchema);
async function getTSConfigJSON() {
const tsconfig = await getJSONC(TSCONFIG_JSON_PATH);
assertObject(tsconfig, `The TSConfig was not an object: ${TSCONFIG_JSON_PATH}`);
return tsconfig;
}
async function getIsaacScriptSection() {
const tsConfig = await getTSConfigJSON();
// We allow different kinds of casing for the field name.
for (const fieldName of ["isaacscript", "isaacScript", "IsaacScript"]) {
const field = tsConfig[fieldName];
if (field !== undefined) {
if (!isObject(field)) {
fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file has a non-object value for the "${fieldName}" field, which is surely a mistake. ${ADVICE}`);
}
return field;
}
}
return undefined;
}
/**
* Parses the "tsconfig.json" file and returns the "customStages" section. If the section does not
* exist, returns an empty array.
*
* Most of this function is simply performing input validation.
*/
export async function getCustomStagesFromTSConfig() {
const isaacScriptSection = await getIsaacScriptSection();
if (isaacScriptSection === undefined) {
return [];
}
const valid = schemaValidate(isaacScriptSection);
if (!valid) {
console.error('Your "isaacscript" section in the "tsconfig.json" file has the following errors:');
console.error(schemaValidate.errors);
fatalError("For more information, see the custom stages documentation on the website.");
}
// "customStages" is an optional field.
const { customStages } = isaacScriptSection;
if (customStages === undefined) {
return [];
}
// The type of "customStages" should be validated by Ajv, but check again just in case.
if (!Array.isArray(customStages)) {
fatalError(`Failed to parse the "customStages" field, since it was not an array. ${ADVICE}.`);
}
// Perform some extra validation that can't be automatically done by Ajv.
for (const customStageTSConfig of customStages) {
const { name } = customStageTSConfig;
if (name === "") {
fatalError(chalk.red("One of the custom stages has a blank name, which is not allowed."));
}
const { xmlPath } = customStageTSConfig;
if (xmlPath === "") {
fatalError(chalk.red(`The "${name}" custom stage has a blank "xmlPath" field, which is not allowed.`));
}
const { roomVariantPrefix } = customStageTSConfig;
if (roomVariantPrefix < 100 || roomVariantPrefix > 999) {
fatalError(chalk.red(`The "${name}" custom stage has an invalid value for the "roomVariantPrefix" field: ${roomVariantPrefix}`));
}
const { baseStage } = customStageTSConfig;
if (baseStage !== undefined && (baseStage < 2 || baseStage > 13)) {
fatalError(`The "${name}" custom stage has an invalid value for the "baseStage" field: ${baseStage}`);
}
const { baseStageType } = customStageTSConfig;
if (baseStageType !== undefined
&& (baseStageType < 0 || baseStageType > 5)) {
fatalError(`The "${name}" custom stage has an invalid value for the "baseStageType" field: ${baseStageType}`);
}
}
return customStages;
}
//# sourceMappingURL=tsconfig.js.map