isaacscript 3.15.3 → 3.16.1-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/checkForWindowsTerminalBugs.js +57 -0
  2. package/{src → dist}/classes/Config.js +1 -6
  3. package/dist/classes/ValidatedConfig.js +1 -0
  4. package/{src → dist}/commands/check/check.js +67 -64
  5. package/dist/commands/check/check.test.js +86 -0
  6. package/dist/commands/copy/copy.js +29 -0
  7. package/dist/commands/init/checkIfProjectPathExists.js +21 -0
  8. package/dist/commands/init/checkModSubdirectory.js +9 -0
  9. package/dist/commands/init/checkModTargetDirectory.js +24 -0
  10. package/dist/commands/init/createProject.js +199 -0
  11. package/dist/commands/init/getAuthorName.js +22 -0
  12. package/dist/commands/init/getModsDir.js +48 -0
  13. package/dist/commands/init/getProjectPath.js +84 -0
  14. package/dist/commands/init/init.js +73 -0
  15. package/dist/commands/init/installVSCodeExtensions.js +27 -0
  16. package/dist/commands/init/promptSaveSlot.js +17 -0
  17. package/{src → dist}/commands/init/promptVSCode.js +5 -10
  18. package/dist/commands/monitor/copyWatcherMod.js +31 -0
  19. package/dist/commands/monitor/modDirectorySyncer/modDirectorySyncer.js +44 -0
  20. package/dist/commands/monitor/monitor.js +154 -0
  21. package/{src → dist}/commands/monitor/notifyGame.js +14 -22
  22. package/{src → dist}/commands/monitor/saveDatWriter/saveDatWriter.js +24 -27
  23. package/dist/commands/monitor/saveDatWriter/types.js +1 -0
  24. package/dist/commands/monitor/spawnModDirectorySyncer.js +31 -0
  25. package/dist/commands/monitor/spawnSaveDatWriter.js +29 -0
  26. package/dist/commands/monitor/spawnTSTLWatcher.js +74 -0
  27. package/dist/commands/monitor/touchWatcherSaveDatFiles.js +15 -0
  28. package/dist/commands/publish/isaacscriptMod.js +90 -0
  29. package/dist/commands/publish/prePublish.js +105 -0
  30. package/dist/commands/publish/publish.js +39 -0
  31. package/dist/commands/publish/validate.js +46 -0
  32. package/dist/common.js +65 -0
  33. package/dist/configFile.js +54 -0
  34. package/dist/constants.js +61 -0
  35. package/dist/customStage.js +298 -0
  36. package/dist/dev.js +10 -0
  37. package/{src/enums → dist/enums/copied}/DoorSlot.js +5 -6
  38. package/dist/enums/copied/DoorSlotFlag.js +35 -0
  39. package/{src/enums → dist/enums/copied}/RoomShape.js +5 -6
  40. package/{src → dist}/exec.js +19 -28
  41. package/dist/git.js +133 -0
  42. package/dist/interfaces/GitHubCLIHostsYAML.js +1 -0
  43. package/dist/interfaces/IsaacScriptTSConfig.js +1 -0
  44. package/dist/interfaces/ShadersXML.js +1 -0
  45. package/dist/interfaces/copied/CustomStageTSConfig.js +4 -0
  46. package/dist/interfaces/copied/JSONRoomsFile.js +4 -0
  47. package/dist/main.js +132 -0
  48. package/dist/objects/copied/doorSlotToDoorSlotFlag.js +16 -0
  49. package/dist/objects/copied/roomShapeToDoorSlotCoordinates.js +112 -0
  50. package/dist/packageManager.js +68 -0
  51. package/{src → dist}/parseArgs.js +36 -15
  52. package/dist/prompt.js +79 -0
  53. package/dist/tsconfig.js +98 -0
  54. package/dist/types/Command.js +4 -0
  55. package/dist/utils.js +8 -0
  56. package/dist/validateInIsaacScriptProject.js +29 -0
  57. package/dist/validateNodeVersion.js +20 -0
  58. package/file-templates/dynamic/.github/workflows/setup/action.yml +21 -0
  59. package/file-templates/dynamic/.yarnrc.yml +1 -0
  60. package/file-templates/dynamic/README.mod.md +4 -3
  61. package/file-templates/dynamic/_gitignore +0 -2
  62. package/file-templates/dynamic/package.mod.json +8 -0
  63. package/file-templates/dynamic/package.ts.json +5 -1
  64. package/file-templates/{dynamic → static}/.github/workflows/ci.yml +10 -38
  65. package/file-templates/static/scripts/tsconfig.json +28 -0
  66. package/file-templates/static-mod/.vscode/settings.json +1 -1
  67. package/file-templates/static-mod/{_cspell.json → _cspell.jsonc} +2 -2
  68. package/file-templates/static-mod/_eslintrc.cjs +1 -1
  69. package/file-templates/static-mod/prettier.config.mjs +6 -1
  70. package/file-templates/static-mod/scripts/lint.ts +36 -0
  71. package/file-templates/static-mod/tsconfig.json +5 -5
  72. package/file-templates/static-ts/.vscode/settings.json +1 -1
  73. package/file-templates/static-ts/{_cspell.json → _cspell.jsonc} +5 -5
  74. package/file-templates/static-ts/_eslintrc.cjs +1 -1
  75. package/file-templates/static-ts/knip.jsonc +6 -0
  76. package/file-templates/static-ts/prettier.config.mjs +6 -1
  77. package/file-templates/static-ts/scripts/lint.ts +30 -0
  78. package/file-templates/static-ts/tsconfig.json +3 -3
  79. package/package.json +27 -9
  80. package/plugins/addCrashDebugStatements.cjs +56 -0
  81. package/plugins/addCrashDebugStatements.ts +39 -0
  82. package/{src/plugins/addIsaacScriptCommentHeader.js → plugins/addIsaacScriptCommentHeader.cjs} +1 -1
  83. package/plugins/addIsaacScriptCommentHeader.ts +42 -0
  84. package/{src/plugins/addIsaacScriptCommentHeaderCommon.js → plugins/addIsaacScriptCommentHeaderCommon.cjs} +6 -4
  85. package/plugins/addIsaacScriptCommentHeaderCommon.ts +59 -0
  86. package/{src/plugins/noExtendedEnums.js → plugins/noExtendedEnums.cjs} +25 -4
  87. package/plugins/noExtendedEnums.ts +83 -0
  88. package/plugins/tsconfig.json +28 -0
  89. package/schemas/tsconfig-isaacscript-section-schema.json +1 -0
  90. package/file-templates/static/nuke.sh +0 -53
  91. package/file-templates/static/update.sh +0 -26
  92. package/file-templates/static-mod/build.sh +0 -22
  93. package/file-templates/static-mod/lint.sh +0 -43
  94. package/file-templates/static-mod/publish.sh +0 -10
  95. package/file-templates/static-mod/run.sh +0 -10
  96. package/file-templates/static-ts/build.sh +0 -53
  97. package/file-templates/static-ts/lint.sh +0 -35
  98. package/file-templates/static-ts/publish.sh +0 -10
  99. package/file-templates/static-ts/run.sh +0 -42
  100. package/src/checkForWindowsTerminalBugs.js +0 -71
  101. package/src/checkForWindowsTerminalBugs.js.map +0 -1
  102. package/src/classes/Config.js.map +0 -1
  103. package/src/classes/ValidatedConfig.js +0 -3
  104. package/src/classes/ValidatedConfig.js.map +0 -1
  105. package/src/commands/check/check.js.map +0 -1
  106. package/src/commands/check/check.test.js +0 -87
  107. package/src/commands/check/check.test.js.map +0 -1
  108. package/src/commands/copy/copy.js +0 -38
  109. package/src/commands/copy/copy.js.map +0 -1
  110. package/src/commands/init/checkIfProjectPathExists.js +0 -28
  111. package/src/commands/init/checkIfProjectPathExists.js.map +0 -1
  112. package/src/commands/init/checkModSubdirectory.js +0 -16
  113. package/src/commands/init/checkModSubdirectory.js.map +0 -1
  114. package/src/commands/init/checkModTargetDirectory.js +0 -31
  115. package/src/commands/init/checkModTargetDirectory.js.map +0 -1
  116. package/src/commands/init/createProject.js +0 -215
  117. package/src/commands/init/createProject.js.map +0 -1
  118. package/src/commands/init/getAuthorName.js +0 -27
  119. package/src/commands/init/getAuthorName.js.map +0 -1
  120. package/src/commands/init/getModsDir.js +0 -58
  121. package/src/commands/init/getModsDir.js.map +0 -1
  122. package/src/commands/init/getProjectPath.js +0 -89
  123. package/src/commands/init/getProjectPath.js.map +0 -1
  124. package/src/commands/init/init.js +0 -78
  125. package/src/commands/init/init.js.map +0 -1
  126. package/src/commands/init/installVSCodeExtensions.js +0 -35
  127. package/src/commands/init/installVSCodeExtensions.js.map +0 -1
  128. package/src/commands/init/promptSaveSlot.js +0 -22
  129. package/src/commands/init/promptSaveSlot.js.map +0 -1
  130. package/src/commands/init/promptVSCode.js.map +0 -1
  131. package/src/commands/monitor/copyWatcherMod.js +0 -39
  132. package/src/commands/monitor/copyWatcherMod.js.map +0 -1
  133. package/src/commands/monitor/modDirectorySyncer/modDirectorySyncer.js +0 -47
  134. package/src/commands/monitor/modDirectorySyncer/modDirectorySyncer.js.map +0 -1
  135. package/src/commands/monitor/monitor.js +0 -263
  136. package/src/commands/monitor/monitor.js.map +0 -1
  137. package/src/commands/monitor/notifyGame.js.map +0 -1
  138. package/src/commands/monitor/saveDatWriter/saveDatWriter.js.map +0 -1
  139. package/src/commands/monitor/saveDatWriter/types.js +0 -3
  140. package/src/commands/monitor/saveDatWriter/types.js.map +0 -1
  141. package/src/commands/monitor/spawnSaveDatWriter.js +0 -35
  142. package/src/commands/monitor/spawnSaveDatWriter.js.map +0 -1
  143. package/src/commands/monitor/touchWatcherSaveDatFiles.js +0 -21
  144. package/src/commands/monitor/touchWatcherSaveDatFiles.js.map +0 -1
  145. package/src/commands/publish/isaacscriptMod.js +0 -97
  146. package/src/commands/publish/isaacscriptMod.js.map +0 -1
  147. package/src/commands/publish/prePublish.js +0 -120
  148. package/src/commands/publish/prePublish.js.map +0 -1
  149. package/src/commands/publish/publish.js +0 -42
  150. package/src/commands/publish/publish.js.map +0 -1
  151. package/src/commands/publish/validate.js +0 -58
  152. package/src/commands/publish/validate.js.map +0 -1
  153. package/src/common.js +0 -69
  154. package/src/common.js.map +0 -1
  155. package/src/configFile.js +0 -64
  156. package/src/configFile.js.map +0 -1
  157. package/src/constants.js +0 -65
  158. package/src/constants.js.map +0 -1
  159. package/src/customStage.js +0 -304
  160. package/src/customStage.js.map +0 -1
  161. package/src/dev.js +0 -19
  162. package/src/dev.js.map +0 -1
  163. package/src/enums/DoorSlot.js.map +0 -1
  164. package/src/enums/DoorSlotFlag.js +0 -37
  165. package/src/enums/DoorSlotFlag.js.map +0 -1
  166. package/src/enums/PackageManager.js +0 -10
  167. package/src/enums/PackageManager.js.map +0 -1
  168. package/src/enums/RoomShape.js.map +0 -1
  169. package/src/exec.js.map +0 -1
  170. package/src/file.js +0 -247
  171. package/src/file.js.map +0 -1
  172. package/src/git.js +0 -154
  173. package/src/git.js.map +0 -1
  174. package/src/interfaces/GitHubCLIHostsYAML.js +0 -3
  175. package/src/interfaces/GitHubCLIHostsYAML.js.map +0 -1
  176. package/src/interfaces/IsaacScriptTSConfig.js +0 -3
  177. package/src/interfaces/IsaacScriptTSConfig.js.map +0 -1
  178. package/src/interfaces/ShadersXML.js +0 -3
  179. package/src/interfaces/ShadersXML.js.map +0 -1
  180. package/src/interfaces/copied/CustomStageTSConfig.js +0 -4
  181. package/src/interfaces/copied/CustomStageTSConfig.js.map +0 -1
  182. package/src/interfaces/copied/JSONRoomsFile.js +0 -4
  183. package/src/interfaces/copied/JSONRoomsFile.js.map +0 -1
  184. package/src/isaacScriptCommonTS.js +0 -233
  185. package/src/isaacScriptCommonTS.js.map +0 -1
  186. package/src/json.js +0 -42
  187. package/src/json.js.map +0 -1
  188. package/src/main.js +0 -127
  189. package/src/main.js.map +0 -1
  190. package/src/objects/doorSlotToDoorSlotFlag.js +0 -17
  191. package/src/objects/doorSlotToDoorSlotFlag.js.map +0 -1
  192. package/src/objects/roomShapeDoorToSlotCoordinates.js +0 -115
  193. package/src/objects/roomShapeDoorToSlotCoordinates.js.map +0 -1
  194. package/src/packageManager.js +0 -153
  195. package/src/packageManager.js.map +0 -1
  196. package/src/parseArgs.js.map +0 -1
  197. package/src/plugins/addCrashDebugStatements.js +0 -32
  198. package/src/plugins/addCrashDebugStatements.js.map +0 -1
  199. package/src/plugins/addIsaacScriptCommentHeader.js.map +0 -1
  200. package/src/plugins/addIsaacScriptCommentHeaderCommon.js.map +0 -1
  201. package/src/plugins/noExtendedEnums.js.map +0 -1
  202. package/src/prompt.js +0 -87
  203. package/src/prompt.js.map +0 -1
  204. package/src/tsconfig.js +0 -103
  205. package/src/tsconfig.js.map +0 -1
  206. package/src/types/Command.js +0 -9
  207. package/src/types/Command.js.map +0 -1
  208. package/src/utils.js +0 -15
  209. package/src/utils.js.map +0 -1
  210. package/src/validateInIsaacScriptProject.js +0 -36
  211. package/src/validateInIsaacScriptProject.js.map +0 -1
  212. package/src/validateNodeVersion.js +0 -29
  213. package/src/validateNodeVersion.js.map +0 -1
  214. package/src/version.js +0 -20
  215. package/src/version.js.map +0 -1
