V4: Initial implementation of refactored character variant system
This commit is contained in:
parent
58c472342b
commit
c1c3ce79ee
88 changed files with 2870 additions and 2381 deletions
|
@ -1,73 +1,145 @@
|
|||
"use strict";
|
||||
|
||||
const objectAssign = require("object-assign");
|
||||
exports.apply = applyVariantData;
|
||||
function applyVariantData(data, para, argv) {
|
||||
const parsed = parseVariantsData(data);
|
||||
let tagSet = new Set();
|
||||
for (const prime of parsed.primes.values()) {
|
||||
if (!prime.tag) continue;
|
||||
if (!tagSet.has(prime.tag)) tagSet.add(prime.tag);
|
||||
else throw new Error(`CV tag conflict: ${prime.tag}`);
|
||||
}
|
||||
|
||||
function mergeVSHive(_target, source) {
|
||||
if (!source) return _target;
|
||||
let __cvmap = objectAssign({}, _target.__cvmap, source.__cvmap);
|
||||
let target = objectAssign(_target, source);
|
||||
target.__cvmap = __cvmap;
|
||||
return target;
|
||||
const variantSelector = {};
|
||||
parsed.defaultComposite.resolve(para, parsed.selectorTree, parsed.composites, variantSelector);
|
||||
if (argv.serif === "slab") {
|
||||
const slabComp = parsed.composites.get("slab");
|
||||
slabComp.resolve(para, parsed.selectorTree, parsed.composites, variantSelector);
|
||||
}
|
||||
if (argv.variants) {
|
||||
const userComposite = new Composite("{user}", argv.variants);
|
||||
userComposite.resolve(para, parsed.selectorTree, parsed.composites, variantSelector);
|
||||
}
|
||||
|
||||
para.variants = {
|
||||
selectorTree: parsed.selectorTree,
|
||||
primes: parsed.primes,
|
||||
composites: parsed.composites
|
||||
};
|
||||
para.variantSelector = variantSelector;
|
||||
}
|
||||
|
||||
function produceComposite(vs, para, g) {
|
||||
let sel = {};
|
||||
if (g.design)
|
||||
for (let h of g.design) {
|
||||
sel = mergeVSHive(sel, vs[h]);
|
||||
}
|
||||
if (!para.isItalic && g.upright) {
|
||||
for (let h of g.upright) {
|
||||
sel = mergeVSHive(sel, vs[h]);
|
||||
}
|
||||
exports.parse = parseVariantsData;
|
||||
function parseVariantsData(data) {
|
||||
const primes = new Map();
|
||||
const selectorTree = new SelectorTree();
|
||||
for (const k in data.prime) {
|
||||
const p = new Prime(k, data.prime[k]);
|
||||
p.register(selectorTree);
|
||||
primes.set(k, p);
|
||||
}
|
||||
if (para.isItalic && g.italic) {
|
||||
for (let h of g.italic) {
|
||||
sel = mergeVSHive(sel, vs[h]);
|
||||
}
|
||||
|
||||
const defaultComposite = new Composite("{default}", data.default);
|
||||
const composites = new Map();
|
||||
for (const k in data.composite) {
|
||||
const comp = new Composite(k, data.composite[k]);
|
||||
composites.set(k, comp);
|
||||
}
|
||||
sel.__isComposite = true;
|
||||
return sel;
|
||||
|
||||
return { selectorTree: selectorTree, primes, composites, defaultComposite };
|
||||
}
|
||||
|
||||
module.exports = function formVariantData(data, para) {
|
||||
const vs = {};
|
||||
// simple selector
|
||||
for (let k in data.simple) {
|
||||
const varDef = data.simple[k];
|
||||
const hive = {
|
||||
...varDef.variant,
|
||||
...(para.isItalic ? varDef.variantItalic : varDef.variantUpright)
|
||||
};
|
||||
vs[k] = hive;
|
||||
class SelectorTree {
|
||||
constructor() {
|
||||
this.m_mapping = new Map();
|
||||
}
|
||||
get(kPrime, kVariant) {
|
||||
if (!this.m_mapping.has(kPrime)) return undefined;
|
||||
return this.m_mapping.get(kPrime).get(kVariant);
|
||||
}
|
||||
set(kPrime, kVariant, prime, variant) {
|
||||
if (!this.m_mapping.has(kPrime)) this.m_mapping.set(kPrime, new Map());
|
||||
this.m_mapping.get(kPrime).set(kVariant, [prime, variant]);
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
for (const m of this.m_mapping.values()) yield* m.values();
|
||||
}
|
||||
}
|
||||
|
||||
const tag = varDef.tag;
|
||||
const tagUpright = varDef.tagUpright;
|
||||
const tagItalic = varDef.tagItalic;
|
||||
if (tag) {
|
||||
let __cvmap = {};
|
||||
for (let k in hive) __cvmap[k] = tag;
|
||||
hive.__cvmap = __cvmap;
|
||||
vs[tag] = hive;
|
||||
class Composite {
|
||||
constructor(key, cfg) {
|
||||
this.key = key;
|
||||
this.tag = cfg.tag;
|
||||
this.description = cfg.description;
|
||||
this.inherits = cfg.inherits;
|
||||
this.design = cfg.design;
|
||||
this.upright = cfg.upright;
|
||||
this.italic = cfg.italic;
|
||||
}
|
||||
decompose(para, selTree) {
|
||||
const ans = [];
|
||||
const cfg = Object.assign({}, this.design, para.isItalic ? this.italic : this.upright);
|
||||
for (const [k, v] of Object.entries(cfg)) {
|
||||
const pv = selTree.get(k, v);
|
||||
if (!pv) throw new Error(`Composite ${this.key} cannot be resolved: ${[k, v]}.`);
|
||||
ans.push(pv);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
resolve(para, selTree, catalog, vs) {
|
||||
if (this.inherits) {
|
||||
for (const item of this.inherits) {
|
||||
if (!catalog.has(item)) throw new Error(`Cannot find composite variant: ${item}`);
|
||||
catalog.get(item).resolve(para, selTree, catalog, vs);
|
||||
}
|
||||
}
|
||||
for (const [prime, variant] of this.decompose(para, selTree)) {
|
||||
variant.resolve(para, vs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Prime {
|
||||
constructor(key, cfg) {
|
||||
this.key = key;
|
||||
this.sampler = cfg.sampler;
|
||||
this.tag = cfg.tag;
|
||||
if (!cfg.variants) throw new Error(`Missing variants in ${key}`);
|
||||
this.variants = new Map();
|
||||
for (const varKey in cfg.variants) {
|
||||
const variant = cfg.variants[varKey];
|
||||
this.variants.set(varKey, new PrimeVariant(varKey, cfg.tag, variant));
|
||||
}
|
||||
}
|
||||
register(tree) {
|
||||
for (const [k, v] of this.variants) tree.set(this.key, k, this, v);
|
||||
if (this.tag) {
|
||||
for (const v of this.variants.values()) if (v.rank) tree.set(this.tag, v.rank, this, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PrimeVariant {
|
||||
constructor(key, tag, cfg) {
|
||||
this.key = key;
|
||||
this.tag = tag;
|
||||
this.description = cfg.description;
|
||||
this.rank = cfg.rank;
|
||||
this.selector = cfg.selector;
|
||||
this.selectorUpright = cfg.selectorUpright;
|
||||
this.selectorItalic = cfg.selectorItalic;
|
||||
}
|
||||
resolveFor(para, gn) {
|
||||
let vs = {};
|
||||
this.resolve(para, vs);
|
||||
return vs[gn];
|
||||
}
|
||||
resolve(para, vs) {
|
||||
Object.assign(vs, this.selector);
|
||||
if (para.isItalic) {
|
||||
Object.assign(vs, this.selectorItalic);
|
||||
} else {
|
||||
if (tagItalic && para.isItalic) {
|
||||
let __cvmap = {};
|
||||
for (let k in hive) __cvmap[k] = tagItalic;
|
||||
hive.__cvmap = __cvmap;
|
||||
vs[tagItalic] = hive;
|
||||
}
|
||||
if (tagUpright && !para.isItalic) {
|
||||
let __cvmap = {};
|
||||
for (let k in hive) __cvmap[k] = tagUpright;
|
||||
hive.__cvmap = __cvmap;
|
||||
vs[tagUpright] = hive;
|
||||
}
|
||||
Object.assign(vs, this.selectorUpright);
|
||||
}
|
||||
}
|
||||
// default selector
|
||||
vs.default = produceComposite(vs, para, data.default);
|
||||
// ss## selector
|
||||
for (let k in data.composite) vs[k] = produceComposite(vs, para, data.composite[k]);
|
||||
|
||||
return vs;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue