@longform/longform 0.0.2 → 0.0.3
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/lib/longform.test.ts +33 -1
- package/lib/longform.ts +42 -11
- package/lib/types.ts +12 -13
- package/package.json +1 -1
package/lib/longform.test.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { parse, resolve } from "node:path";
|
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import { writeFile, unlink } from "node:fs/promises";
|
|
11
11
|
import * as prettier from 'prettier';
|
|
12
|
+
import {execPath} from 'node:process';
|
|
12
13
|
|
|
13
14
|
async function validate(html: string, type: 'html' | 'xml' = 'html'): Promise<boolean> {
|
|
14
15
|
return true;
|
|
@@ -301,7 +302,7 @@ const html9 = `\
|
|
|
301
302
|
const template9 = `\
|
|
302
303
|
<div id="my-template" aria-label="Something something 4">Hello world!</div>\
|
|
303
304
|
`;
|
|
304
|
-
test('It renders templated element fragments', () => {
|
|
305
|
+
test('It renders templated element fragments', { only: true }, () => {
|
|
305
306
|
const parsed = longform(lf9);
|
|
306
307
|
console.log(parsed)
|
|
307
308
|
const res = processTemplate(parsed.templates['my-template'], { position: 4 }, x => {
|
|
@@ -312,4 +313,35 @@ test('It renders templated element fragments', () => {
|
|
|
312
313
|
assert.equal(res, template9);
|
|
313
314
|
});
|
|
314
315
|
|
|
316
|
+
const lf10 = `
|
|
317
|
+
@root
|
|
318
|
+
@doctype:: html
|
|
319
|
+
html::
|
|
320
|
+
@mount:: head
|
|
321
|
+
head::
|
|
322
|
+
body::
|
|
323
|
+
@mount:: header
|
|
324
|
+
header::
|
|
325
|
+
@mount:: main
|
|
326
|
+
main::
|
|
327
|
+
@mount:: footer
|
|
328
|
+
`;
|
|
329
|
+
test('It breaks mount points up into individual dom slices', () => {
|
|
330
|
+
const parsed = longform(lf10, console.log);
|
|
331
|
+
|
|
332
|
+
console.log(parsed);
|
|
333
|
+
|
|
334
|
+
assert(parsed.mountable);
|
|
335
|
+
assert.equal(parsed.mountPoints[0].id, 'head');
|
|
336
|
+
assert.equal(parsed.mountPoints[0].part, '<!doctype html><html><head data-lf-mount="head">');
|
|
337
|
+
assert.equal(parsed.mountPoints[1].id, 'header');
|
|
338
|
+
assert.equal(parsed.mountPoints[1].part, '</head><body><header data-lf-mount="header">');
|
|
339
|
+
assert.equal(parsed.mountPoints[2].id, 'main');
|
|
340
|
+
assert.equal(parsed.mountPoints[2].part, '</header><main data-lf-mount="main">');
|
|
341
|
+
assert.equal(parsed.tail, '</main></body></html>');
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
315
347
|
|
package/lib/longform.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FragmentType, ParsedResult, WorkingElement, WorkingFragment, Fragment } from "./types.ts";
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
4
|
FragmentType,
|
|
@@ -51,22 +51,15 @@ function makeElement(indent: number = 0): WorkingElement {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function makeChunk(type: ChunkType = 'parsed'): WorkingChunk {
|
|
55
|
-
return {
|
|
56
|
-
type,
|
|
57
|
-
html: '',
|
|
58
|
-
els: [],
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
54
|
function makeFragment(type: FragmentType = 'bare'): WorkingFragment {
|
|
63
55
|
return {
|
|
64
56
|
type,
|
|
65
57
|
html: '',
|
|
66
58
|
template: false,
|
|
59
|
+
mountable: false,
|
|
67
60
|
els: [],
|
|
68
|
-
chunks: [],
|
|
69
61
|
refs: [],
|
|
62
|
+
mountPoints: [],
|
|
70
63
|
};
|
|
71
64
|
}
|
|
72
65
|
|
|
@@ -84,7 +77,6 @@ export function longform(doc: string, debug: (...d: unknown[]) => void = () => {
|
|
|
84
77
|
, verbatimIndent: number | null = null
|
|
85
78
|
, verbatimFirst: boolean = false
|
|
86
79
|
, element: WorkingElement = makeElement()
|
|
87
|
-
, chunk: WorkingChunk | null = makeChunk()
|
|
88
80
|
, fragment: WorkingFragment = makeFragment()
|
|
89
81
|
// the root fragment
|
|
90
82
|
, root: WorkingFragment | null = null
|
|
@@ -119,6 +111,10 @@ export function longform(doc: string, debug: (...d: unknown[]) => void = () => {
|
|
|
119
111
|
}
|
|
120
112
|
}
|
|
121
113
|
|
|
114
|
+
if (element.mount != null) {
|
|
115
|
+
fragment.html += ` data-lf-mount="${element.mount}"`;
|
|
116
|
+
}
|
|
117
|
+
|
|
122
118
|
if (element.id != null) {
|
|
123
119
|
fragment.html += ' id="' + element.id + '"';
|
|
124
120
|
}
|
|
@@ -343,6 +339,21 @@ export function longform(doc: string, debug: (...d: unknown[]) => void = () => {
|
|
|
343
339
|
}
|
|
344
340
|
}
|
|
345
341
|
|
|
342
|
+
// this is a hack to get temp support of mounting
|
|
343
|
+
// working. In the future it will be moved to a
|
|
344
|
+
// server specific process.
|
|
345
|
+
if (element.mount != null) {
|
|
346
|
+
const id = element.mount;
|
|
347
|
+
applyIndent(indent + 1);
|
|
348
|
+
fragment.mountPoints.push({
|
|
349
|
+
id,
|
|
350
|
+
part: fragment.html,
|
|
351
|
+
});
|
|
352
|
+
fragment.html = '';
|
|
353
|
+
applyIndent(indent);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
|
|
346
357
|
if (!pr && tx != null) {
|
|
347
358
|
element.text = tx;
|
|
348
359
|
} else if (pr) {
|
|
@@ -427,6 +438,18 @@ export function longform(doc: string, debug: (...d: unknown[]) => void = () => {
|
|
|
427
438
|
}
|
|
428
439
|
|
|
429
440
|
applyIndent(0);
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
case 'mount': {
|
|
444
|
+
if (m2[3] == null) {
|
|
445
|
+
throw new Error('Mount points must have a name');
|
|
446
|
+
} else if (fragment.type !== 'root') {
|
|
447
|
+
throw new Error('Mounting is only allowed on a root element');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
fragment.mountable = true;
|
|
451
|
+
element.mount = m2[3].trim();
|
|
452
|
+
break;
|
|
430
453
|
}
|
|
431
454
|
}
|
|
432
455
|
|
|
@@ -503,6 +526,14 @@ export function longform(doc: string, debug: (...d: unknown[]) => void = () => {
|
|
|
503
526
|
return fragment;
|
|
504
527
|
}
|
|
505
528
|
|
|
529
|
+
if (root?.mountable) {
|
|
530
|
+
output.mountable = true;
|
|
531
|
+
output.tail = root.html;
|
|
532
|
+
output.mountPoints = root.mountPoints;
|
|
533
|
+
|
|
534
|
+
return output;
|
|
535
|
+
}
|
|
536
|
+
|
|
506
537
|
for (let i = 0; i < parsed.size + 1; i++) {
|
|
507
538
|
let fragment: WorkingFragment;
|
|
508
539
|
|
package/lib/types.ts
CHANGED
|
@@ -8,18 +8,7 @@ export type WorkingElement = {
|
|
|
8
8
|
attrs: Record<string, string | null>;
|
|
9
9
|
text?: string;
|
|
10
10
|
html: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export type ChunkType =
|
|
14
|
-
| 'parsed'
|
|
15
|
-
| 'ref'
|
|
16
|
-
| 'scope'
|
|
17
|
-
;
|
|
18
|
-
|
|
19
|
-
export type WorkingChunk = {
|
|
20
|
-
type: ChunkType;
|
|
21
|
-
html: string;
|
|
22
|
-
els: WorkingElement[];
|
|
11
|
+
mount?: string;
|
|
23
12
|
};
|
|
24
13
|
|
|
25
14
|
export type WorkingFragmentType =
|
|
@@ -28,6 +17,7 @@ export type WorkingFragmentType =
|
|
|
28
17
|
| 'bare'
|
|
29
18
|
| 'range'
|
|
30
19
|
| 'text'
|
|
20
|
+
| 'mount'
|
|
31
21
|
| 'template'
|
|
32
22
|
;
|
|
33
23
|
|
|
@@ -47,11 +37,12 @@ export type FragmentRef = {
|
|
|
47
37
|
export type WorkingFragment = {
|
|
48
38
|
id?: string;
|
|
49
39
|
template: boolean;
|
|
40
|
+
mountable: boolean;
|
|
50
41
|
type: WorkingFragmentType;
|
|
51
42
|
html: string;
|
|
52
43
|
refs: FragmentRef[];
|
|
53
|
-
chunks: WorkingChunk[];
|
|
54
44
|
els: WorkingElement[];
|
|
45
|
+
mountPoints: MountPoint[];
|
|
55
46
|
};
|
|
56
47
|
|
|
57
48
|
export type Fragment = {
|
|
@@ -61,9 +52,17 @@ export type Fragment = {
|
|
|
61
52
|
html: string;
|
|
62
53
|
};
|
|
63
54
|
|
|
55
|
+
export type MountPoint = {
|
|
56
|
+
id: string;
|
|
57
|
+
part: string;
|
|
58
|
+
};
|
|
59
|
+
|
|
64
60
|
export type ParsedResult = {
|
|
61
|
+
mountable?: boolean;
|
|
65
62
|
root: string | null;
|
|
66
63
|
selector: string | null;
|
|
64
|
+
mountPoints: MountPoint[];
|
|
65
|
+
tail?: string;
|
|
67
66
|
fragments: Record<string, Fragment>;
|
|
68
67
|
templates: Record<string, string>;
|
|
69
68
|
};
|