@@ -0,0 +1,68 @@
1
+ import chalk from "chalk";
2
+ import commandExists from "command-exists";
3
+ import { PackageManager, fatalError, getPackageManagerLockFileName, getPackageManagersForProject, } from "isaacscript-common-node";
4
+ import { CWD } from "./constants.js";
5
+ export const PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT = PackageManager.yarn;
6
+ export function getPackageManagerUsedForNewProject(args) {
7
+ const packageManagerFromArgs = getPackageManagerFromArgs(args);
8
+ if (packageManagerFromArgs !== undefined) {
9
+ return packageManagerFromArgs;
10
+ }
11
+ if (commandExists.sync("yarn")) {
12
+ return PackageManager.yarn;
13
+ }
14
+ if (commandExists.sync("pnpm")) {
15
+ return PackageManager.pnpm;
16
+ }
17
+ return PackageManager.npm;
18
+ }
19
+ export function getPackageManagerUsedForExistingProject(args) {
20
+ const packageManagers = getPackageManagersForProject(CWD);
21
+ if (packageManagers.length > 1) {
22
+ const packageManagerLockFileNames = packageManagers
23
+ .map((packageManager) => getPackageManagerLockFileName(packageManager))
24
+ .map((packageManagerLockFileName) => `"${packageManagerLockFileName}"`)
25
+ .join(" & ");
26
+ fatalError(`Multiple different kinds of package manager lock files were found (${packageManagerLockFileNames}). You should delete the ones that you are not using so that this program can correctly detect your package manager.`);
27
+ }
28
+ const packageManager = packageManagers[0];
29
+ if (packageManager !== undefined) {
30
+ return packageManager;
31
+ }
32
+ return getPackageManagerUsedForNewProject(args);
33
+ }
34
+ function getPackageManagerFromArgs(args) {
35
+ const dev = args.dev === true;
36
+ if (dev) {
37
+ const packageManagerCommandExists = commandExists.sync(PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT);
38
+ if (!packageManagerCommandExists) {
39
+ fatalError(`You specified the "dev" flag, but "${chalk.green(PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT)}" does not seem to be a valid command. The IsaacScript monorepo uses ${PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT}, so in order to initiate a linked development mod, you must also have ${PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT} installed. Try running "corepack enable" to install it.`);
40
+ }
41
+ return PACKAGE_MANAGER_USED_FOR_ISAACSCRIPT;
42
+ }
43
+ const npm = args.npm === true;
44
+ if (npm) {
45
+ const npmExists = commandExists.sync("npm");
46
+ if (!npmExists) {
47
+ fatalError(`You specified the "--npm" flag, but "${chalk.green("npm")}" does not seem to be a valid command.`);
48
+ }
49
+ return PackageManager.npm;
50
+ }
51
+ const yarn = args.yarn === true;
52
+ if (yarn) {
53
+ const yarnExists = commandExists.sync("yarn");
54
+ if (!yarnExists) {
55
+ fatalError(`You specified the "--yarn" flag, but "${chalk.green("yarn")}" does not seem to be a valid command.`);
56
+ }
57
+ return PackageManager.yarn;
58
+ }
59
+ const pnpm = args.pnpm === true;
60
+ if (pnpm) {
61
+ const pnpmExists = commandExists.sync("pnpm");
62
+ if (!pnpmExists) {
63
+ fatalError(`You specified the "--pnpm" flag, but "${chalk.green("pnpm")}" does not seem to be a valid command.`);
64
+ }
65
+ return PackageManager.pnpm;
66
+ }
67
+ return undefined;
68
+ }
@@ -1,15 +1,29 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseArgs = void 0;
4
- const tslib_1 = require("tslib");
5
- const yargs_1 = tslib_1.__importDefault(require("yargs"));
6
- const constants_js_1 = require("./constants.js");
1
+ // Other potential args libraries:
2
+ // - util.parseArgs
3
+ // - https://nodejs.org/api/util.html#utilparseargsconfig
4
+ // - Too bare bones; does not support numbers.
5
+ // - arg (1.2K stars)
6
+ // - https://github.com/vercel/arg
7
+ // - Does not support commands (i.e. positional arguments).
8
+ // - cmd-ts (193 stars)
9
+ // - https://github.com/Schniz/cmd-ts
10
+ // - ?
11
+ // - clack (4.3K stars)
12
+ // - https://github.com/natemoo-re/clack
13
+ // - ?
14
+ // - commander (25.4K stars)
15
+ // - https://github.com/tj/commander.js
16
+ // - ?
17
+ import { getArgs } from "isaacscript-common-node";
18
+ import yargs from "yargs";
19
+ import { PROJECT_NAME } from "./constants.js";
7
20
  /** Parse command-line arguments. */
