brand-intent 0.2.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/package.json +14 -1
- package/parser/README.md +36 -0
- package/parser/brandParser.ts +551 -0
- package/parser/compositionParser.ts +556 -0
- package/parser/formatParser.ts +283 -0
- package/parser/identityParser.ts +438 -0
- package/parser/index.ts +20 -0
- package/parser/purposeParser.ts +596 -0
- package/parser/types.ts +17 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for .identity brand identity files.
|
|
3
|
+
*
|
|
4
|
+
* Line-based format with indentation-based blocks.
|
|
5
|
+
* Contains brand strategy: essence, promise, voice, pillars, audiences, values.
|
|
6
|
+
* No visual properties of any kind.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ── Parsed types ──────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
export interface ParsedIdentity {
|
|
12
|
+
// ── Required ──
|
|
13
|
+
/** One-sentence brand essence (2-5 words ideal) */
|
|
14
|
+
essence: string;
|
|
15
|
+
/** Brand promise — the commitment to the audience */
|
|
16
|
+
promise: string;
|
|
17
|
+
/** Voice and tone definition */
|
|
18
|
+
voice: ParsedVoice;
|
|
19
|
+
/** Content pillar definitions */
|
|
20
|
+
pillars: ParsedPillars;
|
|
21
|
+
/** Audience segments keyed by ID */
|
|
22
|
+
audiences: Record<string, ParsedAudience>;
|
|
23
|
+
|
|
24
|
+
// ── Optional ──
|
|
25
|
+
/** Public-facing brand claim / tagline */
|
|
26
|
+
tagline?: string;
|
|
27
|
+
/** Competitive positioning — what makes this brand the only one of its kind */
|
|
28
|
+
positioning?: string;
|
|
29
|
+
/** Organizational mission — what the brand does, for whom */
|
|
30
|
+
mission?: string;
|
|
31
|
+
/** Aspirational future state */
|
|
32
|
+
vision?: string;
|
|
33
|
+
/** Brand archetype shorthand (e.g. "craftsman", "sage") */
|
|
34
|
+
archetype?: string;
|
|
35
|
+
/** Named brand narratives (one should be marked primary) */
|
|
36
|
+
narratives?: ParsedNarrative[];
|
|
37
|
+
/** Core brand values with behavior statements */
|
|
38
|
+
values?: ParsedValue[];
|
|
39
|
+
/** Explicitly not-our-audience segments keyed by ID */
|
|
40
|
+
antiAudiences?: Record<string, ParsedAntiAudience>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ParsedVoice {
|
|
44
|
+
/** Formality level (e.g. "informal, Du") */
|
|
45
|
+
register: string;
|
|
46
|
+
/** Voice character description */
|
|
47
|
+
persona: string;
|
|
48
|
+
/** Sentence structure guidance */
|
|
49
|
+
rhythm?: string;
|
|
50
|
+
/** Concrete rules the brand always follows */
|
|
51
|
+
always: string[];
|
|
52
|
+
/** Concrete rules the brand never breaks */
|
|
53
|
+
never: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ParsedPillars {
|
|
57
|
+
/** Primary content topics */
|
|
58
|
+
primary: string[];
|
|
59
|
+
/** Secondary content topics */
|
|
60
|
+
secondary?: string[];
|
|
61
|
+
/** Topics the brand does not inhabit */
|
|
62
|
+
avoid: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ParsedAudience {
|
|
66
|
+
/** Human-readable audience name */
|
|
67
|
+
label: string;
|
|
68
|
+
/** Demographic and behavioral description */
|
|
69
|
+
profile?: string;
|
|
70
|
+
/** What this audience wants from the brand */
|
|
71
|
+
motivation: string;
|
|
72
|
+
/** Tone and register guidance for this audience */
|
|
73
|
+
language: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ParsedAntiAudience {
|
|
77
|
+
/** Human-readable name */
|
|
78
|
+
label: string;
|
|
79
|
+
/** Who they are and why the brand is not for them */
|
|
80
|
+
description: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ParsedNarrative {
|
|
84
|
+
/** Narrative title (e.g. "Origin Story", "Im besonderen Licht") */
|
|
85
|
+
name: string;
|
|
86
|
+
/** Whether this is the brand's dominant narrative */
|
|
87
|
+
primary: boolean;
|
|
88
|
+
/** Free-form narrative text */
|
|
89
|
+
text: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ParsedValue {
|
|
93
|
+
/** Value name (e.g. "Handwerk", "Ehrlichkeit") */
|
|
94
|
+
name: string;
|
|
95
|
+
/** Behavior statement — what this value means in practice */
|
|
96
|
+
behavior: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Parser ────────────────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
type Block = 'top' | 'voice' | 'pillars' | 'audience' | 'anti-audience' | 'values' | 'narrative';
|
|
102
|
+
type NarrativeState = { name: string; primary: boolean; text: string };
|
|
103
|
+
type ListTarget = 'always' | 'never' | 'primary' | 'secondary' | 'avoid';
|
|
104
|
+
|
|
105
|
+
export function parseIdentityFile(content: string, fileName: string): ParsedIdentity {
|
|
106
|
+
const lines = content.split('\n');
|
|
107
|
+
|
|
108
|
+
let essence = '';
|
|
109
|
+
let promise = '';
|
|
110
|
+
let tagline = '';
|
|
111
|
+
let positioning = '';
|
|
112
|
+
let mission = '';
|
|
113
|
+
let vision = '';
|
|
114
|
+
let archetype = '';
|
|
115
|
+
const narratives: ParsedNarrative[] = [];
|
|
116
|
+
let currentNarrative: NarrativeState | null = null;
|
|
117
|
+
const voice: Partial<ParsedVoice> = { always: [], never: [] };
|
|
118
|
+
const pillars: Partial<ParsedPillars> = { primary: [], avoid: [] };
|
|
119
|
+
const audiences: Record<string, Partial<ParsedAudience>> = {};
|
|
120
|
+
const antiAudiences: Record<string, Partial<ParsedAntiAudience>> = {};
|
|
121
|
+
const values: ParsedValue[] = [];
|
|
122
|
+
|
|
123
|
+
let block: Block = 'top';
|
|
124
|
+
let currentAudience = '';
|
|
125
|
+
let currentAntiAudience = '';
|
|
126
|
+
let currentValueName = '';
|
|
127
|
+
let currentValueBehavior = '';
|
|
128
|
+
let listTarget: ListTarget | null = null;
|
|
129
|
+
let continuationKey: string | null = null;
|
|
130
|
+
|
|
131
|
+
function flushNarrative() {
|
|
132
|
+
if (currentNarrative && currentNarrative.text) {
|
|
133
|
+
narratives.push({
|
|
134
|
+
name: currentNarrative.name,
|
|
135
|
+
primary: currentNarrative.primary,
|
|
136
|
+
text: currentNarrative.text.trim(),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
currentNarrative = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function flushValue() {
|
|
143
|
+
if (currentValueName && currentValueBehavior) {
|
|
144
|
+
values.push({ name: currentValueName, behavior: currentValueBehavior.trim() });
|
|
145
|
+
}
|
|
146
|
+
currentValueName = '';
|
|
147
|
+
currentValueBehavior = '';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
for (let i = 0; i < lines.length; i++) {
|
|
151
|
+
const raw = lines[i];
|
|
152
|
+
const lineNum = i + 1;
|
|
153
|
+
|
|
154
|
+
// Strip inline comments (but not inside quoted strings)
|
|
155
|
+
const line = raw.replace(/\s+#.*$/, '');
|
|
156
|
+
|
|
157
|
+
// Skip blank lines and full-line comments
|
|
158
|
+
if (line.trim() === '' || line.trim().startsWith('#')) {
|
|
159
|
+
if (line.trim() === '') continuationKey = null;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── Values block: 2-space = value name, 4-space = behavior ──
|
|
164
|
+
if (block === 'values' && /^\s{2,}/.test(raw) && !raw.trim().startsWith('#')) {
|
|
165
|
+
const indent = raw.match(/^(\s*)/)?.[1].length ?? 0;
|
|
166
|
+
const text = raw.trim();
|
|
167
|
+
if (indent <= 2 && !text.includes(':')) {
|
|
168
|
+
// New value name (2-space indent)
|
|
169
|
+
flushValue();
|
|
170
|
+
currentValueName = text;
|
|
171
|
+
} else if (currentValueName) {
|
|
172
|
+
// Behavior text (4+ space indent) or continuation
|
|
173
|
+
currentValueBehavior += (currentValueBehavior ? ' ' : '') + text;
|
|
174
|
+
}
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── Narrative block: primary flag or text lines ──
|
|
179
|
+
if (block === 'narrative' && currentNarrative && /^\s{2,}/.test(raw) && !raw.trim().startsWith('#')) {
|
|
180
|
+
const trimmed = raw.trim();
|
|
181
|
+
if (trimmed === 'primary') {
|
|
182
|
+
currentNarrative.primary = true;
|
|
183
|
+
} else {
|
|
184
|
+
currentNarrative.text += (currentNarrative.text ? '\n' : '') + trimmed;
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ── Indented continuation lines ──
|
|
190
|
+
if (/^\s{2,}/.test(raw) && !raw.trim().startsWith('-') && !raw.trim().includes(':')) {
|
|
191
|
+
const continuation = raw.trim();
|
|
192
|
+
|
|
193
|
+
// Top-level multi-line continuation
|
|
194
|
+
if (continuationKey) {
|
|
195
|
+
if (continuationKey === 'essence') essence += ' ' + continuation;
|
|
196
|
+
else if (continuationKey === 'promise') promise += ' ' + continuation;
|
|
197
|
+
else if (continuationKey === 'positioning') positioning += ' ' + continuation;
|
|
198
|
+
else if (continuationKey === 'mission') mission += ' ' + continuation;
|
|
199
|
+
else if (continuationKey === 'vision') vision += ' ' + continuation;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ── List items (- prefixed, indented) ──
|
|
205
|
+
const listMatch = raw.match(/^\s{4,}-\s+(.+)/);
|
|
206
|
+
if (listMatch && listTarget) {
|
|
207
|
+
const value = listMatch[1].trim();
|
|
208
|
+
switch (listTarget) {
|
|
209
|
+
case 'always': voice.always!.push(value); break;
|
|
210
|
+
case 'never': voice.never!.push(value); break;
|
|
211
|
+
case 'primary': pillars.primary!.push(value); break;
|
|
212
|
+
case 'secondary': (pillars.secondary ??= []).push(value); break;
|
|
213
|
+
case 'avoid': pillars.avoid!.push(value); break;
|
|
214
|
+
}
|
|
215
|
+
continuationKey = null;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ── Indented key: value inside a block ──
|
|
220
|
+
const propMatch = raw.match(/^\s{2,}([\w-]+):\s*(.*)/);
|
|
221
|
+
if (propMatch) {
|
|
222
|
+
const [, key, value] = propMatch;
|
|
223
|
+
const val = value.trim();
|
|
224
|
+
listTarget = null;
|
|
225
|
+
continuationKey = null;
|
|
226
|
+
|
|
227
|
+
if (block === 'voice') {
|
|
228
|
+
switch (key) {
|
|
229
|
+
case 'register': voice.register = val; break;
|
|
230
|
+
case 'persona': voice.persona = val; break;
|
|
231
|
+
case 'rhythm': voice.rhythm = val; break;
|
|
232
|
+
case 'always': listTarget = 'always'; break;
|
|
233
|
+
case 'never': listTarget = 'never'; break;
|
|
234
|
+
default:
|
|
235
|
+
throw new Error(`${fileName}:${lineNum}: unknown voice key "${key}"`);
|
|
236
|
+
}
|
|
237
|
+
} else if (block === 'pillars') {
|
|
238
|
+
switch (key) {
|
|
239
|
+
case 'primary':
|
|
240
|
+
if (val) pillars.primary = val.split(',').map(s => s.trim());
|
|
241
|
+
else listTarget = 'primary';
|
|
242
|
+
break;
|
|
243
|
+
case 'secondary':
|
|
244
|
+
if (val) pillars.secondary = val.split(',').map(s => s.trim());
|
|
245
|
+
else listTarget = 'secondary';
|
|
246
|
+
break;
|
|
247
|
+
case 'avoid':
|
|
248
|
+
if (val) pillars.avoid = val.split(',').map(s => s.trim());
|
|
249
|
+
else listTarget = 'avoid';
|
|
250
|
+
break;
|
|
251
|
+
default:
|
|
252
|
+
throw new Error(`${fileName}:${lineNum}: unknown pillars key "${key}"`);
|
|
253
|
+
}
|
|
254
|
+
} else if (block === 'audience' && currentAudience) {
|
|
255
|
+
const aud = audiences[currentAudience] ??= {};
|
|
256
|
+
switch (key) {
|
|
257
|
+
case 'label': aud.label = val; break;
|
|
258
|
+
case 'profile': aud.profile = val; break;
|
|
259
|
+
case 'motivation': aud.motivation = val; break;
|
|
260
|
+
case 'language': aud.language = val; break;
|
|
261
|
+
default:
|
|
262
|
+
throw new Error(`${fileName}:${lineNum}: unknown audience key "${key}"`);
|
|
263
|
+
}
|
|
264
|
+
} else if (block === 'anti-audience' && currentAntiAudience) {
|
|
265
|
+
const aa = antiAudiences[currentAntiAudience] ??= {};
|
|
266
|
+
switch (key) {
|
|
267
|
+
case 'label': aa.label = val; break;
|
|
268
|
+
case 'description': aa.description = val; break;
|
|
269
|
+
default:
|
|
270
|
+
throw new Error(`${fileName}:${lineNum}: unknown anti-audience key "${key}"`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ── Top-level key: value ──
|
|
277
|
+
const topMatch = line.match(/^([\w-]+):\s*(.*)/);
|
|
278
|
+
if (topMatch) {
|
|
279
|
+
const [, key, value] = topMatch;
|
|
280
|
+
const val = value.trim();
|
|
281
|
+
if (block === 'values') flushValue();
|
|
282
|
+
if (block === 'narrative') flushNarrative();
|
|
283
|
+
block = 'top';
|
|
284
|
+
listTarget = null;
|
|
285
|
+
continuationKey = null;
|
|
286
|
+
|
|
287
|
+
switch (key) {
|
|
288
|
+
case 'essence':
|
|
289
|
+
essence = val;
|
|
290
|
+
continuationKey = 'essence';
|
|
291
|
+
break;
|
|
292
|
+
case 'promise':
|
|
293
|
+
promise = val;
|
|
294
|
+
continuationKey = 'promise';
|
|
295
|
+
break;
|
|
296
|
+
case 'tagline':
|
|
297
|
+
tagline = val;
|
|
298
|
+
break;
|
|
299
|
+
case 'positioning':
|
|
300
|
+
positioning = val;
|
|
301
|
+
continuationKey = 'positioning';
|
|
302
|
+
break;
|
|
303
|
+
case 'mission':
|
|
304
|
+
mission = val;
|
|
305
|
+
continuationKey = 'mission';
|
|
306
|
+
break;
|
|
307
|
+
case 'vision':
|
|
308
|
+
vision = val;
|
|
309
|
+
continuationKey = 'vision';
|
|
310
|
+
break;
|
|
311
|
+
case 'archetype':
|
|
312
|
+
archetype = val;
|
|
313
|
+
break;
|
|
314
|
+
default:
|
|
315
|
+
throw new Error(`${fileName}:${lineNum}: unknown top-level key "${key}"`);
|
|
316
|
+
}
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ── Block headers ──
|
|
321
|
+
if (raw.match(/^voice\s*$/)) {
|
|
322
|
+
if (block === 'values') flushValue();
|
|
323
|
+
if (block === 'narrative') flushNarrative();
|
|
324
|
+
block = 'voice';
|
|
325
|
+
listTarget = null;
|
|
326
|
+
continuationKey = null;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (raw.match(/^pillars\s*$/)) {
|
|
331
|
+
if (block === 'values') flushValue();
|
|
332
|
+
if (block === 'narrative') flushNarrative();
|
|
333
|
+
block = 'pillars';
|
|
334
|
+
listTarget = null;
|
|
335
|
+
continuationKey = null;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (raw.match(/^values\s*$/)) {
|
|
340
|
+
if (block === 'values') flushValue();
|
|
341
|
+
if (block === 'narrative') flushNarrative();
|
|
342
|
+
block = 'values';
|
|
343
|
+
listTarget = null;
|
|
344
|
+
continuationKey = null;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const narrativeMatch = raw.match(/^narrative\s+(.+?)\s*$/);
|
|
349
|
+
if (narrativeMatch) {
|
|
350
|
+
if (block === 'values') flushValue();
|
|
351
|
+
if (block === 'narrative') flushNarrative();
|
|
352
|
+
block = 'narrative';
|
|
353
|
+
currentNarrative = { name: narrativeMatch[1].trim(), primary: false, text: '' };
|
|
354
|
+
listTarget = null;
|
|
355
|
+
continuationKey = null;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const audienceMatch = raw.match(/^audience\s+(\S+)\s*$/);
|
|
360
|
+
if (audienceMatch) {
|
|
361
|
+
if (block === 'values') flushValue();
|
|
362
|
+
if (block === 'narrative') flushNarrative();
|
|
363
|
+
block = 'audience';
|
|
364
|
+
currentAudience = audienceMatch[1];
|
|
365
|
+
audiences[currentAudience] ??= {};
|
|
366
|
+
listTarget = null;
|
|
367
|
+
continuationKey = null;
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const antiAudienceMatch = raw.match(/^anti-audience\s+(\S+)\s*$/);
|
|
372
|
+
if (antiAudienceMatch) {
|
|
373
|
+
if (block === 'values') flushValue();
|
|
374
|
+
if (block === 'narrative') flushNarrative();
|
|
375
|
+
block = 'anti-audience';
|
|
376
|
+
currentAntiAudience = antiAudienceMatch[1];
|
|
377
|
+
antiAudiences[currentAntiAudience] ??= {};
|
|
378
|
+
listTarget = null;
|
|
379
|
+
continuationKey = null;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Flush last value/narrative if in those blocks
|
|
385
|
+
if (block === 'values') flushValue();
|
|
386
|
+
if (block === 'narrative') flushNarrative();
|
|
387
|
+
|
|
388
|
+
// ── Validation ──────────────────────────────────────────────────────────────
|
|
389
|
+
|
|
390
|
+
if (!essence) throw new Error(`${fileName}: missing required field "essence:"`);
|
|
391
|
+
if (!promise) throw new Error(`${fileName}: missing required field "promise:"`);
|
|
392
|
+
if (!voice.register) throw new Error(`${fileName}: missing required field "voice.register:"`);
|
|
393
|
+
if (!voice.persona) throw new Error(`${fileName}: missing required field "voice.persona:"`);
|
|
394
|
+
if (!voice.always?.length) throw new Error(`${fileName}: voice.always must have at least one rule`);
|
|
395
|
+
if (!voice.never?.length) throw new Error(`${fileName}: voice.never must have at least one rule`);
|
|
396
|
+
if (!pillars.primary?.length) throw new Error(`${fileName}: pillars.primary must have at least one topic`);
|
|
397
|
+
if (!pillars.avoid?.length) throw new Error(`${fileName}: pillars.avoid must have at least one topic`);
|
|
398
|
+
if (Object.keys(audiences).length === 0) throw new Error(`${fileName}: at least one audience block is required`);
|
|
399
|
+
|
|
400
|
+
for (const [id, aud] of Object.entries(audiences)) {
|
|
401
|
+
if (!aud.label) throw new Error(`${fileName}: audience "${id}" missing required field "label:"`);
|
|
402
|
+
if (!aud.motivation) throw new Error(`${fileName}: audience "${id}" missing required field "motivation:"`);
|
|
403
|
+
if (!aud.language) throw new Error(`${fileName}: audience "${id}" missing required field "language:"`);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
for (const [id, aa] of Object.entries(antiAudiences)) {
|
|
407
|
+
if (!aa.label) throw new Error(`${fileName}: anti-audience "${id}" missing required field "label:"`);
|
|
408
|
+
if (!aa.description) throw new Error(`${fileName}: anti-audience "${id}" missing required field "description:"`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ── Hex value exclusion rule ──
|
|
412
|
+
const hexPattern = /#[0-9A-Fa-f]{3,8}\b/;
|
|
413
|
+
if (hexPattern.test(content.replace(/#.*$/gm, ''))) {
|
|
414
|
+
throw new Error(`${fileName}: identity files must not contain hex color values`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const result: ParsedIdentity = {
|
|
418
|
+
essence,
|
|
419
|
+
promise,
|
|
420
|
+
voice: voice as ParsedVoice,
|
|
421
|
+
pillars: pillars as ParsedPillars,
|
|
422
|
+
audiences: audiences as Record<string, ParsedAudience>,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Optional fields — only include if present
|
|
426
|
+
if (tagline) result.tagline = tagline;
|
|
427
|
+
if (positioning) result.positioning = positioning;
|
|
428
|
+
if (mission) result.mission = mission;
|
|
429
|
+
if (vision) result.vision = vision;
|
|
430
|
+
if (archetype) result.archetype = archetype;
|
|
431
|
+
if (narratives.length > 0) result.narratives = narratives;
|
|
432
|
+
if (values.length > 0) result.values = values;
|
|
433
|
+
if (Object.keys(antiAudiences).length > 0) {
|
|
434
|
+
result.antiAudiences = antiAudiences as Record<string, ParsedAntiAudience>;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return result;
|
|
438
|
+
}
|
package/parser/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Brand Intent — reference parser
|
|
2
|
+
// All five parsers are pure functions:
|
|
3
|
+
// they take a string (file content) and filename, return a parsed object.
|
|
4
|
+
|
|
5
|
+
export { parseIdentityFile } from './identityParser';
|
|
6
|
+
export type { ParsedIdentity, ParsedVoice, ParsedPillars, ParsedAudience, ParsedAntiAudience, ParsedValue } from './identityParser';
|
|
7
|
+
|
|
8
|
+
export { parseBrandFile } from './brandParser';
|
|
9
|
+
export type { ParsedBrand, ParsedFontDef, ParsedTypographyDef, ParsedDividerDef, BrandColorPrintSpec, ParsedAssetDef, ParsedBadgeStyle } from './brandParser';
|
|
10
|
+
|
|
11
|
+
export { parseFormatFile } from './formatParser';
|
|
12
|
+
export type { ParsedFormat } from './formatParser';
|
|
13
|
+
|
|
14
|
+
export { parsePurposeFile } from './purposeParser';
|
|
15
|
+
export type { ParsedPurpose, ParsedPurposeSlot, Density } from './purposeParser';
|
|
16
|
+
|
|
17
|
+
export { parseCompositionFile } from './compositionParser';
|
|
18
|
+
export type { ParsedComposition, ParsedFlowRegion, ParsedStickyRegion } from './compositionParser';
|
|
19
|
+
|
|
20
|
+
export type { SlotId, ZoneInsets, TextAlign } from './types';
|