@preserves/schema
Advanced tools
Comparing version 0.1.1 to 0.2.0
@@ -201,2 +201,3 @@ (function (global, factory) { | ||
const EQUALS = Symbol.for('='); | ||
const INCLUDE = Symbol.for('include'); | ||
const ORSYM = Symbol.for('/'); | ||
@@ -278,42 +279,59 @@ function modsymFor(e) { | ||
} | ||
function _readSchema(source, options) { | ||
return new _.Reader(source, Object.assign(Object.assign({}, options !== null && options !== void 0 ? options : {}), { includeAnnotations: true })).readToEnd(); | ||
} | ||
function readSchema(source, options) { | ||
const toplevelTokens = new _.Reader(source, Object.assign(Object.assign({}, options !== null && options !== void 0 ? options : {}), { includeAnnotations: true })).readToEnd(); | ||
return parseSchema(toplevelTokens); | ||
return parseSchema(_readSchema(source, options), options !== null && options !== void 0 ? options : {}); | ||
} | ||
function parseSchema(toplevelTokens) { | ||
const toplevelClauses = splitBy(_.peel(toplevelTokens), DOT); | ||
function parseSchema(toplevelTokens, options) { | ||
let version = void 0; | ||
let pointer = false; | ||
let definitions = new _.Dictionary(); | ||
for (const clause of toplevelClauses) { | ||
if (!Array.isArray(clause)) { | ||
invalidClause(clause); | ||
} | ||
else if (clause.length >= 2 && _.is(clause[1], EQUALS)) { | ||
const name = _.peel(clause[0]); | ||
if (typeof name !== 'symbol') | ||
function process(toplevelTokens) { | ||
const toplevelClauses = splitBy(_.peel(toplevelTokens), DOT); | ||
for (const clause of toplevelClauses) { | ||
if (!Array.isArray(clause)) { | ||
invalidClause(clause); | ||
if (!isValidToken(name.description)) { | ||
throw new SchemaSyntaxError(_.preserves `Invalid definition name: ${name}`, _.position(clause[0])); | ||
} | ||
if (definitions.has(name)) { | ||
throw new SchemaSyntaxError(_.preserves `Duplicate definition: ${clause}`, _.position(clause[0])); | ||
else if (clause.length >= 2 && _.is(clause[1], EQUALS)) { | ||
const pos = _.position(clause[0]); | ||
const name = _.peel(clause[0]); | ||
if (typeof name !== 'symbol') | ||
invalidClause(clause); | ||
if (!isValidToken(name.description)) { | ||
throw new SchemaSyntaxError(_.preserves `Invalid definition name: ${name}`, pos); | ||
} | ||
if (definitions.has(name)) { | ||
throw new SchemaSyntaxError(_.preserves `Duplicate definition: ${clause}`, pos); | ||
} | ||
definitions.set(name, parseDefinition(name, clause.slice(2))); | ||
} | ||
definitions.set(name, parseDefinition(name, clause.slice(2))); | ||
else if (clause.length === 2 && _.is(clause[0], $version)) { | ||
version = asVersion(_.peel(clause[1])); | ||
} | ||
else if (clause.length === 2 && _.is(clause[0], $pointer)) { | ||
const pos = _.position(clause[1]); | ||
const stx = _.peel(clause[1]); | ||
const quasiName = 'pointer name specification'; | ||
pointer = asPointerName((stx === false) ? stx | ||
: (typeof stx === 'symbol') ? parseRef(quasiName, pos, stx) | ||
: invalidPattern(quasiName, stx, pos)); | ||
} | ||
else if (clause.length === 2 && _.is(clause[0], INCLUDE)) { | ||
const pos = _.position(clause[1]); | ||
const path = _.peel(clause[1]); | ||
if (typeof path !== 'string') { | ||
throw new SchemaSyntaxError(_.preserves `Invalid include: ${clause}`, pos); | ||
} | ||
if (options.readInclude === void 0) { | ||
throw new SchemaSyntaxError(_.preserves `Cannot include files in schema`, pos); | ||
} | ||
process(_readSchema(options.readInclude(path), options)); | ||
} | ||
else { | ||
invalidClause(clause); | ||
} | ||
} | ||
else if (clause.length === 2 && _.is(clause[0], $version)) { | ||
version = asVersion(_.peel(clause[1])); | ||
} | ||
else if (clause.length === 2 && _.is(clause[0], $pointer)) { | ||
const pos = _.position(clause[1]); | ||
const stx = _.peel(clause[1]); | ||
const quasiName = 'pointer name specification'; | ||
pointer = asPointerName((stx === false) ? stx | ||
: (typeof stx === 'symbol') ? parseRef(quasiName, pos, stx) | ||
: invalidPattern(quasiName, stx, pos)); | ||
} | ||
else { | ||
invalidClause(clause); | ||
} | ||
} | ||
process(toplevelTokens); | ||
if (version === void 0) { | ||
@@ -663,5 +681,5 @@ throw new SchemaSyntaxError("Schema: missing version declaration.", null); | ||
case $setof: | ||
return seq('_.KeyedSet<', typeFor(p[0]), '>'); | ||
return seq('_.KeyedSet', anglebrackets(typeFor(p[0]), '_ptr')); | ||
case $dictof: | ||
return seq('_.KeyedDictionary', anglebrackets(typeFor(p[0]), typeFor(p[1]))); | ||
return seq('_.KeyedDictionary', anglebrackets(typeFor(p[0]), typeFor(p[1]), '_ptr')); | ||
case $dict: | ||
@@ -668,0 +686,0 @@ return parens(seq(block(...Array.from(p[0]).map(([k, vp]) => seq(`get(k: typeof ${literal(k)}): `, typeFor(vp))), ...Array.from(p[0]).map(([k, _vp]) => seq(`has(k: typeof ${literal(k)}): true`))), ' & _.Dictionary<_val, _ptr>')); |
{ | ||
"name": "@preserves/schema", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"description": "Schema support for Preserves data serialization format", | ||
@@ -34,2 +34,3 @@ "homepage": "https://gitlab.com/preserves/preserves", | ||
"chalk": "^4.1.0", | ||
"chokidar": "^3.5.1", | ||
"glob": "^7.1.6", | ||
@@ -36,0 +37,0 @@ "minimatch": "^3.0.4", |
@@ -46,2 +46,3 @@ import { terser } from 'rollup-plugin-terser'; | ||
'chalk', | ||
'chokidar', | ||
'fs', | ||
@@ -48,0 +49,0 @@ 'glob', |
@@ -10,2 +10,3 @@ import { compile, readSchema } from '../index'; | ||
import { formatPosition, Position } from '@preserves/core'; | ||
import chokidar from 'chokidar'; | ||
@@ -88,4 +89,5 @@ export type CommandLineArguments = { | ||
` Processed ${r.inputFiles.length} file(s) ${errorSummary}. Waiting for changes.`); | ||
const watcher = fs.watch(r.base, { recursive: true }, (_event, filename) => { | ||
filename = path.join(r.base, filename); | ||
const watcher = chokidar.watch(r.base, { | ||
ignoreInitial: true, | ||
}).on('all', (_event, filename) => { | ||
if (minimatch(filename, options.input)) { | ||
@@ -139,3 +141,10 @@ watcher.close(); | ||
const src = fs.readFileSync(inputFilePath, 'utf-8'); | ||
const schema = readSchema(src, { name: inputFilePath }); | ||
const schema = readSchema(src, { | ||
name: inputFilePath, | ||
readInclude(includePath: string): string { | ||
return fs.readFileSync( | ||
path.resolve(path.dirname(inputFilePath), includePath), | ||
'utf-8'); | ||
}, | ||
}); | ||
const schemaPath = relPath.split('/').map(p => p.split('.')[0]).map(Symbol.for); | ||
@@ -142,0 +151,0 @@ return [{ inputFilePath, outputFilePath, schemaPath, schema }]; |
@@ -93,5 +93,5 @@ import { Pattern, NamedPattern, Schema, Input, Environment, Ref, lookup } from "./meta"; | ||
case M.$setof: | ||
return seq('_.KeyedSet<', typeFor(p[0]), '>'); | ||
return seq('_.KeyedSet', anglebrackets(typeFor(p[0]), '_ptr')); | ||
case M.$dictof: | ||
return seq('_.KeyedDictionary', anglebrackets(typeFor(p[0]), typeFor(p[1]))); | ||
return seq('_.KeyedDictionary', anglebrackets(typeFor(p[0]), typeFor(p[1]), '_ptr')); | ||
case M.$dict: | ||
@@ -98,0 +98,0 @@ return parens(seq( |
@@ -22,2 +22,3 @@ import { Value, is, Position } from '@preserves/core'; | ||
export const EQUALS = Symbol.for('='); | ||
export const INCLUDE = Symbol.for('include'); | ||
export const ORSYM = Symbol.for('/'); | ||
@@ -24,0 +25,0 @@ |
@@ -47,43 +47,73 @@ import { Reader, Annotated, Dictionary, is, peel, preserves, Record, strip, Tuple, Value, Position, position, ReaderOptions, stringify } from '@preserves/core'; | ||
export function readSchema(source: string, options?: ReaderOptions<never>): Schema { | ||
const toplevelTokens = new Reader<never>(source, { ... options ?? {}, includeAnnotations: true }).readToEnd(); | ||
return parseSchema(toplevelTokens); | ||
export type SchemaReaderOptions = { | ||
readInclude?(includePath: string): string; | ||
}; | ||
function _readSchema(source: string, options?: ReaderOptions<never>): Array<Input> { | ||
return new Reader<never>(source, { | ||
... options ?? {}, | ||
includeAnnotations: true | ||
}).readToEnd(); | ||
} | ||
export function parseSchema(toplevelTokens: Array<Input>): Schema { | ||
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT); | ||
export function readSchema(source: string, | ||
options?: ReaderOptions<never> & SchemaReaderOptions): Schema | ||
{ | ||
return parseSchema(_readSchema(source, options), options ?? {}); | ||
} | ||
export function parseSchema(toplevelTokens: Array<Input>, | ||
options: ReaderOptions<never> & SchemaReaderOptions): Schema | ||
{ | ||
let version: M.Version | undefined = void 0; | ||
let pointer: M.PointerName = false; | ||
let definitions = new Dictionary<Pattern, never>(); | ||
for (const clause of toplevelClauses) { | ||
if (!Array.isArray(clause)) { | ||
invalidClause(clause); | ||
} else if (clause.length >= 2 && is(clause[1], M.EQUALS)) { | ||
const name = peel(clause[0]); | ||
if (typeof name !== 'symbol') invalidClause(clause); | ||
if (!M.isValidToken(name.description!)) { | ||
throw new SchemaSyntaxError(preserves`Invalid definition name: ${name}`, | ||
position(clause[0])); | ||
function process(toplevelTokens: Array<Input>): void { | ||
const toplevelClauses = splitBy(peel(toplevelTokens) as Array<Input>, M.DOT); | ||
for (const clause of toplevelClauses) { | ||
if (!Array.isArray(clause)) { | ||
invalidClause(clause); | ||
} else if (clause.length >= 2 && is(clause[1], M.EQUALS)) { | ||
const pos = position(clause[0]); | ||
const name = peel(clause[0]); | ||
if (typeof name !== 'symbol') invalidClause(clause); | ||
if (!M.isValidToken(name.description!)) { | ||
throw new SchemaSyntaxError(preserves`Invalid definition name: ${name}`, pos); | ||
} | ||
if (definitions.has(name)) { | ||
throw new SchemaSyntaxError(preserves`Duplicate definition: ${clause}`, pos); | ||
} | ||
definitions.set(name, parseDefinition(name, clause.slice(2))); | ||
} else if (clause.length === 2 && is(clause[0], M.$version)) { | ||
version = M.asVersion(peel(clause[1])); | ||
} else if (clause.length === 2 && is(clause[0], M.$pointer)) { | ||
const pos = position(clause[1]); | ||
const stx = peel(clause[1]); | ||
const quasiName = 'pointer name specification'; | ||
pointer = M.asPointerName((stx === false) ? stx | ||
: (typeof stx === 'symbol') ? parseRef(quasiName, pos, stx) | ||
: invalidPattern(quasiName, stx, pos)); | ||
} else if (clause.length === 2 && is(clause[0], M.INCLUDE)) { | ||
const pos = position(clause[1]); | ||
const path = peel(clause[1]); | ||
if (typeof path !== 'string') { | ||
throw new SchemaSyntaxError(preserves`Invalid include: ${clause}`, pos); | ||
} | ||
if (options.readInclude === void 0) { | ||
throw new SchemaSyntaxError(preserves`Cannot include files in schema`, pos); | ||
} | ||
process(_readSchema(options.readInclude(path), options)); | ||
} else { | ||
invalidClause(clause); | ||
} | ||
if (definitions.has(name)) { | ||
throw new SchemaSyntaxError(preserves`Duplicate definition: ${clause}`, | ||
position(clause[0])); | ||
} | ||
definitions.set(name, parseDefinition(name, clause.slice(2))); | ||
} else if (clause.length === 2 && is(clause[0], M.$version)) { | ||
version = M.asVersion(peel(clause[1])); | ||
} else if (clause.length === 2 && is(clause[0], M.$pointer)) { | ||
const pos = position(clause[1]); | ||
const stx = peel(clause[1]); | ||
const quasiName = 'pointer name specification'; | ||
pointer = M.asPointerName((stx === false) ? stx | ||
: (typeof stx === 'symbol') ? parseRef(quasiName, pos, stx) | ||
: invalidPattern(quasiName, stx, pos)); | ||
} else { | ||
invalidClause(clause); | ||
} | ||
} | ||
process(toplevelTokens); | ||
if (version === void 0) { | ||
throw new SchemaSyntaxError("Schema: missing version declaration.", null); | ||
} | ||
return M.asSchema(Record(M.$schema, [new Dictionary<Value>([ | ||
@@ -90,0 +120,0 @@ [M.$version, version], |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
91478
2206
9
+ Addedchokidar@^3.5.1
+ Addedanymatch@3.1.3(transitive)
+ Addedbinary-extensions@2.3.0(transitive)
+ Addedbraces@3.0.3(transitive)
+ Addedchokidar@3.6.0(transitive)
+ Addedfill-range@7.1.1(transitive)
+ Addedfsevents@2.3.3(transitive)
+ Addedglob-parent@5.1.2(transitive)
+ Addedis-binary-path@2.1.0(transitive)
+ Addedis-extglob@2.1.1(transitive)
+ Addedis-glob@4.0.3(transitive)
+ Addedis-number@7.0.0(transitive)
+ Addednormalize-path@3.0.0(transitive)
+ Addedpicomatch@2.3.1(transitive)
+ Addedreaddirp@3.6.0(transitive)
+ Addedto-regex-range@5.0.1(transitive)