8
- function parseArgs() {
9
- const yargsObject = (0, yargs_1.default)(process.argv.slice(2))
21
+ export function parseArgs() {
22
+ const args = getArgs();
23
+ const yargsObject = yargs(args)
10
24
  .strict()
11
- .usage(`usage: ${constants_js_1.PROJECT_NAME.toLowerCase()} <command> [options]`)
12
- .scriptName(constants_js_1.PROJECT_NAME.toLowerCase())
25
+ .usage(`usage: ${PROJECT_NAME.toLowerCase()} <command> [options]`)
26
+ .scriptName(PROJECT_NAME.toLowerCase())
13
27
  .alias("h", "help") // By default, only "--help" is enabled.
14
28
  .alias("V", "version") // By default, only "--version" is enabled.
15
29
  .command("monitor", "Monitor a project for changes. (default)", (builder) => builder
@@ -38,7 +52,7 @@ function parseArgs() {
38
52
  type: "boolean",
39
53
  description: "Enable verbose output",
40
54
  }))
41
- .command("init [name]", `Initialize a new ${constants_js_1.PROJECT_NAME} mod.`, (builder) => builder
55
+ .command("init [name]", `Initialize a new ${PROJECT_NAME} mod.`, (builder) => builder
42
56
  .option("yes", {
43
57
  alias: "y",
44
58
  type: "boolean",
@@ -100,7 +114,7 @@ function parseArgs() {
100
114
  type: "boolean",
101
115
  description: "Enable verbose output",
102
116
  }))
103
- .command("init-ts [name]", `Initialize a new ${constants_js_1.PROJECT_NAME} TypeScript project.`, (builder) => builder
117
+ .command("init-ts [name]", `Initialize a new ${PROJECT_NAME} TypeScript project.`, (builder) => builder
104
118
  .option("yes", {
105
119
  alias: "y",
106
120
  type: "boolean",
@@ -219,6 +233,10 @@ function parseArgs() {
219
233
  .option("skip-lint", {
220
234
  type: "boolean",
221
235
  description: "Skip linting before publishing",
236
+ })
237
+ .option("otp", {
238
+ type: "boolean",
239
+ description: "Provide a two-factor OTP code tied to the npm account",
222
240
  })
223
241
  .option("verbose", {
224
242
  alias: "v",
@@ -247,7 +265,12 @@ function parseArgs() {
247
265
  type: "boolean",
248
266
  description: "Enable verbose output",
249
267
  }))
250
- .command("check-cspell", 'Check the "cspell.json" file to see if any unused words exist.', (builder) => builder.option("verbose", {
268
+ .command("update", "Update the dependencies in the current project.", (builder) => builder.option("verbose", {
269
+ alias: "v",
270
+ type: "boolean",
271
+ description: "Enable verbose output",
272
+ }))
273
+ .command("nuke", "Delete and reinstall the dependencies in the current project.", (builder) => builder.option("verbose", {
251
274
  alias: "v",
252
275
  type: "boolean",
253
276
  description: "Enable verbose output",
@@ -255,5 +278,3 @@ function parseArgs() {
255
278
  .parseSync();
256
279
  return yargsObject;
257
280
  }
258
- exports.parseArgs = parseArgs;
259
- //# sourceMappingURL=parseArgs.js.map
package/dist/prompt.js ADDED
@@ -0,0 +1,79 @@
1
+ // Both the Inquirer.js library and the Prompts library have a bug where text is duplicated in a Git
2
+ // Bash terminal. Thus, we revert to using the simpler Prompt library.
3
+ import chalk from "chalk";
4
+ import { fatalError } from "isaacscript-common-node";
5
+ import { ReadonlySet, parseIntSafe } from "isaacscript-common-ts";
6
+ import prompt from "prompt";
7
+ const VALID_YES_RESPONSES = new ReadonlySet(["yes", "ye", "y"]);
8
+ const VALID_NO_RESPONSES = new ReadonlySet(["no", "n"]);
9
+ export function promptInit() {
10
+ // Override some of the prompt library's default values:
11
+ // https://github.com/flatiron/prompt#customizing-your-prompt
12
+ prompt.message = chalk.green("?");
13
+ prompt.delimiter = " ";
14
+ prompt.colors = false;
15
+ }
16
+ export async function getInputYesNo(msg, defaultValue = true) {
17
+ prompt.start();
18
+ // Capitalize the letter that represents the default option.
19
+ const y = defaultValue ? "Y" : "y";
20
+ const n = defaultValue ? "n" : "N";
21
+ const questionSuffix = `(${y}\\${n})`;
22
+ const description = `${chalk.bold(msg)} ${chalk.gray(questionSuffix)}`;
23
+ const { response } = await prompt.get({
24
+ properties: {
25
+ response: {
26
+ type: "string",
27
+ description,
28
+ },
29
+ },
30
+ });
31
+ if (typeof response !== "string") {
32
+ console.log(typeof response);
33
+ fatalError("Failed to get a proper response from the prompt library.");
34
+ }
35
+ const cleanedResponse = response.toLowerCase().trim();
36
+ // Default to true.
37
+ if (cleanedResponse === "") {
38
+ return defaultValue;
39
+ }
40
+ if (VALID_YES_RESPONSES.has(cleanedResponse)) {
41
+ return true;
42
+ }
43
+ if (VALID_NO_RESPONSES.has(cleanedResponse)) {
44
+ return false;
45
+ }
46
+ fatalError('Invalid response; must answer "yes" or "no".');
47
+ }
48
+ /** Returns trimmed input. */
49
+ export async function getInputString(msg, defaultValue) {
50
+ prompt.start();
51
+ let description = `${chalk.bold(msg)}`;
52
+ if (defaultValue !== undefined) {
53
+ description += ` ${chalk.gray(`(${defaultValue})`)}`;
54
+ }
55
+ const { response } = await prompt.get({
56
+ properties: {
57
+ response: {
58
+ type: "string",
59
+ description,
60
+ },
61
+ },
62
+ });
63
+ if (typeof response !== "string") {
64
+ fatalError("Failed to get a proper response from the prompt library.");
65
+ }
66
+ if (response === "" && defaultValue !== undefined) {
67
+ return defaultValue;
68
+ }
69
+ return response.trim();
70
+ }
71
+ export async function getInputInt(msg, defaultValue = 1) {
72
+ const defaultValueString = defaultValue.toString();
73
+ const string = await getInputString(msg, defaultValueString);
74
+ const int = parseIntSafe(string);
75
+ if (int === undefined) {
76
+ fatalError("Error: You must enter an integer.");
77
+ }
78
+ return int;
79
+ }
@@ -0,0 +1,98 @@
1
+ import ajvModule from "ajv";
2
+ import chalk from "chalk";
3
+ import { TSCONFIG_JSON, fatalError, getJSONC } from "isaacscript-common-node";
4
+ import { isObject } from "isaacscript-common-ts";
5
+ import { ISAACSCRIPT_SCHEMA_PATH, PROJECT_NAME, TSCONFIG_JSON_PATH, } from "./constants.js";
6
+ const ADVICE = `Try copying the "${TSCONFIG_JSON}" from a brand new ${PROJECT_NAME} project.`;
7
+ const isaacScriptSchema = getJSONC(ISAACSCRIPT_SCHEMA_PATH);
8
+ // Ajv is messed up: https://github.com/ajv-validator/ajv/issues/2132
9
+ const Ajv = ajvModule.default;
10
+ const ajv = new Ajv();
11
+ const schemaValidate = ajv.compile(isaacScriptSchema);
12
+ function getTSConfigJSON() {
13
+ return getJSONC(TSCONFIG_JSON_PATH);
14
+ }
15
+ function getIsaacScriptSection() {
16
+ const tsConfig = getTSConfigJSON();
17
+ // We allow different kinds of casing for the field name.
18
+ for (const fieldName of ["isaacscript", "isaacScript", "IsaacScript"]) {
19
+ const field = tsConfig[fieldName];
20
+ if (field !== undefined) {
21
+ if (!isObject(field)) {
22
+ fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file has a non-object value for the "${fieldName}" field, which is surely a mistake. ${ADVICE}`);
23
+ }
24
+ return field;
25
+ }
26
+ }
27
+ return undefined;
28
+ }
29
+ export function getFirstTSConfigIncludePath() {
30
+ const tsConfig = getTSConfigJSON();
31
+ const { include } = tsConfig;
32
+ if (include === undefined) {
33
+ fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file does not have an "include" field, which is surely a mistake. ${ADVICE}`);
34
+ }
35
+ if (!Array.isArray(include)) {
36
+ fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file has an "include" field that is not an array, which is surely a mistake. ${ADVICE}`);
37
+ }
38
+ const firstInclude = include[0];
39
+ if (firstInclude === undefined) {
40
+ fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file has an empty "include" field, which is surely a mistake. ${ADVICE}`);
41
+ }
42
+ if (typeof firstInclude !== "string") {
43
+ fatalError(`Your "${chalk.green(TSCONFIG_JSON_PATH)}" file has a non-string "include" value, which is surely a mistake. ${ADVICE}`);
44
+ }
45
+ return firstInclude;
46
+ }
47
+ /**
48
+ * Parses the "tsconfig.json" file and returns the "customStages" section. If the section does not
49
+ * exist, returns an empty array.
50
+ *
51
+ * Most of this function is simply performing input validation.
52
+ */
53
+ export function getCustomStagesFromTSConfig() {
54
+ const isaacScriptSection = getIsaacScriptSection();
55
+ if (isaacScriptSection === undefined) {
56
+ return [];
57
+ }
58
+ const valid = schemaValidate(isaacScriptSection);
59
+ if (!valid) {
60
+ console.error('Your "isaacscript" section in the "tsconfig.json" file has the following errors:');
61
+ console.error(schemaValidate.errors);
62
+ fatalError("For more information, see the custom stages documentation on the website.");
63
+ }
64
+ // "customStages" is an optional field.
65
+ const { customStages } = isaacScriptSection;
66
+ if (customStages === undefined) {
67
+ return [];
68
+ }
69
+ // The type of "customStages" should be validated by Ajv, but check again just in case.
70
+ if (!Array.isArray(customStages)) {
71
+ fatalError(`Failed to parse the "customStages" field, since it was not an array. ${ADVICE}.`);
72
+ }
73
+ // Perform some extra validation that can't be automatically done by Ajv.
74
+ for (const customStageTSConfig of customStages) {
75
+ const { name } = customStageTSConfig;
76
+ if (name === "") {
77
+ fatalError(chalk.red("One of the custom stages has a blank name, which is not allowed."));
78
+ }
79
+ const { xmlPath } = customStageTSConfig;
80
+ if (xmlPath === "") {
81
+ fatalError(chalk.red(`The "${name}" custom stage has a blank "xmlPath" field, which is not allowed.`));
82
+ }
83
+ const { roomVariantPrefix } = customStageTSConfig;
84
+ if (roomVariantPrefix < 100 || roomVariantPrefix > 999) {
85
+ fatalError(chalk.red(`The "${name}" custom stage has an invalid value for the "roomVariantPrefix" field: ${roomVariantPrefix}`));
86
+ }
87
+ const { baseStage } = customStageTSConfig;
88
+ if (baseStage !== undefined && (baseStage < 2 || baseStage > 13)) {
89
+ fatalError(`The "${name}" custom stage has an invalid value for the "baseStage" field: ${baseStage}`);
90
+ }
91
+ const { baseStageType } = customStageTSConfig;
92
+ if (baseStageType !== undefined &&
93
+ (baseStageType < 0 || baseStageType > 5)) {
94
+ fatalError(`The "${name}" custom stage has an invalid value for the "baseStageType" field: ${baseStageType}`);
95
+ }
96
+ }
97
+ return customStages;
98
+ }
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_COMMAND = "monitor";
2
+ export function isIsaacScriptModCommand(command) {
3
+ return !command.endsWith("-ts");
4
+ }
package/dist/utils.js ADDED
@@ -0,0 +1,8 @@
1
+ import moment from "moment";
2
+ import { CURRENT_DIRECTORY_NAME } from "./constants.js";
3
+ export function getModTargetDirectoryName(config) {
4
+ return config.customTargetModDirectoryName ?? CURRENT_DIRECTORY_NAME;
5
+ }
6
+ export function getTime() {
7
+ return moment().format("h:mm:ss A"); // e.g. "1:23:45 AM"
8
+ }
@@ -0,0 +1,29 @@
1
+ import chalk from "chalk";
2
+ import { PACKAGE_JSON, isDirectory, isFile } from "isaacscript-common-node";
3
+ import path from "node:path";
4
+ import { CWD, PROJECT_NAME } from "./constants.js";
5
+ const FILE_NAMES_TO_CHECK = [PACKAGE_JSON];
6
+ /** We don't check "node_modules" because we might be cloning a fresh IsaacScript project. */
7
+ const SUBDIRECTORY_NAMES_TO_CHECK = ["src", "mod"];
8
+ // Validate that we are in a directory that looks like an IsaacScript project.
9
+ export function validateInIsaacScriptProject() {
10
+ for (const fileName of FILE_NAMES_TO_CHECK) {
11
+ const filePath = path.join(CWD, fileName);
12
+ if (!isFile(filePath)) {
13
+ errorNotExists(fileName, true);
14
+ }
15
+ }
16
+ for (const subdirectoryName of SUBDIRECTORY_NAMES_TO_CHECK) {
17
+ const subdirectoryPath = path.join(CWD, subdirectoryName);
18
+ if (!isDirectory(subdirectoryPath)) {
19
+ errorNotExists(subdirectoryName, false);
20
+ }
21
+ }
22
+ }
23
+ function errorNotExists(dirName, file) {
24
+ const noun = file ? "file" : "subdirectory";
25
+ console.error(chalk.red(`It looks like the current working directory is not an ${PROJECT_NAME} project. (There is no "${dirName}" ${noun} here.)`));
26
+ console.error(`Did you mean to create a new ${PROJECT_NAME} project with "${chalk.green("npx isaacscript init")}"?`);
27
+ console.error(`If not, then change the current working directory to an ${PROJECT_NAME} project.`);
28
+ process.exit(1);
29
+ }
@@ -0,0 +1,20 @@
1
+ import chalk from "chalk";
2
+ import { fatalError } from "isaacscript-common-node";
3
+ import { parseSemanticVersion } from "isaacscript-common-ts";
4
+ import { PROJECT_NAME } from "./constants.js";
5
+ const REQUIRED_NODE_JS_MAJOR_VERSION = 16;
6
+ export function validateNodeVersion() {
7
+ const { version } = process;
8
+ const semanticVersion = parseSemanticVersion(version);
9
+ if (semanticVersion === undefined) {
10
+ fatalError(`Failed to parse the Node version: ${version}`);
11
+ }
12
+ const { majorVersion } = semanticVersion;
13
+ if (majorVersion >= REQUIRED_NODE_JS_MAJOR_VERSION) {
14
+ return;
15
+ }
16
+ console.error(`Your Node.js version is: ${chalk.red(version)}`);
17
+ console.error(`${PROJECT_NAME} requires a Node.js version of ${chalk.red(`${REQUIRED_NODE_JS_MAJOR_VERSION}.0.0`)} or greater.`);
18
+ console.error(`Please upgrade your version of Node.js before using ${PROJECT_NAME}.`);
19
+ process.exit(1);
20
+ }
@@ -0,0 +1,21 @@
1
+ runs:
2
+ using: composite
3
+
4
+ steps:
5
+ - name: Setup Node.js
6
+ uses: actions/setup-node@v3
7
+ with:
8
+ node-version: lts/*
9
+ cache: PACKAGE_MANAGER_NAME
10
+
11
+ - name: Retrieve the cached "node_modules" directory (if present)
12
+ uses: actions/cache@v3
13
+ id: node-modules-cache
14
+ with:
15
+ path: node_modules
16
+ key: client-build-node-modules-${{ hashFiles('PACKAGE_MANAGER_LOCK_FILE_NAME') }}
17
+
18
+ - name: Install dependencies (if the cached directory was not found)
19
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
20
+ run: PACKAGE_MANAGER_INSTALL_COMMAND
21
+ shell: bash # Composite jobs must specify the shell.
@@ -0,0 +1 @@
1
+ nodeLinker: node-modules
@@ -16,7 +16,8 @@ If you are a developer, or if the mod is not yet uploaded to the Steam Workshop,
16
16
  - Click on the "Code" button in the top-right-corner of this page.
17
17
  - Click on "Download ZIP".
18
18
  - Unzip the zip file to a new directory.
19
- - Open up the repository folder and double-click on the `run.sh` script. If prompted, choose to open it with Git for Windows. You will see a Git Bash terminal window open.
20
- - The script might ask you some questions, like which save file that you use for testing.
21
- - If the script is successful, you will see "Compilation successful." (You can continue to leave the terminal window open; it will monitor for changes in your project, and recompile if necessary.)
19
+ - Open the command prompt (or another shell of your choice).
20
+ - Use the `cd` command to navigate to the place where you unzipped the repository.
21
+ - Use the `npm run start` command to start the IsaacScript watcher.
22
+ - If IsaacScript is successful, you will see "Compilation successful." (You can continue to leave the terminal window open; it will monitor for changes in your project, and recompile if necessary.)
22
23
  - Completely close Isaac if it is already open, and then open the game again, and the mod should be in the list of mods. You can now play or test the mod.
@@ -13,7 +13,5 @@ mod/main.lua
13
13
  # ------------------------------
14
14
  # GitHub Node.gitignore template
15
15
  # https://raw.githubusercontent.com/github/gitignore/master/Node.gitignore
16
- # @template-ts-start
17
16
  # cspell:disable
18
- # @template-ts-end
19
17
  # ------------------------------
@@ -5,6 +5,14 @@
5
5
  "keywords": ["isaac", "mod", "rebirth", "afterbirth", "repentance"],
6
6
  "license": "GPL-3.0",
7
7
  "type": "module",
8
+ "scripts": {
9
+ "build": "tstl",
10
+ "lint": "tsx ./scripts/lint.ts",
11
+ "nuke": "isaacscript nuke",
12
+ "start": "isaacscript monitor",
13
+ "publish": "isaacscript publish",
14
+ "update": "isaacscript update"
15
+ },
8
16
  "dependencies": {
9
17
  "isaac-typescript-definitions": "^0.0.1",
10
18
  "isaacscript-common": "^0.0.1"
@@ -17,7 +17,11 @@
17
17
  "files": ["dist", "LICENSE", "package.json", "README.md"],
18
18
  "scripts": {
19
19
  "build": "rimraf dist && tsc",
20
- "start": "PACKAGE_MANAGER run build && node dist/main.js"
20
+ "lint": "tsx ./scripts/lint.ts",
21
+ "nuke": "isaacscript nuke",
22
+ "publish": "isaacscript publish-ts",
23
+ "start": "PACKAGE_MANAGER run build && node dist/main.js",
24
+ "update": "isaacscript update"
21
25
  },
22
26
  "devDependencies": {
23
27
  "@types/node": "^0.0.1",
@@ -3,47 +3,19 @@ name: CI
3
3
  on: [push, pull_request]
4
4
 
5
5
  jobs:
6
- build_and_lint:
6
+ build:
7
7
  runs-on: ubuntu-latest
8
8
  steps:
9
- - name: Checkout the repository
10
- uses: actions/checkout@v3
9
+ - uses: actions/checkout@v3
10
+ - uses: ./.github/workflows/setup
11
+ - run: npm run build
11
12
 
12
- - name: Setup Node.js
13
- uses: actions/setup-node@v3
14
- with:
15
- node-version: lts/*
16
- cache: PACKAGE_MANAGER_NAME
17
-
18
- - name: Retrieve the cached "node_modules" directory (if present)
19
- uses: actions/cache@v3
20
- id: node-cache
21
- with:
22
- path: node_modules
23
- key: node-modules-${{ runner.os }}-${{ hashFiles('PACKAGE_MANAGER_LOCK_FILE_NAME') }}
24
-
25
- - name: Install dependencies (if the cached directory was not found)
26
- if: steps.node-cache.outputs.cache-hit != 'true'
27
- run: PACKAGE_MANAGER_INSTALL_COMMAND
28
-
29
- - name: Test to see if the project compiles
30
- run: bash build.sh
31
-
32
- - name: Perform automated checks
33
- run: bash lint.sh
34
-
35
- # @template-mod-start
36
- # To enable publishing in CI, follow the instructions here:
37
- # https://github.com/IsaacScript/isaac-steam-workshop-upload
38
- # Then, uncomment the lines below.
39
- #- name: Upload the mod to Steam Workshop (if this is a release commit)
40
- # uses: IsaacScript/isaac-steam-workshop-upload@v2
41
- # if: "contains(github.event.head_commit.message, 'chore: release') && needs.pr-check.outputs.number != 'null'
42
- # with:
43
- # mod_path: mod
44
- # env:
45
- # CONFIG_VDF_CONTENTS: ${{ secrets.CONFIG_VDF_CONTENTS }}
46
- # @template-mod-end
13
+ lint:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v3
17
+ - uses: ./.github/workflows/setup
18
+ - run: npm run lint
47
19
 
48
20
  # To enable CI failure notifications over Discord:
49
21
  # - Right click on a channel in Discord and select "Edit Channel".
@@ -0,0 +1,28 @@
1
+ // A TypeScript configuration file, used by project scripts.
2
+ {
3
+ // We extend the IsaacScript config for Node.js:
4
+ // https://github.com/IsaacScript/isaacscript/blob/main/packages/isaacscript-tsconfig/tsconfig.node.json
5
+ "extends": "./packages/isaacscript-tsconfig/tsconfig.node.json",
6
+
7
+ // We want to lint every file in this directory. Two entries for each file extension are needed
8
+ // because TypeScript will exclude files that begin with a period from an asterisk glob by
9
+ // default.
10
+ "include": [
11
+ "./**/*.js",
12
+ "./**/.*.js",
13
+ "./**/*.cjs",
14
+ "./**/.*.cjs",
15
+ "./**/*.mjs",
16
+ "./**/.*.mjs",
17
+ "./**/*.jsx",
18
+ "./**/.*.jsx",
19
+ "./**/*.ts",
20
+ "./**/.*.ts",
21
+ "./**/*.cts",
22
+ "./**/.*.cts",
23
+ "./**/*.mts",
24
+ "./**/.*.mts",
25
+ "./**/*.tsx",
26
+ "./**/.*.tsx",
27
+ ],
28
+ }
@@ -36,7 +36,7 @@
36
36
  // Extension settings
37
37
  // ------------------
38
38
 
39
- // Use Prettier to format "cspell.json".
39
+ // Use Prettier to format "cspell.jsonc".
40
40
  "cSpell.autoFormatConfigFile": true,
41
41
 
42
42
  // -----------------
@@ -21,7 +21,7 @@
21
21
  "node_modules/**",
22
22
  "package-lock.json",
23
23
  "pnpm-lock.yaml",
24
- "yarn.lock"
24
+ "yarn.lock",
25
25
  ],
26
- "words": []
26
+ "words": [],
27
27
  }
@@ -5,7 +5,7 @@
5
5
  const config = {
6
6
  extends: [
7
7
  // The linter base is the IsaacScript mod config:
8
- // https://github.com/IsaacScript/isaacscript/blob/main/packages/eslint-config-isaacscript/configs/mod.js
8
+ // https://github.com/IsaacScript/isaacscript/blob/main/packages/eslint-config-isaacscript/mod.js
9
9
  "eslint-config-isaacscript/mod",
10
10
  ],
11
11
 
@@ -13,7 +13,12 @@ const config = {
13
13
  // Allow proper formatting of JSONC files:
14
14
  // https://github.com/prettier/prettier/issues/5708
15
15
  {
16
- files: ["**/.vscode/*.json", "**/tsconfig.json", "**/tsconfig.*.json"],
16
+ files: [
17
+ "**/*.jsonc",
18
+ "**/.vscode/*.json",
19
+ "**/tsconfig.json",
20
+ "**/tsconfig.*.json",
21
+ ],
17
22
  options: {
18
23
  parser: "json5",
19
24
  quoteProps: "preserve",
@@ -0,0 +1,36 @@
1
+ import { $, $s, commandExists, lintScript } from "isaacscript-common-node";
2
+
3
+ await lintScript(async () => {
4
+ const promises: Array<Promise<unknown>> = [];
5
+
6
+ promises.push(
7
+ // Use Prettier to check formatting.
8
+ // - "--log-level=warn" makes it only output errors.
9
+ $`npx prettier --log-level=warn --check .`,
10
+
11
+ // Type-check the code using the TypeScript compiler.
12
+ $`tsc --noEmit`,
13
+
14
+ // Use ESLint to lint the TypeScript.
15
+ // - "--max-warnings 0" makes warnings fail, since we set all ESLint errors to warnings.
16
+ $`eslint --max-warnings 0 .`,
17
+
18
+ // Check for unused exports.
19
+ // -"--error" makes it return an error code of 1 if unused exports are found.
20
+ $`npx ts-prune --error`,
21
+
22
+ // Spell check every file using CSpell.
23
+ // - "--no-progress" and "--no-summary" make it only output errors.
24
+ $`npx cspell --no-progress --no-summary .`,
25
+
26
+ // Check for unused CSpell words.
27
+ $`npx cspell-check-unused-words`,
28
+ );
29
+
30
+ if (commandExists("python")) {
31
+ $s`pip install isaac-xml-validator --upgrade --quiet`;
32
+ promises.push($`isaac-xml-validator --quiet`);
33
+ }
34
+
35
+ await Promise.all(promises);
36
+ });