@funcstache/stache-stream 0.2.2 → 0.2.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.
Files changed (109) hide show
  1. package/.eslintrc.json +30 -0
  2. package/.swcrc +29 -0
  3. package/DEV.md +84 -0
  4. package/README.md +145 -0
  5. package/TASKS.md +13 -0
  6. package/TODO.md +28 -0
  7. package/docs/.nojekyll +1 -0
  8. package/docs/assets/hierarchy.js +1 -0
  9. package/docs/assets/highlight.css +120 -0
  10. package/docs/assets/icons.js +18 -0
  11. package/docs/assets/icons.svg +1 -0
  12. package/docs/assets/main.js +60 -0
  13. package/docs/assets/navigation.js +1 -0
  14. package/docs/assets/search.js +1 -0
  15. package/docs/assets/style.css +1633 -0
  16. package/docs/classes/StacheTransformStream.html +13 -0
  17. package/docs/hierarchy.html +1 -0
  18. package/docs/index.html +73 -0
  19. package/docs/interfaces/Context.html +3 -0
  20. package/docs/interfaces/ContextProvider.html +10 -0
  21. package/docs/interfaces/PartialTagContextLambda.html +11 -0
  22. package/docs/interfaces/PartialTagContextLambdaResult.html +7 -0
  23. package/docs/interfaces/SectionTagCallback.html +12 -0
  24. package/docs/interfaces/SectionTagContextRecord.html +4 -0
  25. package/docs/interfaces/Tag.html +45 -0
  26. package/docs/interfaces/VariableTagContextLambda.html +4 -0
  27. package/docs/interfaces/VariableTagContextRecord.html +3 -0
  28. package/docs/media/StacheStream.ts +79 -0
  29. package/docs/modules.html +1 -0
  30. package/docs/types/ContextTypes.html +3 -0
  31. package/docs/types/JsonType.html +2 -0
  32. package/docs/types/PartialTagContext.html +4 -0
  33. package/docs/types/SectionTagContext.html +4 -0
  34. package/docs/types/TemplateName.html +9 -0
  35. package/docs/types/VariableTagContext.html +4 -0
  36. package/docs/types/VariableTagContextPrimitive.html +3 -0
  37. package/docs-assets/images/context-dotted-found.png +0 -0
  38. package/docs-assets/images/context-dotted-not-found.png +0 -0
  39. package/docs-assets/images/context-not-found.png +0 -0
  40. package/package.json +3 -6
  41. package/project.json +26 -0
  42. package/src/global.d.ts +10 -0
  43. package/src/index.ts +67 -0
  44. package/src/lib/parse/Parse.spec.ts +50 -0
  45. package/src/lib/parse/Parse.ts +92 -0
  46. package/src/lib/parse/README.md +62 -0
  47. package/src/lib/plan_base_v2.md +33 -0
  48. package/src/lib/plan_comment.md +53 -0
  49. package/src/lib/plan_implicit-iterator.md +213 -0
  50. package/src/lib/plan_inverted-sections.md +160 -0
  51. package/src/lib/plan_partials.md +237 -0
  52. package/src/lib/plan_sections.md +167 -0
  53. package/src/lib/plan_stache-stream.md +110 -0
  54. package/src/lib/plan_whitespace.md +98 -0
  55. package/src/lib/queue/Queue.spec.ts +275 -0
  56. package/src/lib/queue/Queue.ts +253 -0
  57. package/src/lib/queue/README.md +110 -0
  58. package/src/lib/stache-stream/README.md +45 -0
  59. package/src/lib/stache-stream/StacheStream.spec.ts +107 -0
  60. package/src/lib/stache-stream/StacheStream.ts +79 -0
  61. package/src/lib/tag/README.md +95 -0
  62. package/src/lib/tag/Tag.spec.ts +212 -0
  63. package/src/lib/tag/Tag.ts +295 -0
  64. package/src/lib/template/README.md +102 -0
  65. package/src/lib/template/Template-comment.spec.ts +76 -0
  66. package/src/lib/template/Template-inverted-section.spec.ts +85 -0
  67. package/src/lib/template/Template-partials.spec.ts +125 -0
  68. package/src/lib/template/Template-section.spec.ts +142 -0
  69. package/src/lib/template/Template.spec.ts +178 -0
  70. package/src/lib/template/Template.ts +614 -0
  71. package/src/lib/test/streams.ts +36 -0
  72. package/src/lib/tokenize/README.md +97 -0
  73. package/src/lib/tokenize/Tokenize.spec.ts +364 -0
  74. package/src/lib/tokenize/Tokenize.ts +374 -0
  75. package/src/lib/{types.d.ts → types.ts} +73 -25
  76. package/tsconfig.json +21 -0
  77. package/tsconfig.lib.json +16 -0
  78. package/tsconfig.spec.json +21 -0
  79. package/typedoc.mjs +15 -0
  80. package/vite.config.ts +27 -0
  81. package/vitest.setup.ts +6 -0
  82. package/src/global.d.js +0 -8
  83. package/src/global.d.js.map +0 -1
  84. package/src/index.d.ts +0 -7
  85. package/src/index.js +0 -24
  86. package/src/index.js.map +0 -1
  87. package/src/lib/parse/Parse.d.ts +0 -14
  88. package/src/lib/parse/Parse.js +0 -79
  89. package/src/lib/parse/Parse.js.map +0 -1
  90. package/src/lib/queue/Queue.d.ts +0 -32
  91. package/src/lib/queue/Queue.js +0 -181
  92. package/src/lib/queue/Queue.js.map +0 -1
  93. package/src/lib/stache-stream/StacheStream.d.ts +0 -22
  94. package/src/lib/stache-stream/StacheStream.js +0 -71
  95. package/src/lib/stache-stream/StacheStream.js.map +0 -1
  96. package/src/lib/tag/Tag.d.ts +0 -33
  97. package/src/lib/tag/Tag.js +0 -231
  98. package/src/lib/tag/Tag.js.map +0 -1
  99. package/src/lib/template/Template.d.ts +0 -18
  100. package/src/lib/template/Template.js +0 -428
  101. package/src/lib/template/Template.js.map +0 -1
  102. package/src/lib/test/streams.d.ts +0 -2
  103. package/src/lib/test/streams.js +0 -39
  104. package/src/lib/test/streams.js.map +0 -1
  105. package/src/lib/tokenize/Tokenize.d.ts +0 -22
  106. package/src/lib/tokenize/Tokenize.js +0 -268
  107. package/src/lib/tokenize/Tokenize.js.map +0 -1
  108. package/src/lib/types.js +0 -33
  109. package/src/lib/types.js.map +0 -1
