feat: improve monorepo dev experience

This commit is contained in:
2023-10-27 22:45:44 +02:00
parent f618725598
commit c6ab4ae48b
124 changed files with 2647 additions and 2857 deletions

View File

@@ -0,0 +1,27 @@
import {createGenerator, SchemaGenerator} from 'ts-json-schema-generator';
import {getValidatableTypes} from './get-validatable-types.js';
/**
* Compile the JSON schema for a path
*/
export function compileSchema(path: string, tsconfig: string): ReturnType<SchemaGenerator['createSchema']> {
const generator = createGenerator({
path,
tsconfig,
extraTags: ['elasticsearch'],
skipTypeCheck: true,
});
// @ts-expect-error private access
const program = generator.program;
const schemaNames = getValidatableTypes(program);
const fullSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
definitions: {},
};
for (const schema of schemaNames) {
Object.assign(fullSchema.definitions, generator.createSchema(schema).definitions);
}
return fullSchema;
}

View File

@@ -0,0 +1,34 @@
import {ts} from 'ts-json-schema-generator';
/**
* Get all types with `@validatable` annotations
*/
export function getValidatableTypes(program: ts.Program) {
const checker = program.getTypeChecker();
const declarationNames: string[] = [];
for (const sourceFile of program.getSourceFiles()) {
const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile);
if (!sourceFileSymbol) continue;
for (const exportSymbol of checker.getExportsOfModule(sourceFileSymbol)) {
for (const declaration of exportSymbol.getDeclarations() ?? []) {
const validatableTags = ts.getAllJSDocTags(declaration, isValidatableJSDocTag);
const name = ts.getNameOfDeclaration(declaration);
if (name && validatableTags.length > 0) {
declarationNames.push(name.getText());
}
}
}
}
return declarationNames;
}
/**
* Type predicate for if a JSDoc tag is `@validatable`
*/
// eslint-disable-next-line unicorn/prevent-abbreviations
function isValidatableJSDocTag(tag: ts.JSDocTag): tag is ts.JSDocTag {
return tag.tagName.escapedText === 'validatable';
}

View File

@@ -0,0 +1,37 @@
import {compileSchema} from './generator/compile-schema.js';
import {generateFiles, Plugin, PluginContext} from '@openstapps/tsup-plugin';
export type SchemaConsumer = (
this: PluginContext,
schema: ReturnType<typeof compileSchema>,
) => Record<string, string | Buffer>;
/**
* TSUp plugin for generating JSONSchema files
* @param schemaName the name of the generated schema
* @param schemaConsumers any consumers that can directly use the schema
*/
export function jsonSchemaPlugin(
schemaName: string,
...schemaConsumers: Array<[string, SchemaConsumer]>
): Plugin {
return {
name: 'json-schema-generator',
async buildEnd() {
let schema: ReturnType<typeof compileSchema>;
await generateFiles('JSON-Schema', async function () {
schema = compileSchema((this.options.entry as string[])[0], this.options.tsconfig!);
return {
[schemaName]: JSON.stringify(schema),
};
}).call(this);
for (const [name, consumer] of schemaConsumers) {
await generateFiles(name, async function () {
return consumer.call(this, schema);
}).call(this);
}
},
};
}