@weborigami/origami 0.0.35

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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/ReadMe.md +3 -0
  3. package/exports/PathTransform.d.ts +5 -0
  4. package/exports/PathTransform.js +18 -0
  5. package/exports/buildExports.js +109 -0
  6. package/exports/exports.js +121 -0
  7. package/index.ts +25 -0
  8. package/package.json +40 -0
  9. package/src/builtins/!.js +21 -0
  10. package/src/builtins/@apply.js +6 -0
  11. package/src/builtins/@arrows.js +34 -0
  12. package/src/builtins/@builtins.js +18 -0
  13. package/src/builtins/@cache.js +36 -0
  14. package/src/builtins/@config.js +25 -0
  15. package/src/builtins/@copy.js +71 -0
  16. package/src/builtins/@crawl.js +507 -0
  17. package/src/builtins/@debug.js +89 -0
  18. package/src/builtins/@document.js +18 -0
  19. package/src/builtins/@equals.js +6 -0
  20. package/src/builtins/@explore.js +68 -0
  21. package/src/builtins/@false.js +1 -0
  22. package/src/builtins/@files.js +22 -0
  23. package/src/builtins/@filter.js +23 -0
  24. package/src/builtins/@globs.js +23 -0
  25. package/src/builtins/@help.js +49 -0
  26. package/src/builtins/@http.js +19 -0
  27. package/src/builtins/@https.js +19 -0
  28. package/src/builtins/@if.js +27 -0
  29. package/src/builtins/@image/format.js +5 -0
  30. package/src/builtins/@image/resize.js +5 -0
  31. package/src/builtins/@index.js +72 -0
  32. package/src/builtins/@inherited.js +17 -0
  33. package/src/builtins/@inline.js +29 -0
  34. package/src/builtins/@invoke.js +30 -0
  35. package/src/builtins/@js.js +33 -0
  36. package/src/builtins/@json.js +22 -0
  37. package/src/builtins/@loaders/css.js +4 -0
  38. package/src/builtins/@loaders/htm.js +4 -0
  39. package/src/builtins/@loaders/html.js +4 -0
  40. package/src/builtins/@loaders/js.js +14 -0
  41. package/src/builtins/@loaders/json.js +8 -0
  42. package/src/builtins/@loaders/md.js +4 -0
  43. package/src/builtins/@loaders/mjs.js +4 -0
  44. package/src/builtins/@loaders/ori.js +21 -0
  45. package/src/builtins/@loaders/orit.js +48 -0
  46. package/src/builtins/@loaders/txt.js +33 -0
  47. package/src/builtins/@loaders/xhtml.js +4 -0
  48. package/src/builtins/@loaders/yaml.js +18 -0
  49. package/src/builtins/@loaders/yml.js +4 -0
  50. package/src/builtins/@map.js +182 -0
  51. package/src/builtins/@match.js +92 -0
  52. package/src/builtins/@mdHtml.js +45 -0
  53. package/src/builtins/@new.js +6 -0
  54. package/src/builtins/@node.js +15 -0
  55. package/src/builtins/@not.js +6 -0
  56. package/src/builtins/@or.js +6 -0
  57. package/src/builtins/@ori.js +83 -0
  58. package/src/builtins/@pack.js +13 -0
  59. package/src/builtins/@parse/json.js +7 -0
  60. package/src/builtins/@parse/yaml.js +9 -0
  61. package/src/builtins/@project.js +71 -0
  62. package/src/builtins/@repeat.js +8 -0
  63. package/src/builtins/@rss.js +49 -0
  64. package/src/builtins/@scope/extend.js +22 -0
  65. package/src/builtins/@scope/get.js +25 -0
  66. package/src/builtins/@scope/invoke.js +22 -0
  67. package/src/builtins/@scope/set.js +25 -0
  68. package/src/builtins/@serve.js +74 -0
  69. package/src/builtins/@shell.js +16 -0
  70. package/src/builtins/@stdin.js +26 -0
  71. package/src/builtins/@svg.js +42 -0
  72. package/src/builtins/@tree/concat.js +21 -0
  73. package/src/builtins/@tree/count.js +24 -0
  74. package/src/builtins/@tree/defineds.js +37 -0
  75. package/src/builtins/@tree/dot.js +201 -0
  76. package/src/builtins/@tree/exceptions.js +50 -0
  77. package/src/builtins/@tree/first.js +28 -0
  78. package/src/builtins/@tree/flowSvg.js +55 -0
  79. package/src/builtins/@tree/fn.js +34 -0
  80. package/src/builtins/@tree/from.js +27 -0
  81. package/src/builtins/@tree/fromJson.js +6 -0
  82. package/src/builtins/@tree/fromYaml.js +24 -0
  83. package/src/builtins/@tree/groupBy.js +39 -0
  84. package/src/builtins/@tree/inners.js +44 -0
  85. package/src/builtins/@tree/isAsyncTree.js +17 -0
  86. package/src/builtins/@tree/keys.js +24 -0
  87. package/src/builtins/@tree/keysJson.js +44 -0
  88. package/src/builtins/@tree/map.d.ts +19 -0
  89. package/src/builtins/@tree/merge.js +47 -0
  90. package/src/builtins/@tree/mergeDeep.js +44 -0
  91. package/src/builtins/@tree/nextKey.js +29 -0
  92. package/src/builtins/@tree/parent.js +24 -0
  93. package/src/builtins/@tree/paths.js +35 -0
  94. package/src/builtins/@tree/plain.js +22 -0
  95. package/src/builtins/@tree/previousKey.js +29 -0
  96. package/src/builtins/@tree/reverse.js +51 -0
  97. package/src/builtins/@tree/setDeep.js +45 -0
  98. package/src/builtins/@tree/shuffle.js +31 -0
  99. package/src/builtins/@tree/sitemap.js +59 -0
  100. package/src/builtins/@tree/sort.js +25 -0
  101. package/src/builtins/@tree/sortBy.js +40 -0
  102. package/src/builtins/@tree/static.js +51 -0
  103. package/src/builtins/@tree/table.js +74 -0
  104. package/src/builtins/@tree/take.js +40 -0
  105. package/src/builtins/@tree/values.js +23 -0
  106. package/src/builtins/@tree/valuesDeep.js +23 -0
  107. package/src/builtins/@treeHttp.js +19 -0
  108. package/src/builtins/@treeHttps.js +19 -0
  109. package/src/builtins/@true.js +1 -0
  110. package/src/builtins/@unpack.js +13 -0
  111. package/src/builtins/@watch.js +108 -0
  112. package/src/builtins/@with.js +22 -0
  113. package/src/builtins/@yaml.js +23 -0
  114. package/src/builtins/~.js +9 -0
  115. package/src/cli/cli.js +86 -0
  116. package/src/cli/defaultModuleExport.js +16 -0
  117. package/src/cli/showUsage.js +86 -0
  118. package/src/common/CommandModulesTransform.d.ts +5 -0
  119. package/src/common/CommandModulesTransform.js +37 -0
  120. package/src/common/ConstantTree.js +17 -0
  121. package/src/common/ExplorableSiteTransform.d.ts +5 -0
  122. package/src/common/ExplorableSiteTransform.js +77 -0
  123. package/src/common/FilterTree.js +60 -0
  124. package/src/common/GlobTree.js +67 -0
  125. package/src/common/ShuffleTransform.js +29 -0
  126. package/src/common/TextDocument.js +57 -0
  127. package/src/common/addValueKeyToScope.js +30 -0
  128. package/src/common/arrowFunctionsMap.js +35 -0
  129. package/src/common/processUnpackedContent.js +39 -0
  130. package/src/common/serialize.d.ts +8 -0
  131. package/src/common/serialize.js +138 -0
  132. package/src/common/utilities.d.ts +7 -0
  133. package/src/common/utilities.js +132 -0
  134. package/src/misc/OriCommandTransform.d.ts +5 -0
  135. package/src/misc/OriCommandTransform.js +54 -0
  136. package/src/misc/assertScopeIsDefined.js +7 -0
  137. package/src/misc/explore.orit +241 -0
  138. package/src/misc/yamlOrigamiTag.js +17 -0
  139. package/src/server/mediaTypes.js +97 -0
  140. package/src/server/server.js +258 -0
