feat: generator updates

This commit is contained in:
2023-11-07 17:14:58 +01:00
parent 9ef77ab3ed
commit 8a421cb2fb
51 changed files with 1385 additions and 1241 deletions

View File

@@ -13,15 +13,14 @@
"core",
"validator"
],
"main": "lib/index.js",
"types": "lib/index.d.ts",
"main": "src/index.js",
"types": "src/types.d.ts",
"files": [
"lib",
"README.md",
"CHANGELOG.md"
],
"scripts": {
"build": "tsup-node --dts",
"docs": "typedoc --json ./docs/docs.json --options ../../typedoc.base.json src/index.ts",
"format": "prettier . -c --ignore-path ../../.gitignore",
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
@@ -51,20 +50,10 @@
"mocha": "10.2.0",
"mocha-junit-reporter": "2.2.0",
"nock": "13.3.1",
"ts-node": "10.9.1",
"tsup": "6.7.0",
"typedoc": "0.24.8",
"ts-node": "10.9.1",
"typescript": "5.1.6"
},
"tsup": {
"entry": [
"src/index.ts"
],
"sourcemap": true,
"clean": true,
"format": "esm",
"outDir": "lib"
},
"prettier": "@openstapps/prettier-config",
"eslintConfig": {
"extends": [

View File

@@ -1,11 +1,13 @@
import {createGenerator} from 'ts-json-schema-generator';
import {getValidatableTypes} from './get-validatable-types.js';
import {JSONSchema7} from 'json-schema';
/**
* Compile the JSON schema for a path
* @param path {string}
* @param tsconfig {string}
* @returns {[schema: import('json-schema').JSONSchema7, type: string]}
*/
export function compileSchema(path: string, tsconfig: string): [schma: JSONSchema7, type: string] {
export function compileSchema(path, tsconfig) {
const generator = createGenerator({
path,
tsconfig,

View File

@@ -2,10 +2,13 @@ import {ts} from 'ts-json-schema-generator';
/**
* Get all types with `@validatable` annotations
* @param program {ts.Program}
* @returns {Set<string>}
*/
export function getValidatableTypes(program: ts.Program) {
export function getValidatableTypes(program) {
const checker = program.getTypeChecker();
const declarationNames = new Set<string>();
/** @type {Set<string>} */
const declarationNames = new Set();
for (const sourceFile of program.getSourceFiles()) {
const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile);
@@ -27,8 +30,10 @@ export function getValidatableTypes(program: ts.Program) {
/**
* Type predicate for if a JSDoc tag is `@validatable`
* @param tag {ts.JSDocTag}
* @returns {tag is ts.JSDocTag}
*/
// eslint-disable-next-line unicorn/prevent-abbreviations
function isValidatableJSDocTag(tag: ts.JSDocTag): tag is ts.JSDocTag {
function isValidatableJSDocTag(tag) {
return tag.tagName.escapedText === 'validatable';
}

View File

@@ -1,11 +1,7 @@
import {compileSchema} from './generator/compile-schema.js';
import {generateFiles, Plugin, PluginContext} from '@openstapps/tsup-plugin';
import {JSONSchema7} from 'json-schema';
import {Plugin as EsbuildPlugin} from 'esbuild';
import {generateFiles} from '@openstapps/tsup-plugin';
import {createGenerator} from 'ts-json-schema-generator';
export type SchemaConsumer = (this: PluginContext, schema: JSONSchema7) => Record<string, string | Buffer>;
/**
* ESBuild Plugin for directly importing schemas
*
@@ -19,13 +15,16 @@ export type SchemaConsumer = (this: PluginContext, schema: JSONSchema7) => Recor
* interface Bar {}
* // ./schema-consumer.ts
* import {default as barSchema} from 'schema:./my-type.js#Bar'
*
* @type {import('esbuild').Plugin}
*/
export const esbuildJsonSchemaPlugin: EsbuildPlugin = {
export const esbuildJsonSchemaPlugin = {
name: 'json-schema',
setup(build) {
const fileRegex = /^schema:/;
const namespace = 'json-schema-ns';
const schemas = new Map<string, string>();
/** @type {Map<string, string>} */
const schemas = new Map();
build.onResolve({filter: fileRegex}, ({path, importer}) => {
const [from, name] = path.replace(fileRegex, '').split('#', 1);
@@ -56,22 +55,22 @@ export const esbuildJsonSchemaPlugin: EsbuildPlugin = {
/**
* TSUp plugin for generating JSONSchema files
* @param schemaName the name of the generated schema
* @param schemaConsumers any consumers that can directly use the schema
* @param schemaName {string} the name of the generated schema
* @param schemaConsumers {Array<[string, import('./types.js').SchemaConsumer]>} any consumers
* that can directly use the schema
* @returns {import('@openstapps/tsup-plugin').Plugin}
*/
export function jsonSchemaPlugin(
schemaName: string,
...schemaConsumers: Array<[string, SchemaConsumer]>
): Plugin {
export function jsonSchemaPlugin(schemaName, ...schemaConsumers) {
return {
name: 'json-schema-generator',
async buildEnd() {
let schema: JSONSchema7;
/** @type {import('json-schema').JSONSchema7} */
let schema;
await generateFiles('JSON-Schema', async function () {
const [jsonSchema, types] = compileSchema(
(this.options.entry as string[])[0],
this.options.tsconfig!,
);
if (!this.options.tsconfig) throw new Error('Must supply a tsconfig');
if (!Array.isArray(this.options.entry)) throw new Error('Must supply entry as an array');
const [jsonSchema, types] = compileSchema(this.options.entry[0], this.options.tsconfig);
schema = jsonSchema;
return {

View File

@@ -0,0 +1,6 @@
import {JSONSchema7} from 'json-schema';
import {PluginContext} from '@openstapps/tsup-plugin/src/types.js';
export type SchemaConsumer = (this: PluginContext, schema: JSONSchema7) => Record<string, string | Buffer>;
export {compileSchema, jsonSchemaPlugin, esbuildJsonSchemaPlugin} from './index.js';

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* This is a simple interface declaration for
* testing the schema generation and validation.
*
* @validatable
*/
export interface Foo {
/**
* lorem parameter
*/
lorem: 'lorem' | 'ipsum';
/**
* String literal type property
*/
type: FooType;
}
/**
* This is a simple type declaration for
* usage in the Foo interface.
*/
export type FooType = 'Foo';

View File

@@ -13,46 +13,36 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Logger} from 'packages/logger/lib/index.js';
import {expect} from 'chai';
import {Converter} from '../../core-tools/src/schema.js';
import {compileSchema} from '../src/index.js';
import path from 'path';
import {fileURLToPath} from 'url';
process.on('unhandledRejection', (error: unknown) => {
if (error instanceof Error) {
void Logger.error('UNHANDLED REJECTION', error.stack);
}
process.exit(1);
});
describe('Schema', function () {
this.timeout(40_000);
this.slow(10_000);
it('should create schema', function () {
const converter = new Converter(
const [schema, _types] = compileSchema(
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources'),
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'tsconfig.json'),
);
const schema = converter.getSchema('Foo', '0.0.1');
expect(schema).to.be.deep.equal({
$id: 'https://core.stapps.tu-berlin.de/v0.0.1/lib/schema/Foo.json',
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
definitions: {
FooType: {
description: 'This is a simple type declaration for usage in the Foo interface.',
const: 'Foo',
type: 'string',
},
SCFoo: {
Foo: {
additionalProperties: false,
description:
'This is a simple interface declaration for testing the schema generation and validation.',
properties: {
lorem: {
description: 'Dummy parameter',
description: 'lorem parameter',
enum: ['lorem', 'ipsum'],
type: 'string',
},
@@ -65,20 +55,6 @@ describe('Schema', function () {
type: 'object',
},
},
description: 'This is a simple interface declaration for testing the schema generation and validation.',
properties: {
lorem: {
description: 'Dummy parameter',
enum: ['lorem', 'ipsum'],
type: 'string',
},
type: {
$ref: '#/definitions/FooType',
description: 'String literal type property',
},
},
required: ['lorem', 'type'],
type: 'object',
});
});
});