From 98c2012c0c6233fe3f70ba215c19f6d39d7e1e34 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sat, 20 Jan 2024 17:23:37 -0400 Subject: data: tidy things folder & imports, nicer fields yaml spec --- src/data/thing.js | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/data/thing.js (limited to 'src/data/thing.js') diff --git a/src/data/thing.js b/src/data/thing.js new file mode 100644 index 00000000..ae8e71af --- /dev/null +++ b/src/data/thing.js @@ -0,0 +1,75 @@ +// Thing: base class for wiki data types, providing interfaces generally useful +// to all wiki data objects on top of foundational CacheableObject behavior. + +import {inspect} from 'node:util'; + +import CacheableObject from '#cacheable-object'; +import {colors} from '#cli'; + +export default class Thing extends CacheableObject { + static referenceType = Symbol.for('Thing.referenceType'); + static friendlyName = Symbol.for('Thing.friendlyName'); + + static getPropertyDescriptors = Symbol.for('Thing.getPropertyDescriptors'); + static getSerializeDescriptors = Symbol.for('Thing.getSerializeDescriptors'); + + static yamlDocumentSpec = Symbol.for('Thing.yamlDocumentSpec'); + + // Default custom inspect function, which may be overridden by Thing + // subclasses. This will be used when displaying aggregate errors and other + // command-line logging - it's the place to provide information useful in + // identifying the Thing being presented. + [inspect.custom]() { + const cname = this.constructor.name; + + return ( + (this.name ? `${cname} ${colors.green(`"${this.name}"`)}` : `${cname}`) + + (this.directory ? ` (${colors.blue(Thing.getReference(this))})` : '') + ); + } + + static getReference(thing) { + if (!thing.constructor[Thing.referenceType]) { + throw TypeError(`Passed Thing is ${thing.constructor.name}, which provides no [Thing.referenceType]`); + } + + if (!thing.directory) { + throw TypeError(`Passed ${thing.constructor.name} is missing its directory`); + } + + return `${thing.constructor[Thing.referenceType]}:${thing.directory}`; + } + + static extendDocumentSpec(thingClass, subspec) { + const superspec = thingClass[Thing.yamlDocumentSpec]; + + const { + fields, + ignoredFields, + invalidFieldCombinations, + ...restOfSubspec + } = subspec; + + const newFields = Object.keys(fields ?? {}); + + return { + ...superspec, + ...restOfSubspec, + + fields: { + ...superspec.fields ?? {}, + ...fields, + }, + + ignoredFields: + (superspec.ignoredFields ?? []) + .filter(field => newFields.includes(field)) + .concat(ignoredFields ?? []), + + invalidFieldCombinations: [ + ...superspec.invalidFieldCombinations ?? [], + ...invalidFieldCombinations ?? [], + ], + }; + } +} -- cgit 1.3.0-6-gf8a5