eidosmd 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -29
- package/browser/dist/assets/index-Cc3cNWHY.css +1 -0
- package/browser/dist/assets/index-DQgCQRa5.js +46 -0
- package/browser/dist/favicon.svg +5 -0
- package/browser/dist/index.html +15 -0
- package/browser/dist/mark.svg +4 -0
- package/dist/src/cli.js +7 -0
- package/dist/src/commands/agents.js +1 -1
- package/dist/src/commands/canvas.js +77 -0
- package/dist/src/commands/check.js +10 -4
- package/dist/src/commands/configure.js +201 -0
- package/dist/src/commands/framework.js +37 -7
- package/dist/src/commands/index.js +4 -4
- package/dist/src/commands/init.js +5 -0
- package/dist/src/commands/instructions.js +1 -1
- package/dist/src/commands/list.js +8 -8
- package/dist/src/commands/migrate.js +32 -0
- package/dist/src/commands/new.js +3 -3
- package/dist/src/commands/property.js +125 -0
- package/dist/src/commands/seeds.js +5 -5
- package/dist/src/commands/setup.js +131 -0
- package/dist/src/commands/version.js +44 -0
- package/dist/src/commands/whoami.js +4 -4
- package/dist/src/context.js +5 -5
- package/dist/src/core/blueprint.js +16 -11
- package/dist/src/core/canvas-schema.js +148 -0
- package/dist/src/core/canvas.js +732 -0
- package/dist/src/core/check.js +221 -70
- package/dist/src/core/convert.js +7 -6
- package/dist/src/core/edits.js +1381 -0
- package/dist/src/core/framework-markdown.js +119 -34
- package/dist/src/core/framework-model.js +62 -10
- package/dist/src/core/framework-structured.js +222 -47
- package/dist/src/core/framework.js +13 -13
- package/dist/src/core/frontmatter.js +61 -1
- package/dist/src/core/git.js +84 -0
- package/dist/src/core/index-leaf.js +2 -2
- package/dist/src/core/links.js +87 -0
- package/dist/src/core/markdown.js +16 -9
- package/dist/src/core/me.js +16 -8
- package/dist/src/core/migrate.js +319 -0
- package/dist/src/core/naming.js +1 -1
- package/dist/src/core/regions.js +117 -0
- package/dist/src/core/root.js +2 -2
- package/dist/src/core/scaffold.js +33 -27
- package/dist/src/core/seed.js +187 -71
- package/dist/src/core/server.js +1410 -53
- package/dist/src/core/settings.js +232 -0
- package/dist/src/core/store.js +315 -0
- package/dist/src/core/template.js +32 -0
- package/dist/src/core/versions.js +84 -0
- package/dist/src/output.js +4 -1
- package/dist/src/program.js +421 -41
- package/instructions/authoring.md +15 -12
- package/instructions/configuring.md +81 -34
- package/instructions/init-required.md +4 -4
- package/instructions/overview.md +21 -9
- package/instructions/validating.md +9 -6
- package/package.json +21 -12
- package/standard/EIDOS.md +142 -259
- package/standard/seeds/README.md +12 -16
- package/standard/seeds/book/Framework.yaml +61 -0
- package/standard/seeds/book/README.md +10 -5
- package/standard/seeds/book/_gitignore +9 -3
- package/standard/seeds/book/me.md +1 -1
- package/standard/seeds/book/roles/README.md +3 -3
- package/standard/seeds/book/roles/framework-owner.md +2 -2
- package/standard/seeds/book/{shapes → templates}/chapter.full.md +0 -8
- package/standard/seeds/book/{shapes → templates}/chapter.sketch.md +0 -7
- package/standard/seeds/book/{shapes → templates}/frame.market.md +0 -6
- package/standard/seeds/book/templates/frame.premise.md +17 -0
- package/standard/seeds/book/{shapes → templates}/frame.reader.md +0 -6
- package/standard/seeds/book/{shapes → templates}/frame.voice.md +0 -7
- package/standard/seeds/research/Framework.yaml +61 -0
- package/standard/seeds/research/README.md +10 -5
- package/standard/seeds/research/_gitignore +9 -3
- package/standard/seeds/research/me.md +1 -1
- package/standard/seeds/research/roles/README.md +3 -3
- package/standard/seeds/research/roles/framework-owner.md +2 -2
- package/standard/seeds/research/{shapes → templates}/frame.ethics.md +0 -6
- package/standard/seeds/research/{shapes → templates}/frame.method.md +0 -7
- package/standard/seeds/research/{shapes → templates}/frame.prior-work.md +0 -6
- package/standard/seeds/research/{shapes → templates}/frame.question.md +0 -7
- package/standard/seeds/research/{shapes → templates}/investigation.full.md +0 -8
- package/standard/seeds/research/{shapes → templates}/investigation.note.md +0 -7
- package/standard/seeds/software/Framework.yaml +62 -0
- package/standard/seeds/software/README.md +7 -6
- package/standard/seeds/software/_gitignore +9 -3
- package/standard/seeds/software/me.md +1 -1
- package/standard/seeds/software/roles/README.md +3 -3
- package/standard/seeds/software/roles/framework-owner.md +2 -2
- package/standard/seeds/software/roles/project-manager.md +2 -2
- package/standard/seeds/software/roles/stakeholder.md +1 -1
- package/standard/seeds/software/{shapes → templates}/frame.architecture.md +0 -7
- package/standard/seeds/software/{shapes → templates}/frame.audience.md +1 -8
- package/standard/seeds/software/{shapes → templates}/frame.criteria.md +0 -8
- package/standard/seeds/software/{shapes → templates}/frame.market.md +0 -8
- package/standard/seeds/software/{shapes → templates}/spec.full.md +0 -8
- package/standard/seeds/software/{shapes → templates}/spec.micro.md +0 -9
- package/browser/index.html +0 -268
- package/dist/src/commands/convert.js +0 -30
- package/dist/src/core/shape.js +0 -26
- package/standard/seeds/book/Framework.md +0 -87
- package/standard/seeds/book/shapes/frame.premise.md +0 -24
- package/standard/seeds/research/Framework.md +0 -88
- package/standard/seeds/software/Framework.md +0 -88
- /package/standard/seeds/software/{shapes → templates}/.gitkeep +0 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
// The markdown framework document,
|
|
1
|
+
// The markdown framework document, `.eidos/Framework.md`: frontmatter for the
|
|
2
2
|
// version and naming convention, and a body indexing the Top-Level docs, the
|
|
3
|
-
// Collections (each a `###` with Leaf,
|
|
4
|
-
//
|
|
3
|
+
// Collections (each a `###` with Leaf, Variants, and grouping bullets), the
|
|
4
|
+
// Properties table per owner, the Vocabulary, and the Versions. The 4.x
|
|
5
|
+
// spellings (Schema, Flavors, shape) still read, so `migrate` can load a root
|
|
6
|
+
// it is about to move.
|
|
5
7
|
import { parseFrontmatter } from './frontmatter.js';
|
|
6
|
-
import { groupingProperty, STANDARD_CORE } from './framework-model.js';
|
|
8
|
+
import { coreRequires, groupingProperty, STANDARD_CORE, unitOf } from './framework-model.js';
|
|
7
9
|
import { DEFAULT_NAMING, isNaming } from './naming.js';
|
|
8
10
|
import { section, sections, stripInlineCode } from './markdown.js';
|
|
9
11
|
import path from 'node:path';
|
|
10
|
-
const DECLARED_BULLETS = new Set(['leaf', 'flavors', 'canvas']);
|
|
12
|
+
const DECLARED_BULLETS = new Set(['leaf', 'unit', 'variants', 'flavors', 'canvas']);
|
|
11
13
|
function cleanText(text) {
|
|
12
14
|
return text.replace(/^_+|_+$/g, '').trim();
|
|
13
15
|
}
|
|
@@ -46,13 +48,13 @@ function parseCanvas(value) {
|
|
|
46
48
|
}
|
|
47
49
|
return { mode: 'card', section: null };
|
|
48
50
|
}
|
|
49
|
-
function
|
|
50
|
-
const file = path.posix.basename(
|
|
51
|
+
function variantFromTemplate(label, templateRel) {
|
|
52
|
+
const file = path.posix.basename(templateRel.replace(/\\/g, '/')).replace(/\.md$/i, '');
|
|
51
53
|
const dot = file.indexOf('.');
|
|
52
|
-
const
|
|
54
|
+
const unit = dot === -1 ? file : file.slice(0, dot);
|
|
53
55
|
const fromFile = dot === -1 ? file : file.slice(dot + 1);
|
|
54
56
|
const name = /\.md$/i.test(label) ? fromFile : label;
|
|
55
|
-
return { name,
|
|
57
|
+
return { name, unit };
|
|
56
58
|
}
|
|
57
59
|
function parseCollections(body) {
|
|
58
60
|
const block = section(body, 2, 'Collections');
|
|
@@ -62,22 +64,23 @@ function parseCollections(body) {
|
|
|
62
64
|
const out = [];
|
|
63
65
|
for (const { heading, body: text } of sections(block, 3)) {
|
|
64
66
|
const collection = {
|
|
67
|
+
type: 'collection',
|
|
65
68
|
name: heading.text,
|
|
66
69
|
description: firstParagraph(text),
|
|
67
|
-
framing:
|
|
70
|
+
framing: false,
|
|
68
71
|
leaf: null,
|
|
69
|
-
|
|
72
|
+
variants: [],
|
|
70
73
|
canvas: null,
|
|
71
74
|
grouping: null,
|
|
72
75
|
};
|
|
73
|
-
let
|
|
76
|
+
let inVariants = false;
|
|
74
77
|
let inGrouping = false;
|
|
75
78
|
for (const line of text.split('\n')) {
|
|
76
79
|
const bullet = /^-\s+\*\*(.+?):\*\*\s*(.*)$/.exec(line);
|
|
77
80
|
if (bullet && bullet[1] !== undefined) {
|
|
78
81
|
const label = bullet[1].trim();
|
|
79
82
|
const rest = (bullet[2] ?? '').trim();
|
|
80
|
-
|
|
83
|
+
inVariants = label.toLowerCase() === 'variants' || label.toLowerCase() === 'flavors';
|
|
81
84
|
inGrouping = false;
|
|
82
85
|
if (label.toLowerCase() === 'leaf') {
|
|
83
86
|
collection.leaf = parseLink(rest)?.target ?? null;
|
|
@@ -96,18 +99,18 @@ function parseCollections(body) {
|
|
|
96
99
|
continue;
|
|
97
100
|
}
|
|
98
101
|
const item = nested[1].trim();
|
|
99
|
-
if (
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
// `(default)` in the description marks the default
|
|
103
|
-
const described = (
|
|
102
|
+
if (inVariants) {
|
|
103
|
+
const variantLine = /^\[(.+?)\]\((.+?)\)\s*(?:—\s*(.*))?$/.exec(item);
|
|
104
|
+
if (variantLine && variantLine[1] && variantLine[2]) {
|
|
105
|
+
// `(default)` in the description marks the default variant; it is a flag, not prose.
|
|
106
|
+
const described = (variantLine[3] ?? '').trim();
|
|
104
107
|
const isDefault = /\(default\)/i.test(described);
|
|
105
108
|
const description = described.replace(/\s*\(default\)\.?$/i, '').replace(/\s*\(default\)/i, '').trim();
|
|
106
|
-
const { name,
|
|
107
|
-
collection.
|
|
109
|
+
const { name, unit } = variantFromTemplate(variantLine[1].trim(), variantLine[2].trim());
|
|
110
|
+
collection.variants.push({
|
|
108
111
|
name,
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
unit,
|
|
113
|
+
template: variantLine[2].trim(),
|
|
111
114
|
description,
|
|
112
115
|
isDefault,
|
|
113
116
|
});
|
|
@@ -120,12 +123,13 @@ function parseCollections(body) {
|
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
|
-
if (collection.
|
|
124
|
-
const first = collection.
|
|
126
|
+
if (collection.variants.length > 0 && !collection.variants.some((variant) => variant.isDefault)) {
|
|
127
|
+
const first = collection.variants[0];
|
|
125
128
|
if (first) {
|
|
126
129
|
first.isDefault = true;
|
|
127
130
|
}
|
|
128
131
|
}
|
|
132
|
+
collection.framing = unitOf(collection) === 'frame';
|
|
129
133
|
out.push(collection);
|
|
130
134
|
}
|
|
131
135
|
return out;
|
|
@@ -152,23 +156,89 @@ function parseAppliesTo(value) {
|
|
|
152
156
|
}
|
|
153
157
|
return plain.split(/[,/]/).map((name) => name.trim()).filter((name) => name !== '');
|
|
154
158
|
}
|
|
155
|
-
|
|
159
|
+
// The standard's columns come first (Name, Type, Meaning for the core; Name,
|
|
160
|
+
// Type, Applies To, Meaning for custom properties); any column past them is a
|
|
161
|
+
// tool's, headed with the tool's name, and rides along as that tool's field.
|
|
162
|
+
function parseProperties(block, core, owner = core ? 'eidos' : 'custom') {
|
|
156
163
|
if (block === null) {
|
|
157
164
|
return [];
|
|
158
165
|
}
|
|
159
166
|
const out = [];
|
|
167
|
+
const standard = core ? 3 : 4;
|
|
168
|
+
let header = [];
|
|
160
169
|
for (const cells of parseTable(block)) {
|
|
161
170
|
const name = stripInlineCode(cells[0] ?? '').trim();
|
|
162
|
-
if (name === ''
|
|
171
|
+
if (name === '') {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (name.toLowerCase() === 'name') {
|
|
175
|
+
header = cells.map((cell) => stripInlineCode(cell).trim());
|
|
163
176
|
continue;
|
|
164
177
|
}
|
|
165
178
|
const type = (cells[1] ?? 'Text').trim();
|
|
166
|
-
|
|
167
|
-
|
|
179
|
+
// the 4.x table had no Required column: the core requires what the
|
|
180
|
+
// standard says it does, and every other property is optional
|
|
181
|
+
const required = core && coreRequires(name);
|
|
182
|
+
const property = core || cells.length < 4
|
|
183
|
+
? { name, type, appliesTo: 'all', required, meaning: (cells[Math.min(cells.length, standard) - 1] ?? '').trim(), core, owner }
|
|
184
|
+
: { name, type, appliesTo: parseAppliesTo(cells[2] ?? ''), required, meaning: (cells[3] ?? '').trim(), core, owner };
|
|
185
|
+
const tools = {};
|
|
186
|
+
for (let index = standard; index < cells.length; index += 1) {
|
|
187
|
+
const tool = header[index];
|
|
188
|
+
const cell = (cells[index] ?? '').trim();
|
|
189
|
+
if (tool && cell !== '') {
|
|
190
|
+
tools[tool] = cell;
|
|
191
|
+
}
|
|
168
192
|
}
|
|
169
|
-
|
|
170
|
-
|
|
193
|
+
if (Object.keys(tools).length > 0) {
|
|
194
|
+
property.tools = tools;
|
|
171
195
|
}
|
|
196
|
+
out.push(property);
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
// `## Vocabulary`: Term · Means · Not, one row per term. A Term cell may be a
|
|
201
|
+
// link to the blueprint that defines it; the Not cell lists near-misses, `;` apart.
|
|
202
|
+
function parseVocabulary(body) {
|
|
203
|
+
const block = section(body, 2, 'Vocabulary');
|
|
204
|
+
if (block === null)
|
|
205
|
+
return [];
|
|
206
|
+
const out = [];
|
|
207
|
+
for (const row of parseTable(block)) {
|
|
208
|
+
const [termCell = '', means = '', notCell = ''] = row;
|
|
209
|
+
const link = parseLink(termCell.trim());
|
|
210
|
+
const term = (link ? link.title : stripInlineCode(termCell.replace(/\*\*/g, ''))).trim();
|
|
211
|
+
// the header row, a placeholder row, and a blank row are not terms
|
|
212
|
+
if (term === '' || term.toLowerCase() === 'term' || /^<.*>$/.test(term) || /^-+$/.test(term))
|
|
213
|
+
continue;
|
|
214
|
+
out.push({
|
|
215
|
+
term,
|
|
216
|
+
means: cleanText(means),
|
|
217
|
+
not: notCell
|
|
218
|
+
.split(';')
|
|
219
|
+
.map((entry) => cleanText(entry))
|
|
220
|
+
.filter((entry) => entry !== ''),
|
|
221
|
+
see: link ? link.target : null,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
226
|
+
// `## Versions`: Version · Commit · Tag, newest first, as written. The key
|
|
227
|
+
// left the standard in 5.0.0; `migrate` moves what a 4.x root recorded.
|
|
228
|
+
export function parseVersions(body) {
|
|
229
|
+
const block = section(body, 2, 'Versions');
|
|
230
|
+
if (block === null) {
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
const out = [];
|
|
234
|
+
for (const cells of parseTable(block)) {
|
|
235
|
+
const version = stripInlineCode(cells[0] ?? '').replace(/^\*\*|\*\*$/g, '').trim();
|
|
236
|
+
if (version === '' || version.toLowerCase() === 'version') {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const commit = stripInlineCode(cells[1] ?? '').trim();
|
|
240
|
+
const tag = stripInlineCode(cells[2] ?? '').trim();
|
|
241
|
+
out.push({ version, commit, tag: tag === '' || tag === '—' || tag === '-' ? null : tag });
|
|
172
242
|
}
|
|
173
243
|
return out;
|
|
174
244
|
}
|
|
@@ -207,11 +277,23 @@ export function parseFrameworkMarkdown(text, root, file) {
|
|
|
207
277
|
}
|
|
208
278
|
}
|
|
209
279
|
const version = properties?.['eidos_version'];
|
|
210
|
-
const schemaBlock = section(body, 2, 'Schema') ?? '';
|
|
211
|
-
const coreBlock = section(schemaBlock, 3, 'Eidos Core');
|
|
212
|
-
const customBlock = section(schemaBlock, 3, 'Custom Properties');
|
|
280
|
+
const schemaBlock = section(body, 2, 'Properties') ?? section(body, 2, 'Schema') ?? '';
|
|
281
|
+
const coreBlock = section(schemaBlock, 3, 'Eidos') ?? section(schemaBlock, 3, 'Eidos Core');
|
|
282
|
+
const customBlock = section(schemaBlock, 3, 'Custom') ?? section(schemaBlock, 3, 'Custom Properties');
|
|
213
283
|
const core = parseProperties(coreBlock, true);
|
|
214
284
|
const custom = parseProperties(customBlock, false);
|
|
285
|
+
// `### <tool>` (`### <tool> Properties` before 5.0.0): a block a tool declared and alone writes.
|
|
286
|
+
const tools = {};
|
|
287
|
+
for (const { heading, body: block } of sections(schemaBlock, 3)) {
|
|
288
|
+
const name = heading.text.trim();
|
|
289
|
+
if (/^(eidos( core)?|custom( properties)?)$/i.test(name))
|
|
290
|
+
continue;
|
|
291
|
+
const match = /^(.+?)(?:\s+Properties)?$/i.exec(name);
|
|
292
|
+
const tool = match?.[1]?.trim() ?? '';
|
|
293
|
+
if (!match || tool === '' || tool.toLowerCase() === 'custom' || /^<.*>$/.test(tool))
|
|
294
|
+
continue;
|
|
295
|
+
tools[tool] = parseProperties(block, false, tool);
|
|
296
|
+
}
|
|
215
297
|
const collections = parseCollections(body);
|
|
216
298
|
for (const collection of collections) {
|
|
217
299
|
if (collection.grouping) {
|
|
@@ -226,8 +308,11 @@ export function parseFrameworkMarkdown(text, root, file) {
|
|
|
226
308
|
naming,
|
|
227
309
|
namingError,
|
|
228
310
|
topLevel: parseTopLevel(body),
|
|
311
|
+
// the markdown form predates folder types: every folder it declares is a collection
|
|
312
|
+
folders: collections,
|
|
229
313
|
collections,
|
|
230
|
-
schema: { core: core.length > 0 ? core : STANDARD_CORE, custom },
|
|
314
|
+
schema: { core: core.length > 0 ? core : STANDARD_CORE, custom, tools },
|
|
315
|
+
vocabulary: parseVocabulary(body),
|
|
231
316
|
problems: [],
|
|
232
317
|
};
|
|
233
318
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// The framework model: everything a framework document declares, whichever
|
|
2
|
-
// of
|
|
3
|
-
// convention, the Top-Level docs, the
|
|
4
|
-
//
|
|
2
|
+
// of `.eidos/Framework.md` or `.yaml` it is. The version and naming
|
|
3
|
+
// convention, the Top-Level docs, the Folders (every folder at the root with
|
|
4
|
+
// its type; a collection carries its variants and grouping), the Properties
|
|
5
|
+
// table (`schema` here, `properties` on disk), and the Vocabulary.
|
|
5
6
|
import { kebab } from './naming.js';
|
|
6
|
-
export const FRAMEWORK_DIR = '
|
|
7
|
+
export const FRAMEWORK_DIR = '.eidos';
|
|
8
|
+
// This tool's name, as the standard has a tool sign what it keeps in a
|
|
9
|
+
// framework: its folder under `.eidos/plugins/<name>/`, and its fields on a
|
|
10
|
+
// Properties row (a key on the YAML entry, a column in the markdown table).
|
|
11
|
+
export const TOOL_KEY = 'eidosmd';
|
|
12
|
+
export const PLUGINS_DIR = 'plugins';
|
|
7
13
|
export function isFrameworkFormat(value) {
|
|
8
14
|
return value === 'md' || value === 'yaml';
|
|
9
15
|
}
|
|
@@ -13,20 +19,66 @@ export const FRAMEWORK_FILES = [
|
|
|
13
19
|
{ name: 'Framework.yml', format: 'yaml' },
|
|
14
20
|
];
|
|
15
21
|
export const PROPERTY_TYPES = ['Text', 'List', 'Number', 'Checkbox', 'Date', 'Date & time'];
|
|
22
|
+
export function readValueStyle(value) {
|
|
23
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
24
|
+
return null;
|
|
25
|
+
const given = value;
|
|
26
|
+
const text = (field) => (typeof field === 'string' || typeof field === 'number' ? String(field).trim() : '');
|
|
27
|
+
const style = {};
|
|
28
|
+
if (text(given['shape']) !== '')
|
|
29
|
+
style.shape = text(given['shape']);
|
|
30
|
+
if (text(given['color']) !== '')
|
|
31
|
+
style.color = text(given['color']);
|
|
32
|
+
if (given['fill'] === 'solid' || given['fill'] === 'tint' || given['fill'] === 'none')
|
|
33
|
+
style.fill = given['fill'];
|
|
34
|
+
if (text(given['fill_color']) !== '')
|
|
35
|
+
style.fill_color = text(given['fill_color']);
|
|
36
|
+
if (given['size'] === 'small' || given['size'] === 'medium' || given['size'] === 'large')
|
|
37
|
+
style.size = given['size'];
|
|
38
|
+
return Object.keys(style).length > 0 ? style : null;
|
|
39
|
+
}
|
|
40
|
+
// Every folder at the root is declared with one of the standard's three
|
|
41
|
+
// types (Eidos 5.3.0): a collection holds blueprints; an assets folder holds
|
|
42
|
+
// files that are not markdown; an other folder is whatever its description
|
|
43
|
+
// says. The standard reads nothing inside the last two.
|
|
44
|
+
export const FOLDER_TYPES = ['collection', 'assets', 'other'];
|
|
45
|
+
export function isFolderType(value) {
|
|
46
|
+
return typeof value === 'string' && FOLDER_TYPES.includes(value);
|
|
47
|
+
}
|
|
48
|
+
export function isCollection(folder) {
|
|
49
|
+
return folder.type === 'collection';
|
|
50
|
+
}
|
|
51
|
+
// The unit a collection speaks in, the word for one of its blueprints: what
|
|
52
|
+
// its template files are named for (`<unit>.<variant>.md`), read off the
|
|
53
|
+
// default variant. A collection whose unit is `frame` is the framing one, this
|
|
54
|
+
// CLI's recommendation for every product; the standard names no collection.
|
|
55
|
+
export function unitOf(collection) {
|
|
56
|
+
const variant = collection.variants.find((entry) => entry.isDefault) ?? collection.variants[0];
|
|
57
|
+
return variant && variant.unit !== '' ? variant.unit : null;
|
|
58
|
+
}
|
|
16
59
|
export class FrameworkError extends Error {
|
|
17
60
|
constructor(message) {
|
|
18
61
|
super(message);
|
|
19
62
|
this.name = 'FrameworkError';
|
|
20
63
|
}
|
|
21
64
|
}
|
|
22
|
-
// The standard's own
|
|
65
|
+
// The standard's own four (Eidos 5.3.0), two of them required, used when a
|
|
66
|
+
// framework document carries no core block.
|
|
23
67
|
export const STANDARD_CORE = [
|
|
24
|
-
{ name: 'id', type: 'Text', appliesTo: 'all', meaning: 'Stable, unique,
|
|
25
|
-
{ name: 'title', type: 'Text', appliesTo: 'all', meaning: 'Human-readable name.', core: true },
|
|
26
|
-
{ name: 'summary', type: 'Text', appliesTo: 'all', meaning: 'One
|
|
27
|
-
{ name: '
|
|
28
|
-
{ name: 'connects_to', type: 'List', appliesTo: 'all', meaning: 'Blueprints this one connects to on the canvas, each a link.', core: true },
|
|
68
|
+
{ name: 'id', type: 'Text', appliesTo: 'all', required: true, meaning: 'Stable, unique identity, in any form. Assigned once, never changed.', core: true, owner: 'eidos' },
|
|
69
|
+
{ name: 'title', type: 'Text', appliesTo: 'all', required: true, meaning: 'Human-readable name.', core: true, owner: 'eidos' },
|
|
70
|
+
{ name: 'summary', type: 'Text', appliesTo: 'all', required: false, meaning: 'One line: what this blueprint is. Feeds the index; absent, the index flags it.', core: true, owner: 'eidos' },
|
|
71
|
+
{ name: 'variant', type: 'Text', appliesTo: 'all', required: false, meaning: "Which variant this blueprint follows. Absent = the collection's default.", core: true, owner: 'eidos' },
|
|
29
72
|
];
|
|
73
|
+
// Whether the standard's core requires a property of this name: what an
|
|
74
|
+
// absent `required` on a core row means, since the block is the standard's.
|
|
75
|
+
export function coreRequires(name) {
|
|
76
|
+
return STANDARD_CORE.some((property) => property.name === name && property.required);
|
|
77
|
+
}
|
|
78
|
+
// Every property of the Properties table, whichever block owns it, core first.
|
|
79
|
+
export function allProperties(schema) {
|
|
80
|
+
return [...schema.core, ...schema.custom, ...Object.values(schema.tools).flat()];
|
|
81
|
+
}
|
|
30
82
|
// `Domains` -> `domain`: the custom property that carries a collection's group,
|
|
31
83
|
// matched by the grouping label's singular against the properties scoped to it.
|
|
32
84
|
export function groupingProperty(collection, custom) {
|