Show helpful errors of the repo configuration is wrong

e00effc988e32d2e4f8501586283a893dcb90ba9

Tucker McKnight <tmcknight@instructure.com> | Sun Sep 28 2025

Show helpful errors of the repo configuration is wrong

This is done by using ts-json-schema-generator to produce a JSON
schema from the ReposConfiguration typescript type. This happens
when you run `npm run build`. The resulting file is saved in
schemas/ReposConfiguration.json; this file should be committed when
it is modified.

The resulting JSON schema is then used to look for errors in the
reposConfiguration object that the user passes in when they
use this plugin. Ajv is used for this schema validation.

This change conveniently made me realize that I hadn't yet added
the new `path` property to the ReposConfiguration type, so that
is now in there.

ts-json-schema-generator doesn't seem to be able to "find" your
type definitions unless they are exported like
`export type ReposConfiguration...`, so src/configTypes.ts is
formatted like that now.
main.ts:8
Before
After
make.sh:1
Before
0
1
2
3
4

5
6
#!/bin/bash
rm -R dist
mkdir dist
mkdir dist/templates
mkdir dist/partial_templates
⁣
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
cp -r vendor dist/
After
0
1
2
3
4
5
6
7
#!/bin/bash
rm -R dist schemas
mkdir dist
mkdir dist/templates
mkdir dist/partial_templates
mkdir schemas
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
cp -r vendor dist/
package.json:4
Before
3
4
5
6
7
8
  "version": "0.0.1-alpha.1",
  "main": "dist/main.js",
  "scripts": {
    "build": "./make.sh && npx tsc && npx tsc --project frontend"
  },
  "keywords": [],
  "author": "",
After
3
4
5
6
7
8
  "version": "0.0.1-alpha.1",
  "main": "dist/main.js",
  "scripts": {
    "build": "./make.sh && npx ts-json-schema-generator --path src/configTypes.ts --type ReposConfiguration > schemas/ReposConfiguration.json && npx tsc && npx tsc --project frontend"
  },
  "keywords": [],
  "author": "",
package.json:12
Before
11
12
13

14
15
16

17
18
  "description": "",
  "devDependencies": {
    "@types/node": "^24.0.7",
⁣
    "typescript": "^5.8.3"
  },
  "dependencies": {
⁣
    "diff": "^8.0.2",
    "lodash": "^4.17.21"
  }
After
11
12
13
14
15
16
17
18
19
20
  "description": "",
  "devDependencies": {
    "@types/node": "^24.0.7",
    "ts-json-schema-generator": "^2.4.0",
    "typescript": "^5.8.3"
  },
  "dependencies": {
    "ajv": "^8.17.1",
    "diff": "^8.0.2",
    "lodash": "^4.17.21"
  }
src/configTypes.ts:12
Before
11
12
13

14
15
16
17
18
19
 * live website.
 * @example
 * const config: ReposConfiguration = {
⁣
 *   repos: {
 *     "My Darcs Project": {
 *       _type: "darcs",
 *       baseUrl: "https://repos.tuckerm.us",
 *       defaultBranch: 'main',
 *       branches: {
 *         'main': {
After
11
12
13
14
15
16
17

18
19
 * live website.
 * @example
 * const config: ReposConfiguration = {
 *   baseUrl: "https://repos.tuckerm.us",
 *   repos: {
 *     "My Darcs Project": {
 *       _type: "darcs",
⁣
 *       defaultBranch: 'main',
 *       branches: {
 *         'main': {
src/configTypes.ts:34
Before
33
34
35
36
37
38
 *   },
 * }
 */
type ReposConfiguration = {
  repos: {
    /** An object containing the configuration for your repositories.
    * Each key in this object is a repository name, and the value has several
After
33
34
35
36
37
38
 *   },
 * }
 */
export type ReposConfiguration = {
  repos: {
    /** An object containing the configuration for your repositories.
    * Each key in this object is a repository name, and the value has several
src/configTypes.ts:51
Before
50
51
52







53

54
55
56
  * @example baseUrl: "https://repos.tuckerm.us"
  */
  baseUrl: string,
⁣
⁣
⁣
⁣
⁣
⁣
⁣
}
⁣
type GitConfig = {
  _type: "git",
  /* The absolute path to the repository.
  * @example location: "/home/alice/projects/git_repo"
After
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  * @example baseUrl: "https://repos.tuckerm.us"
  */
  baseUrl: string,
  /**
  * The path to put the generated site in. All generated files will be put in this
  * directory, repos for cloning will be put in this directory, and it will be
  * added to the end of all URLs used by the default virtual template.
  * @example path: "/repos"
  */
  path?: string,
}

export type GitConfig = {
  _type: "git",
  /* The absolute path to the repository.
  * @example location: "/home/alice/projects/git_repo"
src/configTypes.ts:89
Before
88
89
90
91
92
93
*   },
* }
*/
type DarcsConfig = {
  /** Must be set to `"darcs"`. */
  _type: "darcs",
  /**
After
88
89
90
91
92
93
*   },
* }
*/
export type DarcsConfig = {
  /** Must be set to `"darcs"`. */
  _type: "darcs",
  /**
src/configTypes.ts:147
Before
146
147
148
149
150
151
152
153
    [fileExtension: string]: string
  }
}

export {
  ReposConfiguration,
  GitConfig,
  DarcsConfig,
}
After
146
147





    [fileExtension: string]: string
  }
⁣
⁣
⁣
⁣
⁣
⁣
}
tsconfig.json:2
Before
1
2
3

4
5
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "rewriteRelativeImportExtensions": true,
⁣
    "noImplicitAny": false,
    "module": "node18",
    "target": "es6",
After
1
2
3
4
5
6
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "rewriteRelativeImportExtensions": true,
    "resolveJsonModule": true,
    "noImplicitAny": false,
    "module": "node18",
    "target": "es6",