preserves/implementations/javascript/packages/schema/src/bin/preserves-schema-ts.ts

103 lines
3.6 KiB
TypeScript
Raw Normal View History

2021-03-11 09:56:49 +00:00
import { compile, readSchema } from '../index';
import fs from 'fs';
2021-03-11 09:56:49 +00:00
import path from 'path';
import { glob } from 'glob';
import yargs from 'yargs/yargs';
import * as M from '../meta';
export type CommandLineArguments = {
input: string;
base: string | undefined;
output: string | undefined;
core: string;
};
export function computeBase(paths: string[]): string {
if (paths.length === 0) {
return '';
} else if (paths.length === 1) {
return path.dirname(paths[0]) + '/';
} else {
let i = 0;
while (true) {
let ch: string | null = null
for (const p of paths) {
if (i >= p.length) return p.slice(0, i);
if (ch === null) ch = p[i];
if (p[i] !== ch) return p.slice(0, i - 1);
}
i++;
}
}
}
type ToCompile = {
inputFilePath: string,
outputFilePath: string,
schemaPath: M.ModulePath,
schema: M.Schema,
};
function changeExt(p: string, newext: string) {
return p.slice(0, -path.extname(p).length) + newext;
}
export function run(options: CommandLineArguments) {
glob(options.input, (err, matches) => {
if (err) throw err;
const base = options.base ?? computeBase(matches);
const output = options.output ?? base;
const toCompile: Array<ToCompile> = matches.map(inputFilePath => {
if (!inputFilePath.startsWith(base)) {
throw new Error(`Input filename ${inputFilePath} falls outside base ${base}`);
}
const relPath = inputFilePath.slice(base.length);
const outputFilePath = path.join(output, changeExt(relPath, '.ts'));
const src = fs.readFileSync(inputFilePath, 'utf-8');
const schema = readSchema(src);
const schemaPath = relPath.split(path.delimiter).map(p => p.split('.')[0]).map(Symbol.for);
return { inputFilePath, outputFilePath, schemaPath, schema };
});
toCompile.forEach(c => {
const env: M.Environment = toCompile.map(cc => ({
schema: cc.schema,
schemaModulePath: cc.schemaPath,
typescriptModulePath: path.relative(c.outputFilePath, cc.outputFilePath) || null,
}));
fs.mkdirSync(path.dirname(c.outputFilePath), { recursive: true });
fs.writeFileSync(c.outputFilePath, compile(env, c.schema, options.core), 'utf-8');
});
});
}
export function main(argv: Array<string>) {
2021-03-11 09:56:49 +00:00
const options: CommandLineArguments = yargs(argv)
.command('$0 <input>',
'Compile Preserves schema definitions to TypeScript',
yargs => yargs
.positional('input', {
type: 'string',
description: 'Input filename or glob',
demandOption: true,
})
.option('output', {
type: 'string',
description: 'Output directory for sources (default: next to sources)',
})
.option('base', {
type: 'string',
description: 'Base directory for sources (default: common prefix)',
})
.option('core', {
type: 'string',
description: 'Import path for @preserves/core',
default: '@preserves/core',
}),
argv => argv)
.argv;
run(options);
}