Dumber but more reliable and more useful handling of schema input base directories
This commit is contained in:
parent
bfa0b0bcb4
commit
944ac54414
|
@ -13,7 +13,7 @@
|
|||
"types": "lib/index.d.ts",
|
||||
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
|
||||
"scripts": {
|
||||
"regenerate": "rm -rf ./src/gen && ./bin/preserves-schema-ts.js --output ./src/gen ../../../../schema/schema.prs",
|
||||
"regenerate": "rm -rf ./src/gen && ./bin/preserves-schema-ts.js --output ./src/gen ../../../../schema:schema.prs",
|
||||
"clean": "rm -rf lib dist",
|
||||
"prepare": "tsc && rollup -c",
|
||||
"rollupwatch": "rollup -c -w",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
import { formatPosition, Position } from '@preserves/core';
|
||||
import { IdentitySet, formatPosition, Position } from '@preserves/core';
|
||||
import { readSchema } from '../reader';
|
||||
import chalk from 'chalk';
|
||||
import * as M from '../meta';
|
||||
|
@ -13,6 +13,7 @@ export interface Diagnostic {
|
|||
};
|
||||
|
||||
export type InputFile = {
|
||||
inputBaseDir: string,
|
||||
inputFilePath: string,
|
||||
text: string,
|
||||
baseRelPath: string,
|
||||
|
@ -28,7 +29,7 @@ export type XrefFile = {
|
|||
};
|
||||
|
||||
export type Expanded = {
|
||||
base: string,
|
||||
baseDirs: Array<string>,
|
||||
inputFiles: Array<InputFile>,
|
||||
xrefFiles: Array<XrefFile>,
|
||||
failures: Array<Diagnostic>,
|
||||
|
@ -54,18 +55,29 @@ export function computeBase(paths: string[]): string {
|
|||
}
|
||||
}
|
||||
|
||||
export function expandInputGlob(
|
||||
input: string[],
|
||||
xrefs: string[],
|
||||
base0: string | undefined,
|
||||
): Expanded {
|
||||
const matches = input.flatMap(i => glob.sync(i));
|
||||
export function findSchemas(userInput: string): ({
|
||||
names: string[],
|
||||
base: string,
|
||||
}) {
|
||||
const colonPos = userInput.lastIndexOf(':');
|
||||
let [base, g] = (colonPos === -1)
|
||||
? [userInput, '**/*.prs']
|
||||
: [userInput.slice(0, colonPos), userInput.slice(colonPos + 1)];
|
||||
if (base[base.length - 1] !== '/') {
|
||||
base = base + '/';
|
||||
}
|
||||
const names = glob.sync(base + g);
|
||||
return { names, base };
|
||||
}
|
||||
|
||||
export function expandInputGlob(input: string[], xrefs: string[]): Expanded {
|
||||
const failures: Array<Diagnostic> = [];
|
||||
const baseDirs = new IdentitySet<string>();
|
||||
|
||||
function processInputFile(base: string, filePath: string, xref: true): XrefFile[];
|
||||
function processInputFile(base: string, filePath: string, xref: false): InputFile[];
|
||||
function processInputFile(base: string, filePath: string, xref: boolean): (InputFile | XrefFile)[] {
|
||||
if (!xref && !filePath.startsWith(base)) {
|
||||
if (!filePath.startsWith(base)) {
|
||||
throw new Error(`Input filename ${filePath} falls outside base ${base}`);
|
||||
}
|
||||
try {
|
||||
|
@ -83,7 +95,7 @@ export function expandInputGlob(
|
|||
if (xref) {
|
||||
return [{ xrefFilePath: filePath, text, modulePath, schema }];
|
||||
} else {
|
||||
return [{ inputFilePath: filePath, text, baseRelPath, modulePath, schema }];
|
||||
return [{ inputBaseDir: base, inputFilePath: filePath, text, baseRelPath, modulePath, schema }];
|
||||
}
|
||||
} catch (e) {
|
||||
failures.push({ type: 'error', file: filePath, detail: e as Error });
|
||||
|
@ -91,16 +103,22 @@ export function expandInputGlob(
|
|||
}
|
||||
}
|
||||
|
||||
const base = base0 ?? computeBase(matches);
|
||||
const inputFiles = input.flatMap(userInput => {
|
||||
const { names, base } = findSchemas(userInput);
|
||||
baseDirs.add(base);
|
||||
return names.flatMap(f => processInputFile(base, f, false));
|
||||
});
|
||||
|
||||
const xrefFiles = xrefs.flatMap(userInput => {
|
||||
const { names, base } = findSchemas(userInput);
|
||||
baseDirs.add(base);
|
||||
return names.flatMap(f => processInputFile(base, f, true));
|
||||
});
|
||||
|
||||
return {
|
||||
base,
|
||||
inputFiles: matches.flatMap(f => processInputFile(base, f, false)),
|
||||
xrefFiles: xrefs.flatMap(i => {
|
||||
const names = glob.sync(i);
|
||||
const base = computeBase(names);
|
||||
return names.flatMap(f => processInputFile(base, f, true));
|
||||
}),
|
||||
baseDirs: Array.from(baseDirs),
|
||||
inputFiles,
|
||||
xrefFiles,
|
||||
failures,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export type CommandLineArguments = {
|
|||
inputs: string[];
|
||||
xrefs: string[];
|
||||
base: string | undefined;
|
||||
output: string | undefined;
|
||||
output: string;
|
||||
stdout: boolean;
|
||||
core: string;
|
||||
watch: boolean;
|
||||
|
@ -25,11 +25,11 @@ export type CompilationResult = {
|
|||
options: CommandLineArguments,
|
||||
inputFiles: Array<TranslatedFile>,
|
||||
failures: Array<Diagnostic>,
|
||||
base: string,
|
||||
output: string,
|
||||
baseDirs: Array<string>,
|
||||
};
|
||||
|
||||
export type TranslatedFile = {
|
||||
inputBaseDir: string,
|
||||
inputFilePath: string,
|
||||
outputFilePath: string,
|
||||
schemaPath: M.ModulePath,
|
||||
|
@ -62,14 +62,18 @@ export function run(options: CommandLineArguments): void {
|
|||
chalk.greenBright('successfully');
|
||||
console.log(chalk.gray(new Date().toISOString()) +
|
||||
` Processed ${r.inputFiles.length} file(s) ${errorSummary}. Waiting for changes.`);
|
||||
const watcher = chokidar.watch(r.base, {
|
||||
let triggered = false;
|
||||
const watchers = r.baseDirs.map(base => chokidar.watch(base, {
|
||||
ignoreInitial: true,
|
||||
}).on('all', (_event, filename) => {
|
||||
if (options.inputs.some(i => minimatch(filename, i))) {
|
||||
watcher.close();
|
||||
runWatch();
|
||||
if (!triggered) {
|
||||
triggered = true;
|
||||
watchers.map(w => w.close());
|
||||
runWatch();
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
runWatch();
|
||||
}
|
||||
|
@ -86,9 +90,8 @@ function isAbsoluteOrExplicitlyRelative(p: string) {
|
|||
}
|
||||
|
||||
export function runOnce(options: CommandLineArguments): CompilationResult {
|
||||
const { base, failures, inputFiles: inputFiles0, xrefFiles: xrefFiles0 } =
|
||||
expandInputGlob(options.inputs, options.xrefs, options.base);
|
||||
const output = options.output ?? base;
|
||||
const { baseDirs, failures, inputFiles: inputFiles0, xrefFiles: xrefFiles0 } =
|
||||
expandInputGlob(options.inputs, options.xrefs);
|
||||
|
||||
let xrefFiles = xrefFiles0; // filtered during construction of extensionEnv
|
||||
|
||||
|
@ -112,9 +115,9 @@ export function runOnce(options: CommandLineArguments): CompilationResult {
|
|||
});
|
||||
|
||||
const inputFiles: Array<TranslatedFile> = inputFiles0.map(i => {
|
||||
const { inputFilePath, baseRelPath, modulePath, schema } = i;
|
||||
const outputFilePath = path.join(output, changeExt(baseRelPath, '.ts'));
|
||||
return { inputFilePath, outputFilePath, schemaPath: modulePath, schema };
|
||||
const { inputBaseDir, inputFilePath, baseRelPath, modulePath, schema } = i;
|
||||
const outputFilePath = path.join(options.output, changeExt(baseRelPath, '.ts'));
|
||||
return { inputBaseDir, inputFilePath, outputFilePath, schemaPath: modulePath, schema };
|
||||
});
|
||||
|
||||
inputFiles.forEach(c => {
|
||||
|
@ -164,7 +167,7 @@ export function runOnce(options: CommandLineArguments): CompilationResult {
|
|||
|
||||
formatFailures(failures, options.traceback);
|
||||
|
||||
return { options, inputFiles, failures, base, output };
|
||||
return { options, inputFiles, failures, baseDirs };
|
||||
}
|
||||
|
||||
export function main(argv: Array<string>) {
|
||||
|
|
|
@ -7,12 +7,11 @@ import { expandInputGlob, formatFailures } from './cli-utils';
|
|||
|
||||
export type CommandLineArguments = {
|
||||
inputs: string[];
|
||||
base: string | undefined;
|
||||
bundle: boolean;
|
||||
};
|
||||
|
||||
export function run(options: CommandLineArguments): void {
|
||||
const { failures, inputFiles } = expandInputGlob(options.inputs, [], options.base);
|
||||
const { failures, inputFiles } = expandInputGlob(options.inputs, []);
|
||||
|
||||
if (!options.bundle && inputFiles.length !== 1) {
|
||||
failures.push({ type: 'error', file: null, detail: {
|
||||
|
@ -41,14 +40,12 @@ export function main(argv: Array<string>) {
|
|||
new Command()
|
||||
.arguments('[input...]')
|
||||
.description('Compile textual Preserves schema definitions to binary format', {
|
||||
input: 'Input filename or glob',
|
||||
input: 'Input directory, with optional ":glob" appended (defaults to ":**/*.prs")',
|
||||
})
|
||||
.option('--no-bundle', 'Emit a single Schema instead of a schema Bundle')
|
||||
.option('--base <directory>', 'Base directory for sources (default: common prefix)')
|
||||
.action((inputs: string[], rawOptions) => {
|
||||
const options: CommandLineArguments = {
|
||||
inputs: inputs.map(i => path.normalize(i)),
|
||||
base: rawOptions.base,
|
||||
bundle: rawOptions.bundle,
|
||||
};
|
||||
Error.stackTraceLimit = Infinity;
|
||||
|
|
Loading…
Reference in New Issue