@@ -0,0 +1,22 @@
1
+ import { OrigamiFiles, Scope } from "@weborigami/language";
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
5
+
6
+ /**
7
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
+ *
9
+ * @this {AsyncTree|null}
10
+ * @param {string[]} keys
11
+ */
12
+ export default async function files(...keys) {
13
+ assertScopeIsDefined(this);
14
+ const resolved = path.resolve(process.cwd(), ...keys);
15
+ /** @type {AsyncTree} */
16
+ let result = new OrigamiFiles(resolved);
17
+ result = Scope.treeWithScope(result, this);
18
+ return result;
19
+ }
20
+
21
+ files.usage = `@files [path]\tTree of files at the given path`;
22
+ files.documentation = "https://graphorigami.org/language/@files.html";
@@ -0,0 +1,23 @@
1
+ import { Scope } from "@weborigami/language";
2
+ import FilterTree from "../common/FilterTree.js";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * Apply a filter to a tree.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
+ * @this {AsyncTree|null}
11
+ * @param {Treelike} treelike
12
+ * @param {Treelike} filterVariant
13
+ */
14
+ export default async function filter(treelike, filterVariant) {
15
+ assertScopeIsDefined(this);
16
+ /** @type {AsyncTree} */
17
+ let result = new FilterTree(treelike, filterVariant);
18
+ result = Scope.treeWithScope(result, this);
19
+ return result;
20
+ }
21
+
22
+ filter.usage = `@filter <tree>, <filter>\tOnly returns values whose keys match the filter`;
23
+ filter.documentation = "https://graphorigami.org/language/@filter.html";
@@ -0,0 +1,23 @@
1
+ import { Scope } from "@weborigami/language";
2
+ import GlobTree from "../common/GlobTree.js";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * Define a tree whose keys are globs.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
+ *
11
+ * @param {Treelike} tree
12
+ * @this {AsyncTree|null}
13
+ */
14
+ export default async function globs(tree) {
15
+ assertScopeIsDefined(this);
16
+ /** @type {AsyncTree} */
17
+ let result = new GlobTree(tree);
18
+ result = Scope.treeWithScope(result, this);
19
+ return result;
20
+ }
21
+
22
+ globs.usage = `@globs <patterns>\tDefine a tree whose keys can include wildcard globs`;
23
+ globs.documentation = "https://graphorigami.org/language/@globs.html";
@@ -0,0 +1,49 @@
1
+ /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
+ import child_process from "node:child_process";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ const groupUrls = {
6
+ "@cache": "https://graphorigami.org/language/@cache.html",
7
+ "@tree": "https://graphorigami.org/language/@tree.html",
8
+ "@image": "https://graphorigami.org/language/@image.html",
9
+ "@parse": "https://graphorigami.org/language/@parse.html",
10
+ "@scope": "https://graphorigami.org/language/@scope.html",
11
+ };
12
+
13
+ /**
14
+ * @this {AsyncTree|null}
15
+ * @param {string} [name]
16
+ */
17
+ export default async function help(name) {
18
+ assertScopeIsDefined(this);
19
+ let url;
20
+ const scope = this;
21
+ if (scope && name) {
22
+ if (groupUrls[name]) {
23
+ url = groupUrls[name];
24
+ } else {
25
+ const fn = await scope.get(name);
26
+ url = fn?.documentation;
27
+ }
28
+ if (!url) {
29
+ console.error(
30
+ `help: ${name} does not have a property called "documentation" linking to its documentation`
31
+ );
32
+ return;
33
+ }
34
+ } else {
35
+ url = "https://graphorigami.org/cli/";
36
+ }
37
+ const platform = process.platform;
38
+ const start =
39
+ platform === "darwin"
40
+ ? "open"
41
+ : platform === "win32"
42
+ ? "start"
43
+ : "xdg-open";
44
+ const command = `${start} ${url}`;
45
+ child_process.exec(command);
46
+ }
47
+
48
+ help.usage = `@help/<name>\tOpens documentation for the named built-in command`;
49
+ help.documentation = "https://graphorigami.org/language/@help.html";
@@ -0,0 +1,19 @@
1
+ import { ops } from "@weborigami/language";
2
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+
4
+ /**
5
+ * Retrieve the indicated web resource via HTTP.
6
+ *
7
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
+ *
9
+ * @this {AsyncTree|null}
10
+ * @param {string} host
11
+ * @param {...string} keys
12
+ */
13
+ export default async function http(host, ...keys) {
14
+ assertScopeIsDefined(this);
15
+ return ops.http.call(this, host, ...keys);
16
+ }
17
+
18
+ http.usage = `@http <host>, <...keys>\tA web resource via HTTP`;
19
+ http.documentation = "https://graphorigami.org/language/@http.html";
@@ -0,0 +1,19 @@
1
+ import { ops } from "@weborigami/language";
2
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
3
+
4
+ /**
5
+ * Retrieve the indicated web resource via HTTPS.
6
+ *
7
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
8
+ *
9
+ * @this {AsyncTree|null}
10
+ * @param {string} host
11
+ * @param {...string} keys
12
+ */
13
+ export default async function https(host, ...keys) {
14
+ assertScopeIsDefined(this);
15
+ return ops.https.call(this, host, ...keys);
16
+ }
17
+
18
+ https.usage = `@https <host>, <...keys>\tA web resource via HTTPS`;
19
+ https.documentation = "https://graphorigami.org/language/@https.html";
@@ -0,0 +1,27 @@
1
+ /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
+ import { Tree } from "@weborigami/async-tree";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * @this {AsyncTree|null}
7
+ * @param {any} value
8
+ * @param {any} trueResult
9
+ * @param {any} [falseResult]
10
+ */
11
+ export default async function ifCommand(value, trueResult, falseResult) {
12
+ assertScopeIsDefined(this);
13
+ let condition = await value;
14
+ if (Tree.isAsyncTree(condition)) {
15
+ const keys = Array.from(await condition.keys());
16
+ condition = keys.length > 0;
17
+ }
18
+
19
+ let result = condition ? trueResult : falseResult;
20
+ if (typeof result === "function") {
21
+ result = await result.call(this);
22
+ }
23
+ return result;
24
+ }
25
+
26
+ ifCommand.usage = `@if <value>, <true>, [<false>]\tThe true or false result based on the value`;
27
+ ifCommand.documentation = "https://graphorigami.org/language/@if.html";
@@ -0,0 +1,5 @@
1
+ import sharp from "sharp";
2
+
3
+ export default function format(buffer, format, options) {
4
+ return sharp(buffer).toFormat(format, options).toBuffer();
5
+ }
@@ -0,0 +1,5 @@
1
+ import sharp from "sharp";
2
+
3
+ export default function resize(buffer, options) {
4
+ return sharp(buffer).resize(options).toBuffer();
5
+ }
@@ -0,0 +1,72 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+ import { keySymbol } from "../common/utilities.js";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * Return a default index.html page for the current tree.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
+ * @this {AsyncTree|null}
11
+ * @param {Treelike} [treelike]
12
+ */
13
+ export default async function index(treelike) {
14
+ assertScopeIsDefined(this);
15
+ treelike = treelike ?? (await this?.get("@current"));
16
+ if (treelike === undefined) {
17
+ return undefined;
18
+ }
19
+ const tree = Tree.from(treelike);
20
+ const keys = Array.from(await tree.keys());
21
+
22
+ // Skip system-ish files that start with a period. Also skip `index.html`.
23
+ const filtered = keys.filter(
24
+ (key) => !(key.startsWith?.(".") || key === "index.html")
25
+ );
26
+
27
+ const links = [];
28
+ for (const key of filtered) {
29
+ const keyText = String(key);
30
+ // Simple key.
31
+ const link = `<li><a href="${keyText}">${keyText}</a></li>`;
32
+ links.push(link);
33
+ }
34
+
35
+ const heading = tree[keySymbol] ?? "Index";
36
+ const list = `
37
+ <h1>${heading.trim()}</h1>
38
+ <ul>\n${links.join("\n").trim()}\n</ul>
39
+ `;
40
+
41
+ const html = `
42
+ <!DOCTYPE html>
43
+ <html lang="en">
44
+ <head>
45
+ <meta charset="utf-8" />
46
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
47
+ <style>
48
+ li {
49
+ margin-bottom: 0.20em;
50
+ }
51
+
52
+ a {
53
+ text-decoration: none;
54
+ }
55
+ a:hover {
56
+ text-decoration: revert;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ ${list.trim()}
62
+ </body>
63
+ </html>`;
64
+
65
+ /** @type {any} */
66
+ const result = new String(html.trim());
67
+ result.unpack = () => tree;
68
+ return result;
69
+ }
70
+
71
+ index.usage = `@index\tReturn a default index.html page for the current tree`;
72
+ index.documentation = "https://graphorigami.org/language/@index.html";
@@ -0,0 +1,17 @@
1
+ /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
+ import { ops } from "@weborigami/language";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * Return the inherited value (if any) for the indicated key.
7
+ *
8
+ * @param {any} key
9
+ * @this {AsyncTree|null}
10
+ */
11
+ export default async function inherited(key) {
12
+ assertScopeIsDefined(this);
13
+ return ops.inherited.call(this, key);
14
+ }
15
+
16
+ inherited.usage = `@inherited <key>\tThe value of the key in the tree's inherited scope`;
17
+ inherited.documentation = "https://graphorigami.org/language/@inherited.html";
@@ -0,0 +1,29 @@
1
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
2
+ import unpackOrigamiTemplate from "./@loaders/orit.js";
3
+
4
+ /**
5
+ * Inline any Origami expressions found inside {{...}} placeholders in the input
6
+ * text.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").StringLike} StringLike
10
+ *
11
+ * @this {AsyncTree|null}
12
+ * @param {StringLike} input
13
+ */
14
+ export default async function inline(input) {
15
+ assertScopeIsDefined(this);
16
+ if (/** @type {any} */ (input).unpack) {
17
+ input = await /** @type {any} */ (input).unpack();
18
+ }
19
+ const inputDocument = input["@text"] ? input : null;
20
+ const templateInput = inputDocument ?? input;
21
+ const templateFn = await unpackOrigamiTemplate(templateInput);
22
+ const text = await templateFn(inputDocument);
23
+ return inputDocument
24
+ ? Object.assign({}, inputDocument, { "@text": String(text) })
25
+ : text;
26
+ }
27
+
28
+ inline.usage = `@inline <text>\tInline Origami expressions found in the text`;
29
+ inline.documentation = "https://graphorigami.org/language/@inline.html";
@@ -0,0 +1,30 @@
1
+ import builtins from "./@builtins.js";
2
+
3
+ /**
4
+ * Invoke the given function.
5
+ *
6
+ * This built-in exists to facilitate executing an Origami file as a script via
7
+ * a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) directive.
8
+ *
9
+ * You can execute a foo.ori file as a script by adding the following shebang
10
+ * directive to the top of the file:
11
+ *
12
+ * ```sh
13
+ * #!/usr/bin/env ori @invoke
14
+ * ```
15
+ *
16
+ * Then mark the file as executable:
17
+ *
18
+ * ```sh
19
+ * chmod +x foo.ori
20
+ * ```
21
+ *
22
+ * @this {import("@weborigami/types").AsyncTree|null}
23
+ */
24
+ export default async function invoke(fn) {
25
+ if (typeof fn !== "function" && fn.unpack) {
26
+ fn = await fn.unpack();
27
+ }
28
+ const scope = (await this?.get("@current")) ?? builtins;
29
+ return typeof fn === "function" ? fn.call(scope) : fn;
30
+ }
@@ -0,0 +1,33 @@
1
+ const js = {
2
+ Array,
3
+ Boolean,
4
+ Date,
5
+ Error,
6
+ Infinity,
7
+ Intl,
8
+ JSON,
9
+ Math,
10
+ NaN,
11
+ Number,
12
+ Object,
13
+ RegExp,
14
+ String,
15
+ Symbol,
16
+ decodeURI,
17
+ decodeURIComponent,
18
+ encodeURI,
19
+ encodeURIComponent,
20
+ false: false,
21
+ isFinite,
22
+ isNaN,
23
+ null: null,
24
+ parseFloat,
25
+ parseInt,
26
+ true: true,
27
+ undefined: undefined,
28
+ };
29
+
30
+ js.usage = "@js\tAccess JavaScript classes and utility functions";
31
+ js.documentation = "https://graphorigami.org/language/@js.html";
32
+
33
+ export default js;
@@ -0,0 +1,22 @@
1
+ /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
+ import * as serialize from "../common/serialize.js";
3
+ import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
4
+
5
+ /**
6
+ * Render the given object in JSON format.
7
+ *
8
+ * @this {AsyncTree|null}
9
+ * @param {any} [obj]
10
+ */
11
+ export default async function json(obj) {
12
+ assertScopeIsDefined(this);
13
+ obj = obj ?? (await this?.get("@current"));
14
+ if (obj === undefined) {
15
+ return undefined;
16
+ }
17
+ const value = await serialize.toJsonValue(obj);
18
+ return JSON.stringify(value, null, 2);
19
+ }
20
+
21
+ json.usage = "@json <obj>\tRender the object as text in JSON format";
22
+ json.documentation = "https://graphorigami.org/language/@json.html";
@@ -0,0 +1,4 @@
1
+ import unpackText from "./txt.js";
2
+
3
+ // Load this file type as text with possible front matter.
4
+ export default unpackText;
@@ -0,0 +1,4 @@
1
+ import unpackText from "./txt.js";
2
+
3
+ // Load this file type as text with possible front matter.
4
+ export default unpackText;
@@ -0,0 +1,4 @@
1
+ import unpackText from "./txt.js";
2
+
3
+ // Load this file type as text with possible front matter.
4
+ export default unpackText;
@@ -0,0 +1,14 @@
1
+ import processUnpackedContent from "../../common/processUnpackedContent.js";
2
+
3
+ /**
4
+ * Load a .js file as module's default export or exports.
5
+ *
6
+ * @type {import("@weborigami/language").FileUnpackFunction}
7
+ */
8
+ export default async function unpackModule(input, options = {}) {
9
+ const { key, parent } = options;
10
+ if (parent && "import" in parent) {
11
+ const content = await /** @type {any} */ (parent).import?.(key);
12
+ return processUnpackedContent(content, parent);
13
+ }
14
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Load a file as JSON.
3
+ *
4
+ * @type {import("@weborigami/language").FileUnpackFunction}
5
+ */
6
+ export default function unpackJson(input) {
7
+ return JSON.parse(String(input));
8
+ }
@@ -0,0 +1,4 @@
1
+ import unpackText from "./txt.js";
2
+
3
+ // Load this file type as text with possible front matter.
4
+ export default unpackText;
@@ -0,0 +1,4 @@
1
+ import unpackModule from "./js.js";
2
+
3
+ // .mjs modules use the same loader as .js modules.
4
+ export default unpackModule;
@@ -0,0 +1,21 @@
1
+ import { Scope } from "@weborigami/language";
2
+ import * as compile from "../../../../language/src/compiler/compile.js";
3
+ import processUnpackedContent from "../../common/processUnpackedContent.js";
4
+ import builtins from "../@builtins.js";
5
+
6
+ /**
7
+ * Load and evaluate an Origami expression from a file.
8
+ *
9
+ * @type {import("@weborigami/language").FileUnpackFunction}
10
+ */
11
+ export default async function unpackOrigamiExpression(input, options = {}) {
12
+ const parent = options.parent ?? null;
13
+
14
+ // Compile the body text as an Origami expression and evaluate it.
15
+ const text = String(input);
16
+ const fn = compile.expression(text);
17
+ const parentScope = parent ? Scope.getScope(parent) : builtins;
18
+ let content = await fn.call(parentScope);
19
+
20
+ return processUnpackedContent(content, parent);
21
+ }
@@ -0,0 +1,48 @@
1
+ import { Scope } from "@weborigami/language";
2
+ import * as compile from "../../../../language/src/compiler/compile.js";
3
+ import processUnpackedContent from "../../common/processUnpackedContent.js";
4
+ import * as utilities from "../../common/utilities.js";
5
+ import builtins from "../@builtins.js";
6
+ import unpackText from "./txt.js";
7
+
8
+ /**
9
+ * Load and evaluate an Origami template from a file.
10
+ *
11
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
12
+ * @type {import("@weborigami/language").FileUnpackFunction}
13
+ */
14
+ export default async function unpackOrigamiTemplate(input, options = {}) {
15
+ const parent =
16
+ options.parent ??
17
+ /** @type {any} */ (input).parent ??
18
+ /** @type {any} */ (input)[utilities.parentSymbol];
19
+
20
+ // Get the input text and any attached front matter.
21
+ let inputDocument;
22
+ if (input["@text"]) {
23
+ inputDocument = input;
24
+ } else {
25
+ // Unpack the input as a text document with possible front matter.
26
+ inputDocument = await unpackText(input, options);
27
+ }
28
+ const text = utilities.toString(inputDocument);
29
+
30
+ // Compile the body text as an Origami expression and evaluate it.
31
+ const expression = compile.templateDocument(text);
32
+ const parentScope = parent ? Scope.getScope(parent) : builtins;
33
+ const lambda = await expression.call(parentScope);
34
+
35
+ // Wrap the lambda with a function that will attach the input data to the
36
+ // result.
37
+ /** @this {AsyncTree|null} */
38
+ const fn = async function createTemplateResult(templateInput) {
39
+ const text = await lambda.call(this, templateInput);
40
+ /** @type {any} */
41
+ const result = new String(text);
42
+ result.unpack = () => templateInput;
43
+ return result;
44
+ };
45
+ fn.code = lambda.code;
46
+
47
+ return processUnpackedContent(fn, parent, inputDocument);
48
+ }
@@ -0,0 +1,33 @@
1
+ import TextDocument from "../../common/TextDocument.js";
2
+ import { evaluateYaml } from "../../common/serialize.js";
3
+
4
+ /**
5
+ * Load a file as text document with possible front matter.
6
+ *
7
+ * This process will parse out any YAML or JSON front matter and attach it to
8
+ * the document as data. The first line of the text must be "---", followed by a
9
+ * block of JSON or YAML, followed by another line of "---". Any lines following
10
+ * will be treated as the document text.
11
+ *
12
+ * Any Origami expressions in the front matter will be evaluated and the results
13
+ * incorporated into the document data.
14
+ *
15
+ * @type {import("@weborigami/language").FileUnpackFunction}
16
+ */
17
+ export default async function unpackText(input, options = {}) {
18
+ const parent = options.parent ?? null;
19
+ const text = String(input);
20
+ const regex =
21
+ /^(---\r?\n(?<frontText>[\s\S]*?\r?\n)---\r?\n)(?<body>[\s\S]*$)/;
22
+ const match = regex.exec(text);
23
+
24
+ const body = match?.groups?.body ?? text;
25
+
26
+ const frontData = match?.groups
27
+ ? await evaluateYaml(match.groups.frontText, parent)
28
+ : null;
29
+
30
+ const object = Object.assign({}, frontData, { "@text": body });
31
+
32
+ return new TextDocument(object, options.parent);
33
+ }
@@ -0,0 +1,4 @@
1
+ import unpackText from "./txt.js";
2
+
3
+ // Load this file type as text with possible front matter.
4
+ export default unpackText;
@@ -0,0 +1,18 @@
1
+ import * as YAMLModule from "yaml";
2
+ import processUnpackedContent from "../../common/processUnpackedContent.js";
3
+ import { evaluateYaml } from "../../common/serialize.js";
4
+
5
+ // See notes at serialize.js
6
+ // @ts-ignore
7
+ const YAML = YAMLModule.default ?? YAMLModule.YAML;
8
+
9
+ /**
10
+ * Load a file as YAML.
11
+ *
12
+ * @type {import("@weborigami/language").FileUnpackFunction}
13
+ */
14
+ export default async function unpackYaml(input, options = {}) {
15
+ const parent = options.parent ?? null;
16
+ const data = evaluateYaml(String(input), options.parent);
17
+ return processUnpackedContent(data, parent);
18
+ }
@@ -0,0 +1,4 @@
1
+ import yaml from "./yaml.js";
2
+
3
+ // .yml files uses the YAML loader
4
+ export default yaml;