generated from astrohelm/node-workspace
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
1,032 additions
and
1,027 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,35 @@ | ||
'use strict'; | ||
|
||
module.exports = require('./lib/schema'); | ||
const Forge = require('./lib/forge'); | ||
const createError = require('./lib/error'); | ||
Schema.modules = require('./modules'); | ||
module.exports = Schema; | ||
|
||
const MODULE_ERROR = 'Module already exists: '; | ||
function Schema(plan, options = {}) { | ||
const { modules = Schema.modules, errorFormat, prototypes } = options; | ||
const [SchemaError, warnings] = [createError({ format: errorFormat }), []]; | ||
[this.tools, this.modules] = [{ Error: SchemaError, build, warn }, new Map()]; | ||
const forge = new Forge(this, prototypes); | ||
this.child = (a = plan, b = options) => new Schema(a, b === options ? b : { ...b, ...options }); | ||
this.register = (name, module) => { | ||
if (this.modules.has(module)) warn({ cause: MODULE_ERROR, plan: this.modules, sample: module }); | ||
module(this, options, plan), this.modules.set(name); | ||
return this; | ||
}; | ||
|
||
[this.forge, this.warnings] = [forge, warnings]; | ||
for (const [name, plugin] of modules.entries()) this.register(name, plugin); | ||
return Object.assign(this, this.tools.build(plan)); | ||
|
||
function build(plan) { | ||
const Type = forge.get(plan.$type); | ||
if (Type) return new Type(plan); | ||
throw new Error('Building error: recieved wrong plan:\n' + JSON.stringify(plan)); | ||
} | ||
|
||
function warn(options) { | ||
const warn = new SchemaError({ path: 'BUILD', ...options }); | ||
return warnings.push(warn), warn; | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict'; | ||
|
||
const { utils } = require('astropack'); | ||
const core = require('./proto'); | ||
|
||
module.exports = function Forge(schema, custom = {}) { | ||
const [chains, wrappers] = [new Map(), { before: [], after: [] }]; | ||
const { before, after } = wrappers; | ||
this.has = name => chains.has(name); | ||
this.attach = (name, ...prototypes) => { | ||
const protos = prototypes.map(unifyProto); | ||
if (name in wrappers) return void wrappers[name].push(...protos); | ||
const chain = chains.get(name) ?? []; | ||
chain.push(...protos), chains.set(name, chain); | ||
return void 0; | ||
}; | ||
|
||
this.get = name => { | ||
const chain = chains.get(name); | ||
if (!chain) return null; | ||
return function ForgePrototype(plan) { | ||
const meta = plan.$meta; | ||
if (plan.$id) this.$id = plan.$id; | ||
[this.$required, this.$type, this.$plan] = [plan.$required ?? true, name, plan]; | ||
if (meta && typeof meta === 'object' && !Array.isArray(meta)) Object.assign(this, meta); | ||
[...before, ...chain, ...after].forEach(proto => proto.call(this, plan, schema.tools)); | ||
if (!this.$kind) this.$kind = 'unknown'; | ||
}; | ||
}; | ||
|
||
for (const [name, proto] of [...entries(core), ...entries(custom)]) this.attach(name, proto); | ||
return Object.freeze(this); | ||
}; | ||
|
||
function unifyProto(Proto) { | ||
const type = utils.isFunction(Proto); | ||
if (type === 'function' || type === 'arrow') return Proto; | ||
return function Prototype(plan, tools) { | ||
if (type === 'class') Object.assign(this, new Proto(plan, tools)); | ||
if (typeof Proto.construct !== 'function') Object.assign(this, Proto); | ||
else Object.assign(this, Proto.construct(plan, tools)); | ||
}; | ||
} | ||
|
||
function entries(protos) { | ||
if (Array.isArray(protos) && protos[0]?.length === 2) return protos; | ||
return protos?.constructor.name === 'Map' ? protos.entries() : Object.entries(protos); | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
'use strict'; | ||
|
||
const create = type => ({ $kind: type }); | ||
module.exports = new Map( | ||
Object.entries({ | ||
unknown: create('unknown'), | ||
boolean: create('scalar'), | ||
string: create('scalar'), | ||
number: create('scalar'), | ||
bigint: create('scalar'), | ||
any: create('any'), | ||
schema: Schema, | ||
union: Union, | ||
array: List, | ||
tuple: List, | ||
set: List, | ||
record: Struct, | ||
object: Struct, | ||
map: Struct, | ||
enum: Enum, | ||
}), | ||
); | ||
|
||
const ENUM_WARN = 'Recieved incorrect enumerable'; | ||
function Enum(plan, { warn }) { | ||
this.$kind = 'enum'; | ||
const filter = el => typeof el === 'string' || typeof el === 'number'; | ||
this.$enum = Array.isArray(plan.enum) ? [...new Set(plan.enum)].filter(filter) : []; | ||
const isFiltered = this.$enum.length !== plan.enum?.length; | ||
isFiltered && warn({ cause: ENUM_WARN, plan, sample: plan.enum }); | ||
} | ||
|
||
const ITEMS_ERROR = 'Plan items are invalid or empty'; | ||
function List(plan, { warn, build }) { | ||
this.$kind = 'struct'; | ||
const isArray = Array.isArray(plan.items); | ||
this.$isTuple = this.$type === 'tuple' || isArray; | ||
this.$items = (isArray ? plan.items : [plan.items]).map(build); | ||
!this.$items.length && warn({ plan, cause: ITEMS_ERROR, sample: plan.items }); | ||
} | ||
|
||
const PLANS_ERROR = 'Revievd plan without properties'; | ||
function Struct(plan, { build, warn }) { | ||
[this.$kind, this.$properties, this.$patterns] = ['struct', new Map(), new Map()]; | ||
this.$isRecord = this.$type === 'record' || plan.isRecord; | ||
this.$requires = []; | ||
!plan.properties && warn({ plan, sample: plan.properties, cause: PLANS_ERROR }); | ||
for (const [key, value] of Object.entries(plan.properties ?? {})) { | ||
const builded = build(value); | ||
builded.$required && this.$requires.push(key); | ||
(value.isPattern ? this.$patterns : this.$properties).set(key, builded); | ||
} | ||
} | ||
|
||
function Union(plan, { build }) { | ||
this.$kind = 'union'; | ||
this.$condition = plan.condition ?? 'anyof'; | ||
this.$types = (Array.isArray(plan.types) ? plan.types : [plan]).map(build); | ||
} | ||
|
||
function Schema(plan) { | ||
Object.assign(this, plan.schema); | ||
if (plan.$id) this.$id = plan.$id; | ||
this.$required = plan.$required; | ||
} |
Oops, something went wrong.