@longform/longform 0.0.6 → 0.0.8
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 +30 -2
- package/dist/longform.cjs +309 -148
- package/dist/longform.cjs.map +1 -1
- package/dist/longform.d.ts +4 -4
- package/dist/longform.js +309 -148
- package/dist/longform.js.br +0 -0
- package/dist/longform.js.gz +0 -0
- package/dist/longform.js.map +1 -1
- package/dist/longform.min.js +309 -148
- package/dist/longform.min.js.br +0 -0
- package/dist/longform.min.js.gz +0 -0
- package/dist/longform.min.js.map +1 -1
- package/dist/types.d.ts +71 -1
- package/lib/longform.ts +376 -165
- package/lib/types.ts +92 -1
- package/package.json +21 -12
- package/lib/longform.test.ts +0 -347
package/dist/longform.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
const
|
|
1
|
+
const LINE = 0, INDENT = 1, DIRECTIVE_KEY = 2, DIRECTIVE = 3, DIRECTIVE_INLINE_ARGS = 4, ID_TYPE = 5, ID = 6, FRAGMENT_TYPE = 7, ELEMENT = 8, ATTR = 9;
|
|
2
|
+
const sniffTestRe = /^((?: )*)(?:(@)([a-z][a-z\-]*(?::[a-z][a-z\-]*)?)(?:(?::: (.*))| *)?|(##?)([a-z][a-z\-]*)(?: ?(?: +([\["]))? *|(?: *))?|(?:[a-z][a-z\-]*(?::[a-z][a-z\-])?.*(::).*)|(?:(\[)[a-z][a-z\-]?.*(?:=.+)?\]\w*)|(.+))$/gmi
|
|
3
|
+
// captures a single element definition which could be in a chain.
|
|
4
|
+
// id, class and attributes are matched as a single block for a later loop
|
|
5
|
+
// if in chained situation the regexp will need to be looped over for each element
|
|
6
|
+
// we know the element is the last if the final capture group has a positive match
|
|
7
|
+
// or if the line is consumed by the regexp.
|
|
8
|
+
//, outer = /([a-z][\w\-]*(?::[a-z][\w\-]*)?)([^:]+)*::(?: (?:({{?)|(.*)))?/gi
|
|
9
|
+
, outer = /([a-z][\w\-]*(?::[a-z][\w\-]*)?)((?:(?:[^:])|(?::(?!:)))*)::(?: (?:({{?)|(.*)))?/gi
|
|
10
|
+
//, outer = /([a-z][\w\-]*(?::[a-z][\w\-]*)?)(.+?(?=::))?(?: (?:({{?)|(.*)))?/gi
|
|
11
|
+
// captures each id, class and attribute declaration in an element
|
|
12
|
+
, inner = /(?:\.([a-z][\w\-]+)|#([a-z][\w\-]+)|\[([a-z][a-z\-]+(?::[a-z][a-z|\-]*)?)(?:=(?:"([^"]+)"|'([^']+)'|([^\]]+)))?\])/gi, attribute1 = /((?:\ \ )+)\[(\w[\w-]*(?::\w[\w-]*)?)(?:=([^\n]+))?\]/, preformattedClose = /[ \t]*}}?[ \t]*/, id1 = /((?:\ \ )+)?#(#)?([\w\-]+)(?: ([\["]))?/gmi, identRe = /^(\ \ )+/, text1 = /^((?:\ \ )+)([^ \n][^\n]*)$/i, refRe = /#\[([\w\-]+)\]/g, escapeRe = /([&<>"'#\[\]{}])/g, templateLinesRe = /^(\ \ )?([^\n]+)$/gmi
|
|
13
|
+
// TODO: Benchmark v Array.includes()
|
|
14
|
+
, voids = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wrb']);
|
|
2
15
|
let m1, m2, m3;
|
|
3
16
|
const entities = {
|
|
4
17
|
'&': '&',
|
|
@@ -20,8 +33,17 @@ function escape(value) {
|
|
|
20
33
|
function makeElement(indent = 0) {
|
|
21
34
|
return {
|
|
22
35
|
indent,
|
|
23
|
-
|
|
36
|
+
key: undefined,
|
|
37
|
+
id: undefined,
|
|
38
|
+
tag: undefined,
|
|
39
|
+
class: undefined,
|
|
40
|
+
text: undefined,
|
|
24
41
|
attrs: {},
|
|
42
|
+
html: '',
|
|
43
|
+
mount: undefined,
|
|
44
|
+
serializerConfig: undefined,
|
|
45
|
+
chain: undefined,
|
|
46
|
+
beforeRender: undefined,
|
|
25
47
|
};
|
|
26
48
|
}
|
|
27
49
|
function makeFragment(type = 'bare') {
|
|
@@ -35,28 +57,100 @@ function makeFragment(type = 'bare') {
|
|
|
35
57
|
mountPoints: [],
|
|
36
58
|
};
|
|
37
59
|
}
|
|
60
|
+
class Doc {
|
|
61
|
+
id = undefined;
|
|
62
|
+
lang = undefined;
|
|
63
|
+
meta = {};
|
|
64
|
+
#serializerConfig;
|
|
65
|
+
constructor(id, lang, allowAll, allowedAttributes, allowedElements) {
|
|
66
|
+
this.id = id;
|
|
67
|
+
this.lang = lang;
|
|
68
|
+
this.#serializerConfig = {
|
|
69
|
+
allowAll: allowAll ?? false,
|
|
70
|
+
allowedAttributes: allowedAttributes ?? [],
|
|
71
|
+
allowedElements: {},
|
|
72
|
+
};
|
|
73
|
+
if (allowedElements != null) {
|
|
74
|
+
for (let i = 0, l = allowedElements.length, el = allowedElements[i]; i < l; i++) {
|
|
75
|
+
if (typeof el === 'string') {
|
|
76
|
+
this.#serializerConfig.allowedElements[el] = {
|
|
77
|
+
tag: el,
|
|
78
|
+
attrs: [],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.#serializerConfig.allowedElements[el.tag] = el;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
Object.freeze(this);
|
|
87
|
+
}
|
|
88
|
+
allowAll() {
|
|
89
|
+
}
|
|
90
|
+
allowAttributes() {
|
|
91
|
+
}
|
|
92
|
+
allowElements() {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const directiveValidator = /^[a-z][a-z\-]*\:[a-z][a-z\-]*$/gi;
|
|
38
96
|
/**
|
|
39
97
|
* Parses a longform document into a object containing the root and fragments
|
|
40
98
|
* in the output format.
|
|
41
99
|
*
|
|
42
|
-
* @param
|
|
43
|
-
* @
|
|
100
|
+
* @param input - The Longform document to parse.
|
|
101
|
+
* @param args - Arguments for the Longform parser.
|
|
44
102
|
*/
|
|
45
|
-
function longform(
|
|
103
|
+
function longform(input, args) {
|
|
46
104
|
let textIndent = null, verbatimSerialize = true, verbatimIndent = null, verbatimFirst = false, element = makeElement(), fragment = makeFragment()
|
|
47
105
|
// the root fragment
|
|
48
|
-
, root = null;
|
|
106
|
+
, root = null, id, lang, doc;
|
|
49
107
|
// ids of claimed fragments
|
|
50
108
|
const claimed = new Set()
|
|
51
109
|
// parsed fragments
|
|
52
|
-
, parsed = new Map(), output = Object.create(null);
|
|
110
|
+
, parsed = new Map(), output = Object.create(null), directives = {};
|
|
53
111
|
output.fragments = Object.create(null);
|
|
54
112
|
output.templates = Object.create(null);
|
|
113
|
+
if (args?.directives != null) {
|
|
114
|
+
const entries = Object.entries(args.directives);
|
|
115
|
+
for (let i = 0, l = entries.length; i < l; i++) {
|
|
116
|
+
if (!directiveValidator.test(entries[i][0])) {
|
|
117
|
+
console.warn(`Invalid custom directive name '${entries[i][0]}'`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
directives[entries[i][0]] = entries[i][1];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
55
123
|
/**
|
|
56
124
|
* Closes any current in progress element definition
|
|
57
125
|
* and creates a new working element.
|
|
58
126
|
*/
|
|
59
127
|
function applyIndent(targetIndent) {
|
|
128
|
+
if (Array.isArray(element.beforeRender)) {
|
|
129
|
+
const el = {
|
|
130
|
+
id: element.id,
|
|
131
|
+
tag: element.tag,
|
|
132
|
+
class: element.class,
|
|
133
|
+
attrs: element.attrs,
|
|
134
|
+
};
|
|
135
|
+
const chain = [];
|
|
136
|
+
for (let i = 0, l = element.chain.length, el = element.chain[i]; i < l; i++) {
|
|
137
|
+
chain.push({
|
|
138
|
+
id: el.id,
|
|
139
|
+
tag: el.tag,
|
|
140
|
+
class: el.class,
|
|
141
|
+
attrs: el.attrs,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (let i = 0, l = element.beforeRender.length, def = element.beforeRender[i]; i < l; i++) {
|
|
145
|
+
def.beforeRender({
|
|
146
|
+
el,
|
|
147
|
+
chain,
|
|
148
|
+
doc,
|
|
149
|
+
inlineArg: def.inlineArg,
|
|
150
|
+
blockArg: def.blockArg,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
60
154
|
if (element.tag != null) {
|
|
61
155
|
const root = fragment.type === 'range'
|
|
62
156
|
? targetIndent < 2
|
|
@@ -70,13 +164,13 @@ function longform(doc, debug = () => { }) {
|
|
|
70
164
|
fragment.html += ` data-lf="${fragment.id}"`;
|
|
71
165
|
}
|
|
72
166
|
}
|
|
73
|
-
if (element.mount
|
|
167
|
+
if (element.mount !== undefined) {
|
|
74
168
|
fragment.html += ` data-lf-mount="${element.mount}"`;
|
|
75
169
|
}
|
|
76
|
-
if (element.id
|
|
170
|
+
if (element.id !== undefined) {
|
|
77
171
|
fragment.html += ' id="' + element.id + '"';
|
|
78
172
|
}
|
|
79
|
-
if (element.class
|
|
173
|
+
if (element.class !== undefined) {
|
|
80
174
|
fragment.html += ' class="' + element.class + '"';
|
|
81
175
|
}
|
|
82
176
|
for (const attr of Object.entries(element.attrs)) {
|
|
@@ -88,6 +182,28 @@ function longform(doc, debug = () => { }) {
|
|
|
88
182
|
}
|
|
89
183
|
}
|
|
90
184
|
fragment.html += '>';
|
|
185
|
+
if (Array.isArray(element.chain)) {
|
|
186
|
+
let chained;
|
|
187
|
+
for (let i = 0, l = element.chain.length; i < l; i++) {
|
|
188
|
+
chained = element.chain[i];
|
|
189
|
+
fragment.html += '<' + chained.tag;
|
|
190
|
+
if (chained.id !== undefined) {
|
|
191
|
+
fragment.html += ' id="' + chained.id + '"';
|
|
192
|
+
}
|
|
193
|
+
if (chained.class != undefined) {
|
|
194
|
+
fragment.html += ' class="' + chained.class + '"';
|
|
195
|
+
}
|
|
196
|
+
for (const attr of Object.entries(chained.attrs)) {
|
|
197
|
+
if (attr[1] === undefined) {
|
|
198
|
+
fragment.html += ' ' + attr[0];
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
fragment.html += ` ${attr[0]}="${attr[1]}"`;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
fragment.html += '>';
|
|
205
|
+
}
|
|
206
|
+
}
|
|
91
207
|
if (!voids.has(element.tag) && element.text != null) {
|
|
92
208
|
fragment.html += element.text;
|
|
93
209
|
}
|
|
@@ -100,10 +216,14 @@ function longform(doc, debug = () => { }) {
|
|
|
100
216
|
while (fragment.els.length !== 0 && (targetIndent == null ||
|
|
101
217
|
fragment.els[fragment.els.length - 1].indent !== targetIndent - 1)) {
|
|
102
218
|
const element = fragment.els.pop();
|
|
219
|
+
if (Array.isArray(element.chain)) {
|
|
220
|
+
for (let i = 0, l = element.chain.length; i < l; i++) {
|
|
221
|
+
fragment.html += `</${element.chain[i].tag}>`;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
103
224
|
fragment.html += `</${element?.tag}>`;
|
|
104
225
|
}
|
|
105
226
|
if (targetIndent === 0) {
|
|
106
|
-
debug(0, '<', fragment.type, fragment.id);
|
|
107
227
|
if (fragment.template) {
|
|
108
228
|
output.templates[fragment.id] = fragment.html;
|
|
109
229
|
}
|
|
@@ -120,7 +240,7 @@ function longform(doc, debug = () => { }) {
|
|
|
120
240
|
element = makeElement(targetIndent);
|
|
121
241
|
}
|
|
122
242
|
}
|
|
123
|
-
while ((m1 = sniffTestRe.exec(
|
|
243
|
+
main: while ((m1 = sniffTestRe.exec(input))) {
|
|
124
244
|
if (m1[1] === '--') {
|
|
125
245
|
continue;
|
|
126
246
|
}
|
|
@@ -133,14 +253,13 @@ function longform(doc, debug = () => { }) {
|
|
|
133
253
|
// by ending the declaration with `:: {`.
|
|
134
254
|
if (verbatimIndent != null) {
|
|
135
255
|
// inside a script or preformatted block
|
|
136
|
-
|
|
137
|
-
m2 =
|
|
256
|
+
identRe.lastIndex = 0;
|
|
257
|
+
m2 = identRe.exec(m1[0]);
|
|
138
258
|
const indent = m2 == null
|
|
139
259
|
? null
|
|
140
260
|
: m2[0].length / 2;
|
|
141
261
|
if (m2 == null || indent <= verbatimIndent) {
|
|
142
262
|
fragment.html += '\n';
|
|
143
|
-
debug(indent, '}', m2?.[0]);
|
|
144
263
|
applyIndent(indent);
|
|
145
264
|
verbatimIndent = null;
|
|
146
265
|
verbatimFirst = false;
|
|
@@ -151,7 +270,6 @@ function longform(doc, debug = () => { }) {
|
|
|
151
270
|
}
|
|
152
271
|
else {
|
|
153
272
|
const line = m1[0].replace(' '.repeat(verbatimIndent + 1), '');
|
|
154
|
-
debug(indent, '{', line);
|
|
155
273
|
if (element.tag != null) {
|
|
156
274
|
applyIndent(indent);
|
|
157
275
|
}
|
|
@@ -162,69 +280,148 @@ function longform(doc, debug = () => { }) {
|
|
|
162
280
|
fragment.html += '\n';
|
|
163
281
|
}
|
|
164
282
|
if (verbatimSerialize) {
|
|
165
|
-
fragment.html +=
|
|
283
|
+
fragment.html += line;
|
|
166
284
|
}
|
|
167
285
|
else {
|
|
168
|
-
fragment.html += line;
|
|
286
|
+
fragment.html += escape(line);
|
|
169
287
|
}
|
|
170
288
|
continue;
|
|
171
289
|
}
|
|
172
290
|
}
|
|
173
|
-
if (m1[
|
|
291
|
+
if (m1[LINE].trim() === '') {
|
|
174
292
|
continue;
|
|
175
293
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
294
|
+
// The id and lang directives should proceed all other directives and
|
|
295
|
+
// fragment declarations.
|
|
296
|
+
if (doc === undefined) {
|
|
297
|
+
const inlineArgs = m1[DIRECTIVE_INLINE_ARGS] ?? '';
|
|
298
|
+
switch (m1[DIRECTIVE]) {
|
|
299
|
+
case 'id': {
|
|
300
|
+
// TODO: Add id validation
|
|
301
|
+
id = inlineArgs.trim();
|
|
302
|
+
continue main;
|
|
303
|
+
}
|
|
304
|
+
case 'lang': {
|
|
305
|
+
lang = inlineArgs.trim();
|
|
306
|
+
continue main;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
doc = new Doc(id, lang, args?.allowAll, args?.allowedAttributes, args?.allowedElements);
|
|
310
|
+
}
|
|
311
|
+
switch (m1[DIRECTIVE_KEY] ?? m1[ID_TYPE] ?? m1[ELEMENT] ?? m1[ATTR]) {
|
|
312
|
+
case '#':
|
|
313
|
+
case '##': {
|
|
179
314
|
id1.lastIndex = 0;
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
315
|
+
const indent = (m1[INDENT].length ?? 0) / 2;
|
|
316
|
+
if (element.tag != null || textIndent != null) {
|
|
317
|
+
applyIndent(indent);
|
|
318
|
+
textIndent = null;
|
|
319
|
+
}
|
|
320
|
+
fragment.id = m1[ID];
|
|
321
|
+
if (indent === 0) {
|
|
322
|
+
if (m1[FRAGMENT_TYPE] == '[') {
|
|
323
|
+
fragment.type = 'range';
|
|
324
|
+
}
|
|
325
|
+
else if (m1[FRAGMENT_TYPE] === '"') {
|
|
326
|
+
fragment.type = 'text';
|
|
327
|
+
}
|
|
328
|
+
else if (m1[ID_TYPE] === '##') {
|
|
329
|
+
fragment.type = 'bare';
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
fragment.type = 'embed';
|
|
333
|
+
element.id = fragment.id;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
element.id = fragment.id;
|
|
338
|
+
}
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
case '@': {
|
|
342
|
+
const indent = m1[INDENT].length / 2;
|
|
343
|
+
if (element.tag != null || textIndent != null) {
|
|
344
|
+
applyIndent(indent);
|
|
345
|
+
}
|
|
346
|
+
switch (m1[DIRECTIVE]) {
|
|
347
|
+
case 'doctype': {
|
|
348
|
+
const args = m1[DIRECTIVE_INLINE_ARGS] ?? 'html';
|
|
349
|
+
fragment.html += `<!doctype ${args.trim()}>`;
|
|
350
|
+
break;
|
|
186
351
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
352
|
+
case 'xml': {
|
|
353
|
+
const args = m1[DIRECTIVE_INLINE_ARGS] ?? 'version="1.0" encoding="UTF-8"';
|
|
354
|
+
fragment.html += `<?xml ${args.trim()}?>`;
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case 'template': {
|
|
358
|
+
let indented = false;
|
|
359
|
+
fragment.template = indent === 0;
|
|
360
|
+
templateLinesRe.lastIndex = sniffTestRe.lastIndex;
|
|
361
|
+
while ((m2 = templateLinesRe.exec(input))) {
|
|
362
|
+
if (m2[1] == null && !indented && fragment.id == null) {
|
|
363
|
+
id1.lastIndex = 0;
|
|
364
|
+
m3 = id1.exec(m2[0]);
|
|
365
|
+
if (m3 != null)
|
|
366
|
+
fragment.id = m3[3];
|
|
367
|
+
fragment.html += m2[0];
|
|
368
|
+
}
|
|
369
|
+
else if (m2[1] == null && indented) {
|
|
370
|
+
sniffTestRe.lastIndex = templateLinesRe.lastIndex - m2[0].length;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
fragment.html += '\n' + m2[0];
|
|
375
|
+
if (m2[1] != null)
|
|
376
|
+
indented = true;
|
|
377
|
+
}
|
|
192
378
|
}
|
|
193
|
-
|
|
194
|
-
|
|
379
|
+
applyIndent(0);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
case 'mount': {
|
|
383
|
+
if (m1[DIRECTIVE_INLINE_ARGS] == null) {
|
|
384
|
+
throw new Error('Mount points must have a name');
|
|
195
385
|
}
|
|
196
|
-
else if (
|
|
197
|
-
|
|
386
|
+
else if (fragment.type !== 'root') {
|
|
387
|
+
throw new Error('Mounting is only allowed on a root element');
|
|
198
388
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
389
|
+
fragment.mountable = true;
|
|
390
|
+
element.mount = m1[DIRECTIVE_INLINE_ARGS].trim();
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
default: {
|
|
394
|
+
const def = directives[m1[DIRECTIVE]];
|
|
395
|
+
if (def == null)
|
|
396
|
+
break;
|
|
397
|
+
if (typeof def.beforeRender === 'function') {
|
|
398
|
+
if (element.id != null) {
|
|
399
|
+
applyIndent(indent);
|
|
400
|
+
}
|
|
401
|
+
if (element.beforeRender == null)
|
|
402
|
+
element.beforeRender = [];
|
|
403
|
+
// TODO: Parse block args
|
|
404
|
+
const applied = {
|
|
405
|
+
...def,
|
|
406
|
+
inlineArg: m1[DIRECTIVE_INLINE_ARGS],
|
|
407
|
+
};
|
|
408
|
+
element.beforeRender.push(applied);
|
|
202
409
|
}
|
|
203
410
|
}
|
|
204
|
-
break;
|
|
205
411
|
}
|
|
412
|
+
break;
|
|
206
413
|
}
|
|
207
|
-
case '@':
|
|
208
414
|
case '[':
|
|
209
|
-
// deno-lint-ignore no-fallthrough
|
|
210
415
|
case '::': {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// if null then invalid element selector
|
|
217
|
-
// allow the default text case to handle
|
|
218
|
-
if (m2 != null) {
|
|
219
|
-
const indent = (m2[1]?.length ?? 0) / 2, tg = m2[2], ar = m2[3], pr = m2[4] === '{' || m2[4] === '{{';
|
|
220
|
-
const tx = pr ? null : m2[4];
|
|
221
|
-
debug(indent, 'e', tg, pr, tx);
|
|
222
|
-
if (element.tag != null ||
|
|
416
|
+
if (m1[ELEMENT] !== undefined) {
|
|
417
|
+
const indent = (m1[INDENT]?.length ?? 0) / 2;
|
|
418
|
+
let preformattedType;
|
|
419
|
+
let inlineText;
|
|
420
|
+
if (element.tag !== undefined ||
|
|
223
421
|
element.indent > indent) {
|
|
224
422
|
applyIndent(indent);
|
|
225
423
|
}
|
|
226
424
|
element.indent = indent;
|
|
227
|
-
element.tag = tg;
|
|
228
425
|
textIndent = null;
|
|
229
426
|
if (indent === 0 && fragment.id == null) {
|
|
230
427
|
if (root != null) ;
|
|
@@ -233,36 +430,58 @@ function longform(doc, debug = () => { }) {
|
|
|
233
430
|
root = fragment;
|
|
234
431
|
}
|
|
235
432
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
433
|
+
const parent = element;
|
|
434
|
+
outer.lastIndex = 0;
|
|
435
|
+
// Looping through chained element declarations
|
|
436
|
+
// foo#x.y::bar::free::
|
|
437
|
+
while ((m2 = outer.exec(m1[LINE]))) {
|
|
438
|
+
let working;
|
|
439
|
+
preformattedType = m2[3];
|
|
440
|
+
inlineText = m2[4];
|
|
441
|
+
if (element.tag === undefined) {
|
|
442
|
+
element.tag = m2[1];
|
|
443
|
+
working = element;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
if (parent.chain === undefined)
|
|
447
|
+
parent.chain = [];
|
|
448
|
+
working = makeElement(indent);
|
|
449
|
+
working.tag = m2[1];
|
|
450
|
+
parent.chain.push(working);
|
|
451
|
+
}
|
|
452
|
+
inner.lastIndex = 0;
|
|
453
|
+
// Looping through ids, classes and attrs
|
|
454
|
+
while ((m3 = inner.exec(m2[2]))) {
|
|
455
|
+
if (m3[2] !== undefined) {
|
|
456
|
+
working.id = m3[2];
|
|
241
457
|
}
|
|
242
|
-
else if (
|
|
243
|
-
if (
|
|
244
|
-
|
|
458
|
+
else if (m3[1] !== undefined) {
|
|
459
|
+
if (working.class == null) {
|
|
460
|
+
working.class = m3[1];
|
|
245
461
|
}
|
|
246
462
|
else {
|
|
247
|
-
|
|
463
|
+
working.class += ' ' + m3[1];
|
|
248
464
|
}
|
|
249
465
|
}
|
|
250
466
|
else {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
467
|
+
// TODO: Preserve quoting style around attribute values
|
|
468
|
+
let value = m3[4] ?? m3[5] ?? m3[6];
|
|
469
|
+
switch (m3[3]) {
|
|
470
|
+
case 'id':
|
|
471
|
+
if (!working.id) {
|
|
472
|
+
working.id = value;
|
|
473
|
+
}
|
|
474
|
+
break;
|
|
475
|
+
case 'class':
|
|
476
|
+
if (!working.class) {
|
|
477
|
+
working.class = value;
|
|
478
|
+
}
|
|
479
|
+
else {
|
|
480
|
+
working.class += ' ' + value;
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
default:
|
|
484
|
+
working.attrs[m3[3]] = value;
|
|
266
485
|
}
|
|
267
486
|
}
|
|
268
487
|
}
|
|
@@ -281,22 +500,21 @@ function longform(doc, debug = () => { }) {
|
|
|
281
500
|
applyIndent(indent);
|
|
282
501
|
break;
|
|
283
502
|
}
|
|
284
|
-
if (
|
|
285
|
-
element.text = tx;
|
|
286
|
-
}
|
|
287
|
-
else if (pr) {
|
|
503
|
+
if (preformattedType !== undefined) {
|
|
288
504
|
verbatimFirst = true;
|
|
289
505
|
verbatimIndent = indent;
|
|
290
|
-
verbatimSerialize =
|
|
506
|
+
verbatimSerialize = preformattedType === '{{';
|
|
507
|
+
}
|
|
508
|
+
else if (inlineText !== undefined) {
|
|
509
|
+
element.text = inlineText;
|
|
291
510
|
}
|
|
292
511
|
break;
|
|
293
512
|
}
|
|
294
513
|
attribute1.lastIndex = 0;
|
|
295
|
-
m2 = m1[
|
|
296
|
-
?
|
|
297
|
-
:
|
|
514
|
+
m2 = m1[ATTR] !== undefined
|
|
515
|
+
? attribute1.exec(m1[LINE])
|
|
516
|
+
: undefined;
|
|
298
517
|
if (m2 != null && element.tag != null) {
|
|
299
|
-
debug('a', m2[2], m2[3]);
|
|
300
518
|
if (m2[2] === 'id') {
|
|
301
519
|
if (element.id == null) {
|
|
302
520
|
element.id = m2[3].trim();
|
|
@@ -318,64 +536,6 @@ function longform(doc, debug = () => { }) {
|
|
|
318
536
|
}
|
|
319
537
|
break;
|
|
320
538
|
}
|
|
321
|
-
directive1.lastIndex = 0;
|
|
322
|
-
m2 = m1[3] != null
|
|
323
|
-
? null
|
|
324
|
-
: directive1.exec(m1[0]);
|
|
325
|
-
if (m2 != null) {
|
|
326
|
-
const indent = (m2[1]?.length ?? 0) / 2;
|
|
327
|
-
if (element.tag != null || textIndent != null) {
|
|
328
|
-
applyIndent(indent);
|
|
329
|
-
}
|
|
330
|
-
debug(indent, 'd', m2[2], m2[3]);
|
|
331
|
-
switch (m2[2]) {
|
|
332
|
-
case 'doctype': {
|
|
333
|
-
fragment.html += `<!doctype ${m2[3] ?? 'html'}>`;
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
case 'xml': {
|
|
337
|
-
fragment.html += `<?xml ${m2[3] ?? 'version="1.0" encoding="UTF-8"'}?>`;
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
case 'template': {
|
|
341
|
-
let indented = false;
|
|
342
|
-
fragment.template = indent === 0;
|
|
343
|
-
templateLinesRe.lastIndex = sniffTestRe.lastIndex;
|
|
344
|
-
while ((m2 = templateLinesRe.exec(doc))) {
|
|
345
|
-
if (m2[1] == null && !indented && fragment.id == null) {
|
|
346
|
-
id1.lastIndex = 0;
|
|
347
|
-
m3 = id1.exec(m2[0]);
|
|
348
|
-
if (m3 != null)
|
|
349
|
-
fragment.id = m3[3];
|
|
350
|
-
fragment.html += m2[0];
|
|
351
|
-
}
|
|
352
|
-
else if (m2[1] == null && indented) {
|
|
353
|
-
sniffTestRe.lastIndex = templateLinesRe.lastIndex - m2[0].length;
|
|
354
|
-
break;
|
|
355
|
-
}
|
|
356
|
-
else {
|
|
357
|
-
fragment.html += '\n' + m2[0];
|
|
358
|
-
if (m2[1] != null)
|
|
359
|
-
indented = true;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
applyIndent(0);
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
case 'mount': {
|
|
366
|
-
if (m2[3] == null) {
|
|
367
|
-
throw new Error('Mount points must have a name');
|
|
368
|
-
}
|
|
369
|
-
else if (fragment.type !== 'root') {
|
|
370
|
-
throw new Error('Mounting is only allowed on a root element');
|
|
371
|
-
}
|
|
372
|
-
fragment.mountable = true;
|
|
373
|
-
element.mount = m2[3].trim();
|
|
374
|
-
break;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
break;
|
|
378
|
-
}
|
|
379
539
|
}
|
|
380
540
|
default: {
|
|
381
541
|
m2 = text1.exec(m1[0]);
|
|
@@ -384,7 +544,6 @@ function longform(doc, debug = () => { }) {
|
|
|
384
544
|
}
|
|
385
545
|
const indent = m2[1].length / 2;
|
|
386
546
|
const tx = m2[2].trim();
|
|
387
|
-
debug(indent, 't', m2[2]);
|
|
388
547
|
if (element.tag != null) {
|
|
389
548
|
applyIndent(indent);
|
|
390
549
|
fragment.html += tx;
|
|
@@ -480,6 +639,8 @@ function longform(doc, debug = () => { }) {
|
|
|
480
639
|
html: fragment.html,
|
|
481
640
|
};
|
|
482
641
|
}
|
|
642
|
+
output.id = doc?.id;
|
|
643
|
+
output.lang = doc?.lang;
|
|
483
644
|
return output;
|
|
484
645
|
}
|
|
485
646
|
const templateRe = /(?:#{([\w][\w\-_]*)})|(?:#\[([\w][\w\-_]+)\])/g;
|
package/dist/longform.js.br
CHANGED
|
Binary file
|
package/dist/longform.js.gz
CHANGED
|
Binary file
|