Parametric declarations
This commit is contained in:
parent
29503614cc
commit
e515f51c0e
10 changed files with 128 additions and 36 deletions
|
@ -11,7 +11,8 @@
|
|||
"bin": "./src/cli.js",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"test": "nyc --reporter=html --reporter=text mocha -r chai/register-should test/unit/*.js test/complex/index.js"
|
||||
"test": "mocha -r chai/register-should test/index.js",
|
||||
"coverage": "nyc --reporter=html --reporter=text mocha -r chai/register-should test/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "^9.0.1",
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
const u = require('./utils')
|
||||
const a = require('./assert')
|
||||
|
||||
const unnest = exports.unnest = config => {
|
||||
if (a.type(config)() !== 'object') return config
|
||||
const result = {}
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
u.deep(result, key, unnest(val))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const _extend = exports._extend = (to, from) => {
|
||||
const to_type = a.type(to)()
|
||||
const from_type = a.type(from)()
|
||||
|
@ -41,32 +32,79 @@ const extend = exports.extend = (...args) => {
|
|||
return res
|
||||
}
|
||||
|
||||
const _inherit = exports._inherit = (config, root, breadcrumbs) => {
|
||||
const traverse = exports.traverse = (config, root, breadcrumbs, op) => {
|
||||
if (a.type(config)() !== 'object') return config
|
||||
const result = {}
|
||||
for (const [key, val] of Object.entries(config)) {
|
||||
breadcrumbs.push(key)
|
||||
let newval = _inherit(val, root, breadcrumbs)
|
||||
if (newval && newval.$extends !== undefined) {
|
||||
let candidates = u.deepcopy(newval.$extends)
|
||||
if (a.type(candidates)() !== 'array') candidates = [candidates]
|
||||
const list = [newval]
|
||||
while (candidates.length) {
|
||||
const path = candidates.shift()
|
||||
const other = u.deepcopy(u.deep(root, path))
|
||||
a.assert(other, `"${path}" (reached from "${breadcrumbs.join('.')}.$extends") does not name a valid inheritance target!`)
|
||||
let parents = other.$extends || []
|
||||
if (a.type(parents)() !== 'array') parents = [parents]
|
||||
candidates = candidates.concat(parents)
|
||||
list.unshift(other)
|
||||
}
|
||||
newval = extend.apply(this, list)
|
||||
delete newval.$extends
|
||||
}
|
||||
result[key] = newval
|
||||
op(result, key, traverse(val, root, breadcrumbs, op), root, breadcrumbs)
|
||||
breadcrumbs.pop()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const inherit = exports.inherit = config => _inherit(config, config, [])
|
||||
exports.unnest = config => traverse(config, config, [], (target, key, val) => {
|
||||
u.deep(target, key, val)
|
||||
})
|
||||
|
||||
exports.inherit = config => traverse(config, config, [], (target, key, val, root, breadcrumbs) => {
|
||||
if (val && val.$extends !== undefined) {
|
||||
let candidates = u.deepcopy(val.$extends)
|
||||
if (a.type(candidates)() !== 'array') candidates = [candidates]
|
||||
const list = [val]
|
||||
while (candidates.length) {
|
||||
const path = candidates.shift()
|
||||
const other = u.deepcopy(u.deep(root, path))
|
||||
a.assert(other, `"${path}" (reached from "${breadcrumbs.join('.')}.$extends") does not name a valid inheritance target!`)
|
||||
let parents = other.$extends || []
|
||||
if (a.type(parents)() !== 'array') parents = [parents]
|
||||
candidates = candidates.concat(parents)
|
||||
list.unshift(other)
|
||||
}
|
||||
val = extend.apply(this, list)
|
||||
delete val.$extends
|
||||
}
|
||||
target[key] = val
|
||||
})
|
||||
|
||||
exports.parameterize = config => traverse(config, config, [], (target, key, val, root, breadcrumbs) => {
|
||||
let params = val.$params
|
||||
let args = val.$args
|
||||
|
||||
// explicitly skipped (probably intermediate) template, remove (by not setting it)
|
||||
if (val.$skip) return
|
||||
|
||||
// nothing to do here, just pass the original value through
|
||||
if (!params && !args) {
|
||||
target[key] = val
|
||||
return
|
||||
}
|
||||
|
||||
// unused template, remove (by not setting it)
|
||||
if (params && !args) return
|
||||
|
||||
if (!params && args) {
|
||||
throw new Error(`Trying to parameterize through "${breadcrumbs}.$args", but the corresponding "$params" field is missing!`)
|
||||
}
|
||||
|
||||
params = a.strarr(params, `${breadcrumbs}.$params`)
|
||||
args = a.sane(args, `${breadcrumbs}.$args`, 'array')()
|
||||
if (params.length !== args.length) {
|
||||
throw new Error(`The number of "$params" and "$args" don't match for "${breadcrumbs}"!`)
|
||||
}
|
||||
|
||||
let str = JSON.stringify(val)
|
||||
const zip = rows => rows[0].map((_, i) => rows.map(row => row[i]))
|
||||
for (const [par, arg] of zip([params, args])) {
|
||||
str = str.replace(new RegExp(`"${par}"`, 'g'), JSON.stringify(arg))
|
||||
}
|
||||
try {
|
||||
val = JSON.parse(str)
|
||||
} catch (ex) {
|
||||
throw new Error(`Replacements didn't lead to a valid JSON object at "${breadcrumbs}"! ` + ex)
|
||||
}
|
||||
|
||||
delete val.$params
|
||||
delete val.$args
|
||||
target[key] = val
|
||||
})
|
|
@ -2,12 +2,21 @@ const fs = require('fs-extra')
|
|||
const path = require('path')
|
||||
const yaml = require('js-yaml')
|
||||
const glob = require('glob')
|
||||
const u = require('../../src/utils')
|
||||
const ergogen = require('../../src/ergogen')
|
||||
const u = require('../src/utils')
|
||||
const ergogen = require('../src/ergogen')
|
||||
|
||||
let what = process.env.npm_config_what
|
||||
what = what ? what.split(',') : false
|
||||
for (const unit of glob.sync(path.join(__dirname, 'unit', '*.js'))) {
|
||||
const base = path.basename(unit, '.js')
|
||||
if (what && !what.includes(base)) continue
|
||||
require(`./unit/${base}.js`)
|
||||
}
|
||||
|
||||
const cap = s => s.charAt(0).toUpperCase() + s.slice(1)
|
||||
|
||||
for (const part of ['points', 'outlines', 'cases', 'pcbs']) {
|
||||
if (what && !what.includes(part)) continue
|
||||
describe(cap(part), function() {
|
||||
const dir = path.join(__dirname, part)
|
||||
for (const input_path of glob.sync(path.join(dir, '*.yaml'))) {
|
|
@ -11,12 +11,12 @@ describe('Prepare', function() {
|
|||
|
||||
it('extend', function() {
|
||||
p.extend('something', undefined).should.equal('something')
|
||||
should.equal(p.extend('something', '!!unset'), undefined)
|
||||
should.equal(p.extend('something', '$unset'), undefined)
|
||||
p.extend(undefined, 'something').should.equal('something')
|
||||
p.extend(28, 'something').should.equal('something')
|
||||
p.extend('something', 28).should.equal(28)
|
||||
p.extend(27, 28).should.equal(28)
|
||||
p.extend({a: 1, c: 1, d: 1}, {b: 2, c: 2, d: '!!unset'}).should.deep.equal({a: 1, b: 2, c: 2})
|
||||
p.extend({a: 1, c: 1, d: 1}, {b: 2, c: 2, d: '$unset'}).should.deep.equal({a: 1, b: 2, c: 2})
|
||||
p.extend([3, 2, 1], [null, 4, 5]).should.deep.equal([3, 4, 5])
|
||||
})
|
||||
|
||||
|
@ -27,11 +27,11 @@ describe('Prepare', function() {
|
|||
y: 2
|
||||
},
|
||||
b: {
|
||||
extends: 'a',
|
||||
$extends: 'a',
|
||||
z: 3
|
||||
},
|
||||
c: {
|
||||
extends: 'b',
|
||||
$extends: ['b'],
|
||||
w: 4
|
||||
}
|
||||
}).c.should.deep.equal({
|
||||
|
@ -41,4 +41,48 @@ describe('Prepare', function() {
|
|||
w: 4
|
||||
})
|
||||
})
|
||||
|
||||
it('parameterize', function() {
|
||||
p.parameterize(1).should.equal(1)
|
||||
|
||||
p.parameterize({
|
||||
unused: {
|
||||
$params: ['PAR']
|
||||
},
|
||||
skip: {
|
||||
$skip: true
|
||||
}
|
||||
}).should.deep.equal({})
|
||||
|
||||
p.parameterize({
|
||||
decl: {
|
||||
a: 'PAR',
|
||||
$params: ['PAR'],
|
||||
$args: [1]
|
||||
}
|
||||
}).decl.should.deep.equal({
|
||||
a: 1
|
||||
})
|
||||
|
||||
p.parameterize.bind(this, {
|
||||
decl: {
|
||||
$args: [1]
|
||||
}
|
||||
}).should.throw('missing')
|
||||
|
||||
p.parameterize.bind(this, {
|
||||
decl: {
|
||||
$params: ['PAR1', 'PAR2'],
|
||||
$args: [1]
|
||||
}
|
||||
}).should.throw('match')
|
||||
|
||||
p.parameterize.bind(this, {
|
||||
decl: {
|
||||
a: 'PAR',
|
||||
$params: ['PAR'],
|
||||
$args: [undefined]
|
||||
}
|
||||
}).should.throw('valid')
|
||||
})
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue