-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgulpfile.js
163 lines (138 loc) · 4.84 KB
/
gulpfile.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const gulp = require('gulp');
const fs = require('fs');
const path = require('path');
const spawn = require('child_process').spawn;
const tsj = require("ts-json-schema-generator");
const esbuild = require("esbuild");
const Ajv = require("ajv");
const addFormats = require("ajv-formats");
const standaloneCode = require("ajv/dist/standalone");
/**
* Runs a command, returns the stdout on a successful exit code(0)
* @param command The executable name
* @param args The args as a string
* @param cwd Current Working Directory
* @param echoOutputs Pipes the command standard streams directly to this process to get the output as it is happening,
* not waiting for the exit code
* @param prefixOutputs Useful if running multiple commands in parallel
* @param extraEnv Extra variables to pass as Environment variables
* @return {Promise<string>}
*/
async function execCommand(command, args, cwd = __dirname, echoOutputs = true, prefixOutputs = "", extraEnv = {})
{
return new Promise((resolve, reject) =>
{
let allData = "";
let errOutput = "";
const call = spawn(command, [args], {shell: true, windowsVerbatimArguments: true, cwd: cwd, env: {...process.env, ...extraEnv} });
call.stdout.on('data', function (data)
{
allData += data.toString();
echoOutputs && process.stdout.write(prefixOutputs + data.toString());
});
call.stderr.on('data', function (data)
{
errOutput = data.toString();
echoOutputs && process.stdout.write(prefixOutputs + data.toString());
});
call.on('exit', function (code)
{
if (code == 0)
resolve(allData);
else
reject({command, args, stdout: allData, stderr: errOutput});
});
});
}
function clearDir(destDir)
{
fs.rmSync(destDir, { recursive: true, force: true });
fs.mkdirSync(destDir, {recursive: true});
}
function typeScriptToJsonSchema(srcDir, destDir)
{
const config = {
path: srcDir+"/**/*.ts",
type: "*",
};
let schemas = [];
console.time("* TS TO JSONSCHEMA");
let schemaRaw = tsj.createGenerator(config).createSchema(config.type);
console.timeEnd("* TS TO JSONSCHEMA");
/* Remove all `#/definitions/` so that we can use the Type name as the $id and have matching $refs with the other Types */
let schema = JSON.parse(JSON.stringify(schemaRaw).replace(/#\/definitions\//gm, ""));
/* Save each Type jsonschema individually, use the Type name as $id */
for(let [id, definition] of Object.entries(schema.definitions))
{
let singleTypeDefinition = {
"$id": id,
"$schema": "http://json-schema.org/draft-07/schema#",
...definition,
};
schemas.push(singleTypeDefinition);
fs.writeFileSync(path.resolve(destDir+"/"+id+".json"), JSON.stringify(singleTypeDefinition, null, 2));
}
return schemas;
}
function compileAjvStandalone(schemas, validationFile)
{
console.time("* AJV COMPILE");
const ajv = new Ajv({schemas: schemas, code: {source: true, esm: true}});
addFormats(ajv);
let moduleCode = standaloneCode(ajv);
console.timeEnd("* AJV COMPILE");
fs.writeFileSync(validationFile, moduleCode);
}
function esBuildCommonToEsm(validationFile)
{
console.time("* ES BUILD");
esbuild.buildSync({
// minify: true,
bundle: true,
target: ["node14"],
keepNames: true,
platform: 'node',
format: "esm",
entryPoints: [validationFile],
outfile: validationFile,
allowOverwrite: true
});
console.timeEnd("* ES BUILD");
}
async function generateTypings(validationFile, validationFileFolder)
{
console.time("* TSC DECLARATIONS");
await execCommand("tsc","-allowJs --declaration --emitDeclarationOnly \""+validationFile+"\" --outDir \""+validationFileFolder+"\"");
console.timeEnd("* TSC DECLARATIONS");
}
async function buildTypes()
{
let paths = {
types: path.resolve(__dirname + "/types"),
typesJsonSchema: path.resolve(__dirname + "/types/schemas"),
validationFile: path.resolve(__dirname + "/types/schemas/validations.js"),
};
/* Clear the output dir for the AJV validation code, definition and JSON Schema definitions */
clearDir(paths.typesJsonSchema);
/* Create the JSON Schema files from the TS Types and save them as individual JSON Schema files */
let schemas = typeScriptToJsonSchema(paths.types, paths.typesJsonSchema);
/* Create the AJV validation code in ESM format from the JSON Schema files */
compileAjvStandalone(schemas, paths.validationFile);
/* Bundle the AJV validation code file in ESM format */
esBuildCommonToEsm(paths.validationFile);
/* Create TypeScript typings for the generated AJV validation code */
await generateTypings(paths.validationFile, paths.typesJsonSchema);
}
gulp.task('build_types', async () =>
{
await buildTypes();
});
gulp.task('watch_types', async () =>
{
await buildTypes();
gulp.watch(['types/*.ts'], async function(cb)
{
await buildTypes();
cb();
});
});