config-loader: add support for defining config schema using .d.ts files

This commit is contained in:
Patrik Oldsberg
2020-11-15 20:13:42 +01:00
parent 28a49c2ffa
commit 06205426d8
3 changed files with 79 additions and 15 deletions
+1
View File
@@ -38,6 +38,7 @@
"fs-extra": "^9.0.0",
"json-schema": "^0.2.5",
"json-schema-merge-allof": "^0.7.0",
"typescript-json-schema": "^0.43.0",
"yaml": "^1.9.2",
"yup": "^0.29.3"
},
@@ -21,6 +21,8 @@ import {
dirname,
} from 'path';
import { ConfigSchemaPackageEntry } from './types';
import { getProgramFromFiles, generateSchema } from 'typescript-json-schema';
import { JsonObject } from '@backstage/config';
type Item = {
name: string;
@@ -40,6 +42,7 @@ export async function collectConfigSchemas(
): Promise<ConfigSchemaPackageEntry[]> {
const visitedPackages = new Set<string>();
const schemas = Array<ConfigSchemaPackageEntry>();
const tsSchemaPaths = Array<string>();
const currentDir = process.cwd();
async function processItem({ name, parentPath }: Item) {
@@ -83,18 +86,23 @@ export async function collectConfigSchemas(
}
if (hasSchema) {
if (typeof pkg.configSchema === 'string') {
if (!pkg.configSchema.endsWith('.json')) {
const isJson = pkg.configSchema.endsWith('.json');
const isDts = pkg.configSchema.endsWith('.d.ts');
if (!isJson && !isDts) {
throw new Error(
`Config schema files must be .json, got ${pkg.configSchema}`,
`Config schema files must be .json or .d.ts, got ${pkg.configSchema}`,
);
}
const value = await fs.readJson(
resolvePath(dirname(pkgPath), pkg.configSchema),
);
schemas.push({
value,
path: relativePath(currentDir, pkgPath),
});
if (isDts) {
tsSchemaPaths.push(resolvePath(dirname(pkgPath), pkg.configSchema));
} else {
const path = resolvePath(dirname(pkgPath), pkg.configSchema);
const value = await fs.readJson(path);
schemas.push({
value,
path: relativePath(currentDir, path),
});
}
} else {
schemas.push({
value: pkg.configSchema,
@@ -110,5 +118,49 @@ export async function collectConfigSchemas(
await Promise.all(packageNames.map(name => processItem({ name })));
return schemas;
const tsSchemas = compileTsSchemas(currentDir, tsSchemaPaths);
return schemas.concat(tsSchemas);
}
// This handles the support of TypeScript .d.ts config schema declarations.
// We collect all typescript schema definition and compile them all in one go.
// This is much faster than compiling them separately.
function compileTsSchemas(currentDir: string, paths: string[]) {
if (paths.length === 0) {
return [];
}
const program = getProgramFromFiles(paths, {
incremental: false,
isolatedModules: true,
lib: ['ES5'], // Skipping most libs speeds processing up a lot, we just need the primitive types anyway
noEmit: true,
noResolve: true,
skipLibCheck: true, // Skipping lib checks speeds things up
skipDefaultLibCheck: true,
strict: true,
typeRoots: [], // Do not include any additional types
types: [],
});
const tsSchemas = paths.map(schemaFile => {
const value = generateSchema(
program,
// All schemas should export a `Config` symbol
'Config',
// This enables usage of @visibility is doc comments
{ validationKeywords: ['visibility'] },
[schemaFile],
) as JsonObject | null;
const path = relativePath(currentDir, schemaFile);
if (!value) {
throw new Error(`Invalid schema in ${path}, missing Config export`);
}
return { path, value };
});
return tsSchemas;
}
+16 -5
View File
@@ -12478,7 +12478,7 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.6:
version "7.1.6"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -23239,10 +23239,21 @@ typedarray@^0.0.6:
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^4.0.3:
version "4.0.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5"
integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg==
typescript-json-schema@^0.43.0:
version "0.43.0"
resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.43.0.tgz#8bd9c832f1f15f006ff933907ce192222fdfd92f"
integrity sha512-4c9IMlIlHYJiQtzL1gh2nIPJEjBgJjDUs50gsnnc+GFyDSK1oFM3uQIBSVosiuA/4t6LSAXDS9vTdqbQC6EcgA==
dependencies:
"@types/json-schema" "^7.0.5"
glob "~7.1.6"
json-stable-stringify "^1.0.1"
typescript "~4.0.2"
yargs "^15.4.1"
typescript@^4.0.3, typescript@~4.0.2:
version "4.0.5"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389"
integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==
ua-parser-js@^0.7.18:
version "0.7.21"