@@ -1,428 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "Template", {
6
- enumerable: true,
7
- get: function() {
8
- return Template;
9
- }
10
- });
11
- const _web = require("node:stream/web");
12
- const _nodeevents = require("node:events");
13
- const _lodash = require("lodash");
14
- const _logger = require("@funcstache/logger");
15
- const _Parse = require("../parse/Parse");
16
- const _Queue = require("../queue/Queue");
17
- const _Tokenize = require("../tokenize/Tokenize");
18
- let instance = 0;
19
- let Template = class Template extends _nodeevents.EventEmitter {
20
- #logger;
21
- #_parse;
22
- #_queue;
23
- #_tokenize;
24
- /** The context for this template. AKA "hash" in the mustache documentation. */ #contextProvider;
25
- #consumeNextNewline;
26
- #instance;
27
- #lineHasContent;
28
- #pendingWhitespace;
29
- #readable;
30
- #writeToOutput;
31
- constructor({ contextProvider, readable, writeToOutput, ...options }){
32
- super(options);
33
- this.#logger = new _logger.Log({
34
- category: "TML",
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
- level: process.env.LOG_LEVEL || "warn"
37
- });
38
- this.#consumeNextNewline = false;
39
- this.#lineHasContent = false;
40
- this.#pendingWhitespace = "";
41
- instance++;
42
- this.#instance = instance;
43
- if (contextProvider) {
44
- this.#contextProvider = contextProvider;
45
- }
46
- this.#readable = readable;
47
- this.#writeToOutput = (...args)=>{
48
- this.#logger.debug(()=>[
49
- `~~~ ctor.writeToOutput[${this.#instance}]: args=`,
50
- args
51
- ]);
52
- return writeToOutput(...args);
53
- };
54
- }
55
- async getContextValue(tag) {
56
- // this.#logger.debug(() => [
57
- // `~~~ getContextValue[${this.#instance}]: tag='${
58
- // tag.value
59
- // }', this.context='\n%o\n'`,
60
- // this.context,
61
- // ]);
62
- let found = false;
63
- let value;
64
- if (isContext(this.context)) {
65
- ({ found, value } = await this.#findContextForTag(tag, this.context));
66
- }
67
- // this.#logger.debug(
68
- // () =>
69
- // `~~~ getContextValue[${
70
- // this.#instance
71
- // }]: found='${found}', value='${value}'`
72
- // );
73
- if (!found) {
74
- if (this.#contextProvider?.getContextValue) {
75
- value = await this.#contextProvider.getContextValue(tag);
76
- }
77
- }
78
- // this.#logger.debug(() => [
79
- // `~~~ getContextValue[${this.#instance}]: tag='${
80
- // tag.value
81
- // }', value='${value}'`,
82
- // this.context,
83
- // ]);
84
- return value;
85
- }
86
- read() {
87
- this.#parse.read(this.#readable);
88
- return this;
89
- }
90
- get context() {
91
- return this.#contextProvider?.context || {};
92
- }
93
- get #parse() {
94
- if (!this.#_parse) {
95
- this.#_parse = new _Parse.Parse({
96
- onChar: this.#tokenize.push.bind(this.#tokenize)
97
- });
98
- }
99
- return this.#_parse;
100
- }
101
- get #queue() {
102
- if (!this.#_queue) {
103
- this.#_queue = new _Queue.Queue().on("error", (err)=>{
104
- throw err;
105
- }).on("comment", this.#handleComment.bind(this)).on("implicit", this.#handleImplicit.bind(this)).on("inactive", this.#handleInactive.bind(this)).on("inverted", this.#handleInverted.bind(this)).on("partial", this.#handlePartial.bind(this)).on("section", this.#handleSection.bind(this)).on("text", this.#handleText.bind(this)).on("variable", this.#handleVariable.bind(this));
106
- }
107
- return this.#_queue;
108
- }
109
- get #tokenize() {
110
- if (!this.#_tokenize) {
111
- this.#_tokenize = new _Tokenize.Tokenize().on("token", this.#queue.push.bind(this.#queue));
112
- }
113
- return this.#_tokenize;
114
- }
115
- async #applyStandaloneState(bodyEvents) {
116
- const firstBodyEvent = bodyEvents[0];
117
- const isStandalone = !this.#lineHasContent && firstBodyEvent !== undefined && firstBodyEvent.type === "text" && /^(\r\n|\n)/.test(firstBodyEvent.data.toString());
118
- if (isStandalone) {
119
- this.#pendingWhitespace = "";
120
- this.#consumeNextNewline = true;
121
- } else {
122
- await this.#flushPendingWhitespace();
123
- }
124
- return isStandalone;
125
- }
126
- /**
127
- * Gets the context for a tag. This is a complex operation so it's been broken into several
128
- * functions. If context is not found in this template's context an attempt will be made to find
129
- * the context in this Template's parent - if it exists.
130
- * @param tag Find context for this tag.
131
- * @param context The context provided to the template.
132
- */ async #findContextForTag(tag, context) {
133
- // this.#logger.debug(() => [
134
- // `~~~ #findContextForTag[${this.#instance}]: tag='${
135
- // tag.value
136
- // }', this.context='\n%o\n'`,
137
- // this.context,
138
- // ]);
139
- let ctx = context;
140
- let found = false;
141
- let keys = tag.key.split(".");
142
- let value = undefined;
143
- while(keys.length){
144
- try {
145
- ({ found = true, keys, value } = this.#getFromContext(keys, ctx));
146
- // this.#logger.debug(
147
- // () =>
148
- // `~~~ #findContextForTag[${
149
- // this.#instance
150
- // }]: found='${found}', keys='${keys}', value=${value}`
151
- // );
152
- if (!found) {
153
- break;
154
- }
155
- if (keys.length < 1) {
156
- // No keys left, return the value.
157
- found = true;
158
- break;
159
- }
160
- if (typeof value === "function") {
161
- // We got a function for the key and there are more keys, invoke the lambda function and
162
- // expect the result to be an object we can use for the remainder of the keys.
163
- ctx = await value();
164
- continue;
165
- }
166
- ctx = value;
167
- } catch (err) {
168
- this.#logger.error(()=>[
169
- `#findContextForTag[${this.#instance}]: error;\n tag='${tag.value}',\n keys='%0',\n ctx=%1,\n err=%2`,
170
- keys,
171
- ctx,
172
- err
173
- ]);
174
- break;
175
- }
176
- }
177
- // this.#logger.debug(
178
- // () =>
179
- // `~~~ #findContextForTag[${
180
- // this.#instance
181
- // }]: found='${found}', value=${value}`
182
- // );
183
- return {
184
- found,
185
- value: value
186
- };
187
- }
188
- #getFromContext(keys, context) {
189
- if (isContext(context)) {
190
- const key = keys[0];
191
- if (!key) {
192
- throw Error(`No keys were provided.`);
193
- }
194
- if (!(key in context)) {
195
- return {
196
- found: false,
197
- keys
198
- };
199
- }
200
- const value = context[key];
201
- if (isPrimitive(value)) {
202
- if (1 < keys.length) {
203
- throw Error(`key '${key}', returned '${typeof value}' from context however, more keys remain so expected an object.`);
204
- }
205
- return {
206
- value,
207
- keys: []
208
- };
209
- }
210
- return {
211
- value,
212
- keys: keys.slice(1)
213
- };
214
- }
215
- throw new Error(`Expect an object for context, received a '${typeof context}'.`);
216
- }
217
- async #handleComment() {
218
- if (!this.#lineHasContent) {
219
- this.#pendingWhitespace = "";
220
- this.#consumeNextNewline = true;
221
- } else {
222
- await this.#flushPendingWhitespace();
223
- }
224
- }
225
- async #handleInverted(events) {
226
- const bodyEvents = events.slice(1, -1);
227
- const isStandalone = await this.#applyStandaloneState(bodyEvents);
228
- const startEvent = events[0];
229
- if (!startEvent || startEvent.type !== "tag") {
230
- return;
231
- }
232
- const value = await this.getContextValue(startEvent.data);
233
- const isFalsy = value === undefined || value === false || value === "" || Array.isArray(value) && value.length === 0;
234
- if (!isFalsy) {
235
- return;
236
- }
237
- let templateStr = bodyEvents.map((e)=>e.data.toString()).join("");
238
- if (isStandalone) {
239
- templateStr = stripLeadingNewline(templateStr);
240
- }
241
- await this.#renderSectionContent(templateStr, this.context);
242
- }
243
- async #handleImplicit({ data: tag }) {
244
- await this.#flushPendingWhitespace();
245
- const ctx = this.context;
246
- if (isPrimitive(ctx)) {
247
- this.#writeToOutput(tag.raw ? "" + ctx : (0, _lodash.escape)("" + ctx));
248
- }
249
- }
250
- async #handleInactive() {
251
- await this.#flushPendingWhitespace();
252
- this.emit("inactive", undefined);
253
- }
254
- async #handlePartial(event) {
255
- const partialContext = await this.getContextValue(event.data);
256
- if (typeof partialContext !== "function") {
257
- await this.#flushPendingWhitespace();
258
- return;
259
- }
260
- const isStandalone = !this.#lineHasContent;
261
- const indent = isStandalone ? this.#pendingWhitespace : "";
262
- if (isStandalone) {
263
- this.#pendingWhitespace = "";
264
- this.#consumeNextNewline = true;
265
- } else {
266
- await this.#flushPendingWhitespace();
267
- }
268
- const { input, context } = await partialContext(event.data);
269
- const readable = await input();
270
- await this.#renderPartialContent(readable, context, indent);
271
- }
272
- async #handleSection(events) {
273
- const bodyEvents = events.slice(1, -1);
274
- const isStandalone = await this.#applyStandaloneState(bodyEvents);
275
- const startEvent = events[0];
276
- if (!startEvent || startEvent.type !== "tag") {
277
- return;
278
- }
279
- const sectionContext = startEvent.data.key === "." ? this.context : await this.getContextValue(startEvent.data);
280
- if (sectionContext === undefined || sectionContext === false || sectionContext === "" || Array.isArray(sectionContext) && sectionContext.length === 0) {
281
- return;
282
- }
283
- let templateStr = bodyEvents.map((e)=>e.data.toString()).join("");
284
- if (isStandalone) {
285
- templateStr = stripLeadingNewline(templateStr);
286
- }
287
- if (isSectionLambda(sectionContext)) {
288
- // TODO: make `SectionTagCallback` async
289
- await this.#writeToOutput(sectionContext(templateStr));
290
- return;
291
- }
292
- const items = Array.isArray(sectionContext) ? sectionContext : [
293
- sectionContext
294
- ];
295
- for (const item of items){
296
- await this.#renderSectionContent(templateStr, item);
297
- }
298
- }
299
- async #renderSectionContent(templateStr, context) {
300
- return new Promise((resolve)=>{
301
- const childContextProvider = {
302
- context,
303
- getContextValue: (tag)=>this.getContextValue(tag)
304
- };
305
- new Template({
306
- contextProvider: childContextProvider,
307
- readable: stringToReadableStream(templateStr),
308
- writeToOutput: this.#writeToOutput
309
- }).on("inactive", ()=>resolve()).read();
310
- });
311
- }
312
- async #flushPendingWhitespace() {
313
- if (this.#pendingWhitespace) {
314
- await this.#writeToOutput(this.#pendingWhitespace);
315
- this.#pendingWhitespace = "";
316
- }
317
- }
318
- async #handleText(event) {
319
- let text = event.data;
320
- // After a standalone partial the trailing newline belongs to the partial tag, not the output.
321
- if (this.#consumeNextNewline) {
322
- if (text.startsWith("\r\n")) {
323
- text = text.slice(2);
324
- } else if (text.startsWith("\n")) {
325
- text = text.slice(1);
326
- }
327
- this.#consumeNextNewline = false;
328
- if (!text) {
329
- return;
330
- }
331
- }
332
- const lastNewlineEnd = lastNewlineIndex(text);
333
- if (lastNewlineEnd !== -1) {
334
- // Flush everything up to and including the last newline, then reset line state.
335
- await this.#writeToOutput(this.#pendingWhitespace + text.slice(0, lastNewlineEnd));
336
- this.#pendingWhitespace = "";
337
- this.#lineHasContent = false;
338
- text = text.slice(lastNewlineEnd);
339
- if (!text) {
340
- return;
341
- }
342
- }
343
- // text contains no newlines — process as current-line fragment.
344
- if (isHorizontalWhitespace(text)) {
345
- this.#pendingWhitespace += text;
346
- } else {
347
- await this.#writeToOutput(this.#pendingWhitespace + text);
348
- this.#pendingWhitespace = "";
349
- this.#lineHasContent = true;
350
- }
351
- }
352
- async #renderPartialContent(readable, context, indent) {
353
- return new Promise((resolve)=>{
354
- const childContextProvider = {
355
- context: context ?? this.context,
356
- getContextValue: (tag)=>this.getContextValue(tag)
357
- };
358
- const indentingWriter = indent ? makeIndentingWriter(this.#writeToOutput, indent) : this.#writeToOutput;
359
- new Template({
360
- contextProvider: childContextProvider,
361
- readable,
362
- writeToOutput: indentingWriter
363
- }).on("inactive", ()=>resolve()).read();
364
- });
365
- }
366
- async #handleVariable({ data: tag }) {
367
- await this.#flushPendingWhitespace();
368
- // this.#logger.debug(
369
- // () => `~~~ #handleVariable[${this.#instance}]: tag=${tag.toString()}`
370
- // );
371
- let tagVariableContext = await this.getContextValue(tag);
372
- // this.#logger.debug(() => [
373
- // `~~~ #handleVariable[${this.#instance}]: tagVariableContext=`,
374
- // tagVariableContext,
375
- // ]);
376
- // If the variable context value is a function then invoke it to get the value.
377
- if (typeof tagVariableContext === "function") {
378
- tagVariableContext = await tagVariableContext();
379
- }
380
- if (isPrimitive(tagVariableContext)) {
381
- this.#writeToOutput(tag.raw ? "" + tagVariableContext : (0, _lodash.escape)("" + tagVariableContext));
382
- } else {
383
- this.#logger.log(()=>`#handleVariable[${this.#instance}]: variable tag '${tag.valueOption}' returns context value '${tagVariableContext}'`);
384
- }
385
- return;
386
- }
387
- };
388
- function isContext(obj) {
389
- return !!(obj && typeof obj !== "boolean" && typeof obj !== "number" && typeof obj !== "string" && typeof obj !== "function" && !Array.isArray(obj));
390
- }
391
- function isHorizontalWhitespace(text) {
392
- return /^[ \t]*$/.test(text);
393
- }
394
- function isPrimitive(obj) {
395
- return typeof obj === "boolean" || typeof obj === "number" || typeof obj === "string";
396
- }
397
- function isSectionLambda(value) {
398
- return !!value && typeof value === "function";
399
- }
400
- /** Returns the index of the first character after the last `\n` (or `\r\n`), or -1 if none. */ function lastNewlineIndex(text) {
401
- const index = text.lastIndexOf("\n");
402
- if (index === -1) {
403
- return -1;
404
- }
405
- return index + 1;
406
- }
407
- function makeIndentingWriter(writeToOutput, indent) {
408
- let atLineStart = true;
409
- return async (text)=>{
410
- const indented = (atLineStart ? indent : "") + text.replace(/\n(?!\n|$)/g, "\n" + indent);
411
- atLineStart = text.endsWith("\n");
412
- return writeToOutput(indented);
413
- };
414
- }
415
- function stripLeadingNewline(str) {
416
- const index = str.startsWith("\r\n") ? 2 : str.startsWith("\n") ? 1 : 0;
417
- return !index ? str : str.slice(index);
418
- }
419
- function stringToReadableStream(str) {
420
- return new _web.ReadableStream({
421
- start (controller) {
422
- controller.enqueue(str);
423
- controller.close();
424
- }
425
- });
426
- }
427
-
428
- //# sourceMappingURL=Template.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../libs/stache-stream/src/lib/template/Template.ts"],"sourcesContent":["import { ReadableStream } from \"node:stream/web\";\nimport { EventEmitter } from \"node:events\";\nimport { escape } from \"lodash\";\nimport { Log } from \"@funcstache/logger\";\nimport type {\n Context,\n ContextProvider,\n ContextTypes,\n PartialTagContext,\n SectionTagCallback,\n Tag as TagType,\n VariableTagContext,\n VariableTagContextLambda,\n WriteToOutput,\n} from \"../types\";\nimport { Parse } from \"../parse/Parse\";\nimport { Queue, type TokenizeAllEvent } from \"../queue/Queue\";\nimport {\n Tokenize,\n type TokenizeTagEvent,\n type TokenizeTextEvent,\n} from \"../tokenize/Tokenize\";\n\nlet instance = 0;\n\nexport class Template\n extends EventEmitter<{ inactive: [undefined] }>\n implements ContextProvider\n{\n #logger = new Log({\n category: \"TML\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n level: (process.env as any).LOG_LEVEL || \"warn\",\n });\n\n #_parse: Parse | undefined;\n #_queue: Queue | undefined;\n #_tokenize: Tokenize | undefined;\n /** The context for this template. AKA \"hash\" in the mustache documentation. */\n #contextProvider: ContextProvider | undefined;\n #consumeNextNewline = false;\n #instance: number;\n #lineHasContent = false;\n #pendingWhitespace = \"\";\n #readable: ReadableStream<string>;\n #writeToOutput: WriteToOutput;\n\n constructor({\n contextProvider,\n readable,\n writeToOutput,\n ...options\n }: ConstructorParameters<\n typeof EventEmitter<{ inactive: [undefined] }>\n >[0] & {\n contextProvider?: ContextProvider;\n readable: ReadableStream<string>;\n writeToOutput: WriteToOutput;\n }) {\n super(options);\n\n instance++;\n this.#instance = instance;\n\n if (contextProvider) {\n this.#contextProvider = contextProvider;\n }\n\n this.#readable = readable;\n this.#writeToOutput = (...args: Parameters<WriteToOutput>) => {\n this.#logger.debug(() => [\n `~~~ ctor.writeToOutput[${this.#instance}]: args=`,\n args,\n ]);\n return writeToOutput(...args);\n };\n }\n\n async getContextValue<CTX extends ContextTypes>(\n tag: TagType\n ): Promise<CTX | undefined> {\n // this.#logger.debug(() => [\n // `~~~ getContextValue[${this.#instance}]: tag='${\n // tag.value\n // }', this.context='\\n%o\\n'`,\n // this.context,\n // ]);\n\n let found = false;\n let value: CTX | undefined;\n if (isContext(this.context)) {\n ({ found, value } = await this.#findContextForTag<CTX>(\n tag,\n this.context\n ));\n }\n\n // this.#logger.debug(\n // () =>\n // `~~~ getContextValue[${\n // this.#instance\n // }]: found='${found}', value='${value}'`\n // );\n\n if (!found) {\n if (this.#contextProvider?.getContextValue) {\n value = await this.#contextProvider.getContextValue(tag);\n }\n }\n\n // this.#logger.debug(() => [\n // `~~~ getContextValue[${this.#instance}]: tag='${\n // tag.value\n // }', value='${value}'`,\n // this.context,\n // ]);\n\n return value;\n }\n\n read(): Template {\n this.#parse.read(this.#readable);\n return this;\n }\n\n get context(): ContextTypes {\n return this.#contextProvider?.context || {};\n }\n\n get #parse(): Parse {\n if (!this.#_parse) {\n this.#_parse = new Parse({\n onChar: this.#tokenize.push.bind(this.#tokenize),\n });\n }\n\n return this.#_parse;\n }\n\n get #queue(): Queue {\n if (!this.#_queue) {\n this.#_queue = new Queue()\n .on(\"error\", (err) => {\n throw err;\n })\n .on(\"comment\", this.#handleComment.bind(this))\n .on(\"implicit\", this.#handleImplicit.bind(this))\n .on(\"inactive\", this.#handleInactive.bind(this))\n .on(\"inverted\", this.#handleInverted.bind(this))\n .on(\"partial\", this.#handlePartial.bind(this))\n .on(\"section\", this.#handleSection.bind(this))\n .on(\"text\", this.#handleText.bind(this))\n .on(\"variable\", this.#handleVariable.bind(this));\n }\n\n return this.#_queue;\n }\n\n get #tokenize(): Tokenize {\n if (!this.#_tokenize) {\n this.#_tokenize = new Tokenize().on(\n \"token\",\n this.#queue.push.bind(this.#queue)\n );\n }\n\n return this.#_tokenize;\n }\n\n async #applyStandaloneState(\n bodyEvents: TokenizeAllEvent[]\n ): Promise<boolean> {\n const firstBodyEvent = bodyEvents[0];\n const isStandalone =\n !this.#lineHasContent &&\n firstBodyEvent !== undefined &&\n firstBodyEvent.type === \"text\" &&\n /^(\\r\\n|\\n)/.test(firstBodyEvent.data.toString());\n\n if (isStandalone) {\n this.#pendingWhitespace = \"\";\n this.#consumeNextNewline = true;\n } else {\n await this.#flushPendingWhitespace();\n }\n\n return isStandalone;\n }\n\n /**\n * Gets the context for a tag. This is a complex operation so it's been broken into several\n * functions. If context is not found in this template's context an attempt will be made to find\n * the context in this Template's parent - if it exists.\n * @param tag Find context for this tag.\n * @param context The context provided to the template.\n */\n async #findContextForTag<CTX extends ContextTypes>(\n tag: TagType,\n context: Context\n ): Promise<{ found: boolean; value: CTX | undefined }> {\n // this.#logger.debug(() => [\n // `~~~ #findContextForTag[${this.#instance}]: tag='${\n // tag.value\n // }', this.context='\\n%o\\n'`,\n // this.context,\n // ]);\n\n let ctx = context;\n let found = false;\n let keys = tag.key.split(\".\");\n let value: Context | ContextTypes | undefined = undefined;\n while (keys.length) {\n try {\n ({ found = true, keys, value } = this.#getFromContext(keys, ctx));\n\n // this.#logger.debug(\n // () =>\n // `~~~ #findContextForTag[${\n // this.#instance\n // }]: found='${found}', keys='${keys}', value=${value}`\n // );\n\n if (!found) {\n break;\n }\n\n if (keys.length < 1) {\n // No keys left, return the value.\n found = true;\n break;\n }\n\n if (typeof value === \"function\") {\n // We got a function for the key and there are more keys, invoke the lambda function and\n // expect the result to be an object we can use for the remainder of the keys.\n ctx = (await (value as VariableTagContextLambda)()) as Context;\n continue;\n }\n\n ctx = value as Context;\n } catch (err) {\n this.#logger.error(() => [\n `#findContextForTag[${this.#instance}]: error;\\n tag='${\n tag.value\n }',\\n keys='%0',\\n ctx=%1,\\n err=%2`,\n keys,\n ctx,\n err,\n ]);\n break;\n }\n }\n\n // this.#logger.debug(\n // () =>\n // `~~~ #findContextForTag[${\n // this.#instance\n // }]: found='${found}', value=${value}`\n // );\n\n return { found, value: value as CTX };\n }\n\n #getFromContext(keys: string[], context: Context | undefined) {\n if (isContext(context)) {\n const key = keys[0];\n if (!key) {\n throw Error(`No keys were provided.`);\n }\n\n if (!(key in context)) {\n return { found: false, keys };\n }\n\n const value = context[key];\n\n if (isPrimitive(value)) {\n if (1 < keys.length) {\n throw Error(\n `key '${key}', returned '${typeof value}' from context however, more keys remain so expected an object.`\n );\n }\n\n return { value, keys: [] };\n }\n\n return { value, keys: keys.slice(1) };\n }\n\n throw new Error(\n `Expect an object for context, received a '${typeof context}'.`\n );\n }\n\n async #handleComment(): Promise<void> {\n if (!this.#lineHasContent) {\n this.#pendingWhitespace = \"\";\n this.#consumeNextNewline = true;\n } else {\n await this.#flushPendingWhitespace();\n }\n }\n\n async #handleInverted(events: TokenizeAllEvent[]): Promise<void> {\n const bodyEvents = events.slice(1, -1);\n const isStandalone = await this.#applyStandaloneState(bodyEvents);\n\n const startEvent = events[0];\n if (!startEvent || startEvent.type !== \"tag\") {\n return;\n }\n\n const value = await this.getContextValue(startEvent.data);\n\n const isFalsy =\n value === undefined ||\n value === false ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0);\n\n if (!isFalsy) {\n return;\n }\n\n let templateStr = bodyEvents.map((e) => e.data.toString()).join(\"\");\n if (isStandalone) {\n templateStr = stripLeadingNewline(templateStr);\n }\n\n await this.#renderSectionContent(templateStr, this.context);\n }\n\n async #handleImplicit({ data: tag }: TokenizeTagEvent): Promise<void> {\n await this.#flushPendingWhitespace();\n const ctx = this.context;\n\n if (isPrimitive(ctx)) {\n this.#writeToOutput(tag.raw ? \"\" + ctx : escape(\"\" + ctx));\n }\n }\n\n async #handleInactive(): Promise<void> {\n await this.#flushPendingWhitespace();\n this.emit(\"inactive\", undefined);\n }\n\n async #handlePartial(event: TokenizeTagEvent): Promise<void> {\n const partialContext = await this.getContextValue<PartialTagContext>(\n event.data\n );\n if (typeof partialContext !== \"function\") {\n await this.#flushPendingWhitespace();\n return;\n }\n\n const isStandalone = !this.#lineHasContent;\n const indent = isStandalone ? this.#pendingWhitespace : \"\";\n\n if (isStandalone) {\n this.#pendingWhitespace = \"\";\n this.#consumeNextNewline = true;\n } else {\n await this.#flushPendingWhitespace();\n }\n\n const { input, context } = await partialContext(event.data);\n const readable = await input();\n\n await this.#renderPartialContent(\n readable as ReadableStream<string>,\n context,\n indent\n );\n }\n\n async #handleSection(events: TokenizeAllEvent[]): Promise<void> {\n const bodyEvents = events.slice(1, -1);\n const isStandalone = await this.#applyStandaloneState(bodyEvents);\n\n const startEvent = events[0];\n if (!startEvent || startEvent.type !== \"tag\") {\n return;\n }\n\n const sectionContext =\n startEvent.data.key === \".\"\n ? this.context\n : await this.getContextValue(startEvent.data);\n\n if (\n sectionContext === undefined ||\n sectionContext === false ||\n sectionContext === \"\" ||\n (Array.isArray(sectionContext) && sectionContext.length === 0)\n ) {\n return;\n }\n\n let templateStr = bodyEvents.map((e) => e.data.toString()).join(\"\");\n if (isStandalone) {\n templateStr = stripLeadingNewline(templateStr);\n }\n\n if (isSectionLambda(sectionContext)) {\n // TODO: make `SectionTagCallback` async\n await this.#writeToOutput(sectionContext(templateStr));\n return;\n }\n\n const items: ContextTypes[] = Array.isArray(sectionContext)\n ? sectionContext\n : [sectionContext];\n\n for (const item of items) {\n await this.#renderSectionContent(templateStr, item);\n }\n }\n\n async #renderSectionContent(\n templateStr: string,\n context: ContextTypes\n ): Promise<void> {\n return new Promise<void>((resolve) => {\n const childContextProvider: ContextProvider = {\n context,\n getContextValue: <CTX extends ContextTypes>(\n tag: TagType\n ): Promise<CTX | undefined> => this.getContextValue<CTX>(tag),\n };\n\n new Template({\n contextProvider: childContextProvider,\n readable: stringToReadableStream(templateStr),\n writeToOutput: this.#writeToOutput,\n })\n .on(\"inactive\", () => resolve())\n .read();\n });\n }\n\n async #flushPendingWhitespace(): Promise<void> {\n if (this.#pendingWhitespace) {\n await this.#writeToOutput(this.#pendingWhitespace);\n this.#pendingWhitespace = \"\";\n }\n }\n\n async #handleText(event: TokenizeTextEvent): Promise<void> {\n let text = event.data;\n // After a standalone partial the trailing newline belongs to the partial tag, not the output.\n if (this.#consumeNextNewline) {\n if (text.startsWith(\"\\r\\n\")) {\n text = text.slice(2);\n } else if (text.startsWith(\"\\n\")) {\n text = text.slice(1);\n }\n this.#consumeNextNewline = false;\n if (!text) {\n return;\n }\n }\n\n const lastNewlineEnd = lastNewlineIndex(text);\n if (lastNewlineEnd !== -1) {\n // Flush everything up to and including the last newline, then reset line state.\n await this.#writeToOutput(\n this.#pendingWhitespace + text.slice(0, lastNewlineEnd)\n );\n this.#pendingWhitespace = \"\";\n this.#lineHasContent = false;\n text = text.slice(lastNewlineEnd);\n if (!text) {\n return;\n }\n }\n\n // text contains no newlines — process as current-line fragment.\n if (isHorizontalWhitespace(text)) {\n this.#pendingWhitespace += text;\n } else {\n await this.#writeToOutput(this.#pendingWhitespace + text);\n this.#pendingWhitespace = \"\";\n this.#lineHasContent = true;\n }\n }\n\n async #renderPartialContent(\n readable: ReadableStream<string>,\n context: ContextTypes | undefined,\n indent: string\n ): Promise<void> {\n return new Promise<void>((resolve) => {\n const childContextProvider: ContextProvider = {\n context: context ?? this.context,\n getContextValue: <CTX extends ContextTypes>(\n tag: TagType\n ): Promise<CTX | undefined> => this.getContextValue<CTX>(tag),\n };\n\n const indentingWriter: WriteToOutput = indent\n ? makeIndentingWriter(this.#writeToOutput, indent)\n : this.#writeToOutput;\n\n new Template({\n contextProvider: childContextProvider,\n readable,\n writeToOutput: indentingWriter,\n })\n .on(\"inactive\", () => resolve())\n .read();\n });\n }\n\n async #handleVariable({ data: tag }: TokenizeTagEvent): Promise<void> {\n await this.#flushPendingWhitespace();\n // this.#logger.debug(\n // () => `~~~ #handleVariable[${this.#instance}]: tag=${tag.toString()}`\n // );\n\n let tagVariableContext = await this.getContextValue<VariableTagContext>(\n tag\n );\n\n // this.#logger.debug(() => [\n // `~~~ #handleVariable[${this.#instance}]: tagVariableContext=`,\n // tagVariableContext,\n // ]);\n\n // If the variable context value is a function then invoke it to get the value.\n if (typeof tagVariableContext === \"function\") {\n tagVariableContext = await (\n tagVariableContext as VariableTagContextLambda\n )();\n }\n\n if (isPrimitive(tagVariableContext)) {\n this.#writeToOutput(\n tag.raw ? \"\" + tagVariableContext : escape(\"\" + tagVariableContext)\n );\n } else {\n this.#logger.log(\n () =>\n `#handleVariable[${this.#instance}]: variable tag '${\n tag.valueOption\n }' returns context value '${tagVariableContext}'`\n );\n }\n\n return;\n }\n}\n\nfunction isContext(obj: unknown): obj is Context {\n return !!(\n obj &&\n typeof obj !== \"boolean\" &&\n typeof obj !== \"number\" &&\n typeof obj !== \"string\" &&\n typeof obj !== \"function\" &&\n !Array.isArray(obj)\n );\n}\n\nfunction isHorizontalWhitespace(text: string): boolean {\n return /^[ \\t]*$/.test(text);\n}\n\nfunction isPrimitive(obj: unknown): obj is boolean | number | string {\n return (\n typeof obj === \"boolean\" ||\n typeof obj === \"number\" ||\n typeof obj === \"string\"\n );\n}\n\nfunction isSectionLambda(value: ContextTypes): value is SectionTagCallback {\n return !!value && typeof value === \"function\";\n}\n\n/** Returns the index of the first character after the last `\\n` (or `\\r\\n`), or -1 if none. */\nfunction lastNewlineIndex(text: string): number {\n const index = text.lastIndexOf(\"\\n\");\n if (index === -1) {\n return -1;\n }\n return index + 1;\n}\n\nfunction makeIndentingWriter(\n writeToOutput: WriteToOutput,\n indent: string\n): WriteToOutput {\n let atLineStart = true;\n return async (text: string) => {\n const indented =\n (atLineStart ? indent : \"\") + text.replace(/\\n(?!\\n|$)/g, \"\\n\" + indent);\n atLineStart = text.endsWith(\"\\n\");\n return writeToOutput(indented);\n };\n}\n\nfunction stripLeadingNewline(str: string): string {\n const index = str.startsWith(\"\\r\\n\") ? 2 : str.startsWith(\"\\n\") ? 1 : 0;\n return !index ? str : str.slice(index);\n}\n\nfunction stringToReadableStream(str: string): ReadableStream<string> {\n return new ReadableStream<string>({\n start(controller) {\n controller.enqueue(str);\n controller.close();\n },\n });\n}\n"],"names":["Template","instance","EventEmitter","logger","_parse","_queue","_tokenize","contextProvider","consumeNextNewline","lineHasContent","pendingWhitespace","readable","writeToOutput","constructor","options","Log","category","level","process","env","LOG_LEVEL","args","debug","getContextValue","tag","found","value","isContext","context","findContextForTag","read","parse","Parse","onChar","tokenize","push","bind","queue","Queue","on","err","handleComment","handleImplicit","handleInactive","handleInverted","handlePartial","handleSection","handleText","handleVariable","Tokenize","applyStandaloneState","bodyEvents","firstBodyEvent","isStandalone","undefined","type","test","data","toString","flushPendingWhitespace","ctx","keys","key","split","length","getFromContext","error","Error","isPrimitive","slice","events","startEvent","isFalsy","Array","isArray","templateStr","map","e","join","stripLeadingNewline","renderSectionContent","raw","escape","emit","event","partialContext","indent","input","renderPartialContent","sectionContext","isSectionLambda","items","item","Promise","resolve","childContextProvider","stringToReadableStream","text","startsWith","lastNewlineEnd","lastNewlineIndex","isHorizontalWhitespace","indentingWriter","makeIndentingWriter","tagVariableContext","log","valueOption","obj","index","lastIndexOf","atLineStart","indented","replace","endsWith","str","ReadableStream","start","controller","enqueue","close"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { ReadableStream } from "node:stream/web";
2
- export declare function createReadableStream(source: string, charCount?: number, pause?: number): ReadableStream<AllowSharedBufferSource>;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "createReadableStream", {
6
- enumerable: true,
7
- get: function() {
8
- return createReadableStream;
9
- }
10
- });
11
- const _web = require("node:stream/web");
12
- function createReadableStream(source, charCount = -1, pause = 0) {
13
- const encoder = new TextEncoder();
14
- let sourceIndex = 0;
15
- let pullCount = 0;
16
- return new _web.ReadableStream({
17
- pull: async (controller)=>{
18
- pullCount++;
19
- if (source.length <= sourceIndex) {
20
- controller.close();
21
- return;
22
- }
23
- for(let i = 0; i < (0 < charCount ? charCount : source.length); i++){
24
- if (sourceIndex < source.length) {
25
- controller.enqueue(encoder.encode(source.charAt(sourceIndex)));
26
- } else {
27
- controller.close();
28
- return;
29
- }
30
- sourceIndex++;
31
- if (0 < pause) {
32
- await new Promise((resolve)=>setTimeout(resolve, pause));
33
- }
34
- }
35
- }
36
- });
37
- }
38
-
39
- //# sourceMappingURL=streams.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../../../../libs/stache-stream/src/lib/test/streams.ts"],"sourcesContent":["import { ReadableStream } from \"node:stream/web\";\n\nexport function createReadableStream(\n source: string,\n charCount = -1,\n pause = 0\n) {\n const encoder = new TextEncoder();\n let sourceIndex = 0;\n let pullCount = 0;\n\n return new ReadableStream<AllowSharedBufferSource>({\n pull: async (controller) => {\n pullCount++;\n if (source.length <= sourceIndex) {\n controller.close();\n return;\n }\n\n for (let i = 0; i < (0 < charCount ? charCount : source.length); i++) {\n if (sourceIndex < source.length) {\n controller.enqueue(encoder.encode(source.charAt(sourceIndex)));\n } else {\n controller.close();\n return;\n }\n\n sourceIndex++;\n\n if (0 < pause) {\n await new Promise<void>((resolve) => setTimeout(resolve, pause));\n }\n }\n },\n });\n}\n"],"names":["createReadableStream","source","charCount","pause","encoder","TextEncoder","sourceIndex","pullCount","ReadableStream","pull","controller","length","close","i","enqueue","encode","charAt","Promise","resolve","setTimeout"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAEgBA;;;eAAAA;;;qBAFe;AAExB,SAASA,qBACdC,MAAc,EACdC,YAAY,CAAC,CAAC,EACdC,QAAQ,CAAC;IAET,MAAMC,UAAU,IAAIC;IACpB,IAAIC,cAAc;IAClB,IAAIC,YAAY;IAEhB,OAAO,IAAIC,mBAAc,CAA0B;QACjDC,MAAM,OAAOC;YACXH;YACA,IAAIN,OAAOU,MAAM,IAAIL,aAAa;gBAChCI,WAAWE,KAAK;gBAChB;YACF;YAEA,IAAK,IAAIC,IAAI,GAAGA,IAAK,CAAA,IAAIX,YAAYA,YAAYD,OAAOU,MAAM,AAAD,GAAIE,IAAK;gBACpE,IAAIP,cAAcL,OAAOU,MAAM,EAAE;oBAC/BD,WAAWI,OAAO,CAACV,QAAQW,MAAM,CAACd,OAAOe,MAAM,CAACV;gBAClD,OAAO;oBACLI,WAAWE,KAAK;oBAChB;gBACF;gBAEAN;gBAEA,IAAI,IAAIH,OAAO;oBACb,MAAM,IAAIc,QAAc,CAACC,UAAYC,WAAWD,SAASf;gBAC3D;YACF;QACF;IACF;AACF"}
@@ -1,22 +0,0 @@
1
- import { EventEmitter } from "node:events";
2
- import { Tag } from "../tag/Tag";
3
- export declare class Tokenize extends EventEmitter<TokenizeEventMap> {
4
- #private;
5
- push(char: string | null): Promise<void>;
6
- }
7
- interface TokenizeEvent {
8
- uid: number;
9
- }
10
- export interface TokenizeTagEvent extends TokenizeEvent {
11
- data: Tag;
12
- type: "tag";
13
- }
14
- export interface TokenizeTextEvent extends TokenizeEvent {
15
- data: string;
16
- type: "text";
17
- }
18
- export type TokenizeEventMap = {
19
- token: [TokenizeTagEvent | TokenizeTextEvent | null];
20
- };
21
- export type StateNames = "inTagValue" | "outsideTag" | "tagExitingMaybe" | "tagEnteringMaybe";
22
- export {};