@weborigami/origami 0.0.45 → 0.0.47
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/exports/buildExports.js +13 -9
- package/exports/exports.js +17 -16
- package/package.json +11 -13
- package/src/builtins/@cache.js +2 -6
- package/src/builtins/@config.js +12 -5
- package/src/builtins/@crawl.js +3 -3
- package/src/builtins/@debug.js +9 -2
- package/src/builtins/@document.js +3 -5
- package/src/builtins/@fnTree.js +5 -2
- package/src/builtins/@inline.js +18 -25
- package/src/builtins/@inners.js +1 -3
- package/src/builtins/@invoke.js +2 -1
- package/src/builtins/@json.js +0 -3
- package/src/builtins/@keysJson.js +1 -4
- package/src/builtins/@map.js +38 -45
- package/src/builtins/@mapDeep.js +2 -2
- package/src/builtins/@mdHtml.js +10 -11
- package/src/builtins/@mkdir.js +3 -0
- package/src/builtins/@node.js +2 -1
- package/src/builtins/@project.js +22 -14
- package/src/builtins/@shuffle.js +1 -6
- package/src/builtins/@sitemap.js +2 -2
- package/src/builtins/@sort.js +1 -4
- package/src/builtins/@static.js +1 -3
- package/src/builtins/@tree.js +1 -4
- package/src/builtins/@yaml.js +0 -3
- package/src/builtins/css_handler.js +7 -0
- package/src/builtins/htm_handler.js +2 -0
- package/src/builtins/html_handler.js +7 -0
- package/src/builtins/jpeg_handler.js +58 -0
- package/src/builtins/jpg_handler.js +2 -0
- package/src/builtins/js_handler.js +20 -0
- package/src/builtins/json_handler.js +19 -0
- package/src/builtins/map.d.ts +5 -5
- package/src/builtins/md_handler.js +7 -0
- package/src/builtins/mjs_handler.js +2 -0
- package/src/builtins/ori_handler.js +48 -0
- package/src/builtins/txt_handler.js +78 -0
- package/src/builtins/wasm_handler.js +17 -0
- package/src/builtins/xhtml_handler.js +2 -0
- package/src/builtins/yaml_handler.js +29 -0
- package/src/builtins/yml_handler.js +2 -0
- package/src/common/ExplorableSiteTransform.js +5 -1
- package/src/common/addValueKeyToScope.js +3 -2
- package/src/common/arrowFunctionsMap.js +5 -5
- package/src/common/documentObject.js +33 -0
- package/src/common/serialize.d.ts +1 -0
- package/src/common/serialize.js +68 -27
- package/src/common/utilities.js +9 -7
- package/src/misc/getTreeArgument.js +12 -2
- package/src/misc/treeDot.js +6 -1
- package/src/server/constructResponse.js +18 -5
- package/src/server/server.js +5 -4
- package/src/builtins/!.js +0 -21
- package/src/builtins/@loaders/css.js +0 -2
- package/src/builtins/@loaders/htm.js +0 -2
- package/src/builtins/@loaders/html.js +0 -2
- package/src/builtins/@loaders/jpeg.js +0 -55
- package/src/builtins/@loaders/jpg.js +0 -2
- package/src/builtins/@loaders/js.js +0 -14
- package/src/builtins/@loaders/json.js +0 -14
- package/src/builtins/@loaders/md.js +0 -2
- package/src/builtins/@loaders/mjs.js +0 -2
- package/src/builtins/@loaders/ori.js +0 -45
- package/src/builtins/@loaders/txt.js +0 -37
- package/src/builtins/@loaders/wasm.js +0 -11
- package/src/builtins/@loaders/xhtml.js +0 -2
- package/src/builtins/@loaders/yaml.js +0 -23
- package/src/builtins/@loaders/yml.js +0 -2
- package/src/common/TextDocument.js +0 -58
package/src/builtins/@node.js
CHANGED
package/src/builtins/@project.js
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
import { OrigamiFiles, Scope } from "@weborigami/language";
|
|
3
3
|
import assertScopeIsDefined from "../misc/assertScopeIsDefined.js";
|
|
4
4
|
import builtins from "./@builtins.js";
|
|
5
|
+
import fileTypeOrigami from "./ori_handler.js";
|
|
5
6
|
|
|
6
|
-
const configFileName = "
|
|
7
|
+
const configFileName = "config.ori";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Return the tree for the current project's root folder.
|
|
10
11
|
*
|
|
11
|
-
* This searches the current directory and its ancestors for an Origami
|
|
12
|
-
*
|
|
13
|
-
* folder is considered to be the project root. This returns a tree
|
|
14
|
-
* folder, with the exported configuration as the context for that
|
|
15
|
-
* is, the tree exported by the configuration will be the scope.
|
|
12
|
+
* This searches the current directory and its ancestors for an Origami file
|
|
13
|
+
* called `config.ori`. If an Origami configuration file is found, the
|
|
14
|
+
* containing folder is considered to be the project root. This returns a tree
|
|
15
|
+
* for that folder, with the exported configuration as the context for that
|
|
16
|
+
* folder — that is, the tree exported by the configuration will be the scope.
|
|
16
17
|
*
|
|
17
18
|
* If no Origami configuration file is found, the current folder will be
|
|
18
19
|
* returned as a tree, with the builtins as its parent.
|
|
@@ -25,24 +26,31 @@ export default async function project(key) {
|
|
|
25
26
|
|
|
26
27
|
const dirname = process.cwd();
|
|
27
28
|
const currentTree = new OrigamiFiles(dirname);
|
|
28
|
-
let
|
|
29
|
+
let containerTree = await findConfigContainer(currentTree);
|
|
29
30
|
|
|
30
31
|
let config;
|
|
31
|
-
if (
|
|
32
|
+
if (containerTree) {
|
|
32
33
|
// Load the configuration.
|
|
33
|
-
|
|
34
|
+
const configParent = Scope.treeWithScope(containerTree, builtins);
|
|
35
|
+
const buffer = await configParent.get(configFileName);
|
|
36
|
+
config = await fileTypeOrigami.unpack(buffer, {
|
|
37
|
+
key: configFileName,
|
|
38
|
+
parent: configParent,
|
|
39
|
+
});
|
|
34
40
|
if (!config) {
|
|
41
|
+
const configPath = /** @type {any} */ (configParent).path;
|
|
35
42
|
throw new Error(
|
|
36
|
-
`Couldn't load the Origami configuration in ${
|
|
43
|
+
`Couldn't load the Origami configuration in ${configPath}/${configFileName}`
|
|
37
44
|
);
|
|
38
45
|
}
|
|
39
46
|
} else {
|
|
40
|
-
|
|
41
|
-
config =
|
|
47
|
+
containerTree = currentTree;
|
|
48
|
+
config = null;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
// Add the configuration as the context for the project root.
|
|
45
|
-
const
|
|
52
|
+
const scope = new Scope(config, builtins);
|
|
53
|
+
const result = Scope.treeWithScope(containerTree, scope);
|
|
46
54
|
return key === undefined ? result : result.get(key);
|
|
47
55
|
}
|
|
48
56
|
|
|
@@ -67,5 +75,5 @@ async function findConfigContainer(start) {
|
|
|
67
75
|
return undefined;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
project.usage = `@project\tThe root of the current
|
|
78
|
+
project.usage = `@project\tThe root of the current Origami project`;
|
|
71
79
|
project.documentation = "https://weborigami.org/language/@project.html";
|
package/src/builtins/@shuffle.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Scope } from "@weborigami/language";
|
|
2
1
|
import ShuffleTransform from "../common/ShuffleTransform.js";
|
|
3
2
|
import { transformObject } from "../common/utilities.js";
|
|
4
3
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
@@ -14,11 +13,7 @@ import getTreeArgument from "../misc/getTreeArgument.js";
|
|
|
14
13
|
*/
|
|
15
14
|
export default async function shuffle(treelike) {
|
|
16
15
|
const tree = await getTreeArgument(this, arguments, treelike, "@shuffle");
|
|
17
|
-
|
|
18
|
-
/** @type {AsyncTree} */
|
|
19
|
-
let shuffled = transformObject(ShuffleTransform, tree);
|
|
20
|
-
shuffled = Scope.treeWithScope(shuffled, this);
|
|
21
|
-
return shuffled;
|
|
16
|
+
return transformObject(ShuffleTransform, tree);
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
shuffle.usage = `@shuffle <tree>\tReturn a new tree with the original's keys shuffled`;
|
package/src/builtins/@sitemap.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
2
2
|
import builtins from "./@builtins.js";
|
|
3
|
-
import unpackOrigamiExpression from "./@loaders/ori.js";
|
|
4
3
|
import paths from "./@paths.js";
|
|
4
|
+
import fileTypeOrigami from "./ori_handler.js";
|
|
5
5
|
|
|
6
6
|
const templateText = `=\`<?xml version="1.0" encoding="UTF-8"?>
|
|
7
7
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
@@ -48,7 +48,7 @@ export default async function sitemap(treelike, baseHref = "") {
|
|
|
48
48
|
.filter((path) => path.endsWith(".html"))
|
|
49
49
|
.map((path) => (path.endsWith("index.html") ? path.slice(0, -10) : path));
|
|
50
50
|
|
|
51
|
-
const templateFn = await
|
|
51
|
+
const templateFn = await fileTypeOrigami.unpack(templateText);
|
|
52
52
|
const templateResult = await templateFn.call(builtins, htmlPaths);
|
|
53
53
|
return String(templateResult);
|
|
54
54
|
}
|
package/src/builtins/@sort.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { sortNatural } from "@weborigami/async-tree";
|
|
2
|
-
import { Scope } from "@weborigami/language";
|
|
3
2
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -14,9 +13,7 @@ import getTreeArgument from "../misc/getTreeArgument.js";
|
|
|
14
13
|
*/
|
|
15
14
|
export default async function sort(treelike) {
|
|
16
15
|
const tree = await getTreeArgument(this, arguments, treelike, "@sort");
|
|
17
|
-
|
|
18
|
-
const scoped = Scope.treeWithScope(sorted, this);
|
|
19
|
-
return scoped;
|
|
16
|
+
return sortNatural()(tree);
|
|
20
17
|
}
|
|
21
18
|
|
|
22
19
|
sort.usage = `@sort <tree>\tReturn a new tree with the original's keys sorted`;
|
package/src/builtins/@static.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Tree, keysJson } from "@weborigami/async-tree";
|
|
2
|
-
import { Scope } from "@weborigami/language";
|
|
3
2
|
import { transformObject } from "../common/utilities.js";
|
|
4
3
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
5
4
|
import index from "./@index.js";
|
|
@@ -14,8 +13,7 @@ import index from "./@index.js";
|
|
|
14
13
|
*/
|
|
15
14
|
export default async function staticTree(treelike) {
|
|
16
15
|
const tree = await getTreeArgument(this, arguments, treelike, "@static");
|
|
17
|
-
|
|
18
|
-
result = Scope.treeWithScope(result, this);
|
|
16
|
+
const result = transformObject(StaticTransform, tree);
|
|
19
17
|
return result;
|
|
20
18
|
}
|
|
21
19
|
|
package/src/builtins/@tree.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Scope } from "@weborigami/language";
|
|
2
1
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -10,9 +9,7 @@ import getTreeArgument from "../misc/getTreeArgument.js";
|
|
|
10
9
|
* @param {Treelike} [treelike]
|
|
11
10
|
*/
|
|
12
11
|
export default async function tree(treelike) {
|
|
13
|
-
|
|
14
|
-
tree = Scope.treeWithScope(tree, this);
|
|
15
|
-
return tree;
|
|
12
|
+
return getTreeArgument(this, arguments, treelike, "@tree");
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
tree.usage = `@tree <treelike>\tConvert JSON, YAML, function, or plain object to a tree`;
|
package/src/builtins/@yaml.js
CHANGED
|
@@ -21,9 +21,6 @@ export default async function toYaml(obj) {
|
|
|
21
21
|
if (obj === undefined) {
|
|
22
22
|
return undefined;
|
|
23
23
|
}
|
|
24
|
-
if (typeof obj.unpack === "function") {
|
|
25
|
-
obj = await obj.unpack();
|
|
26
|
-
}
|
|
27
24
|
const value = await serialize.toJsonValue(obj);
|
|
28
25
|
return YAML.stringify(value);
|
|
29
26
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import exifParser from "exif-parser";
|
|
2
|
+
|
|
3
|
+
const exifDateTags = [
|
|
4
|
+
"ModifyDate",
|
|
5
|
+
"MDPrepDate",
|
|
6
|
+
"DateTimeOriginal",
|
|
7
|
+
"CreateDate",
|
|
8
|
+
"PreviewDateTime",
|
|
9
|
+
"GPSDateStamp",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A JPEG file with possible Exif metadata
|
|
14
|
+
*/
|
|
15
|
+
export default {
|
|
16
|
+
mediaType: "image/jpeg",
|
|
17
|
+
|
|
18
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
19
|
+
async unpack(packed, options) {
|
|
20
|
+
const parser = exifParser.create(packed);
|
|
21
|
+
parser.enableTagNames(true);
|
|
22
|
+
parser.enableSimpleValues(true);
|
|
23
|
+
const parsed = await parser.parse();
|
|
24
|
+
|
|
25
|
+
// The exif-parser `enableSimpleValues` option should convert dates to
|
|
26
|
+
// JavaScript Date objects, but that doesn't seem to work. Ensure dates are
|
|
27
|
+
// Date objects.
|
|
28
|
+
const exif = parsed.tags;
|
|
29
|
+
for (const tag of exifDateTags) {
|
|
30
|
+
if (typeof exif[tag] === "number") {
|
|
31
|
+
exif[tag] = new Date(exif[tag] * 1000);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result = {
|
|
36
|
+
height: parsed.imageSize.height,
|
|
37
|
+
width: parsed.imageSize.width,
|
|
38
|
+
exif,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Promote some Exif properties to the top level.
|
|
42
|
+
const tagsToPromote = {
|
|
43
|
+
ImageDescription: "caption",
|
|
44
|
+
ModifyDate: "modified",
|
|
45
|
+
Orientation: "orientation",
|
|
46
|
+
};
|
|
47
|
+
for (const [tag, key] of Object.entries(tagsToPromote)) {
|
|
48
|
+
if (exif[tag] !== undefined) {
|
|
49
|
+
result[key] = exif[tag];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Add aspect ratio for use with `aspect-ratio` CSS.
|
|
54
|
+
result.aspectRatio = result.width / result.height;
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
},
|
|
58
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import processUnpackedContent from "../common/processUnpackedContent.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A JavaScript file
|
|
5
|
+
*
|
|
6
|
+
* Unpacking a JavaScript file returns its default export, or its set of exports
|
|
7
|
+
* if there is more than one.
|
|
8
|
+
*/
|
|
9
|
+
export default {
|
|
10
|
+
mediaType: "application/javascript",
|
|
11
|
+
|
|
12
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
13
|
+
async unpack(packed, options = {}) {
|
|
14
|
+
const { key, parent } = options;
|
|
15
|
+
if (parent && "import" in parent) {
|
|
16
|
+
const content = await /** @type {any} */ (parent).import?.(key);
|
|
17
|
+
return processUnpackedContent(content, parent);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as utilities from "../common/utilities.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A JSON file
|
|
5
|
+
*
|
|
6
|
+
* Unpacking a JSON file returns the parsed data.
|
|
7
|
+
*/
|
|
8
|
+
export default {
|
|
9
|
+
mediaType: "application/json",
|
|
10
|
+
|
|
11
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
12
|
+
unpack(packed) {
|
|
13
|
+
const json = utilities.toString(packed);
|
|
14
|
+
if (!json) {
|
|
15
|
+
throw new Error("Tried to parse something as JSON but it wasn't text.");
|
|
16
|
+
}
|
|
17
|
+
return JSON.parse(json);
|
|
18
|
+
},
|
|
19
|
+
};
|
package/src/builtins/map.d.ts
CHANGED
|
@@ -6,12 +6,12 @@ type TreeMapOptions = {
|
|
|
6
6
|
deep?: boolean;
|
|
7
7
|
description?: string;
|
|
8
8
|
extensions?: string;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
inverseKey?: KeyFn;
|
|
10
|
+
key?: ValueKeyFn;
|
|
11
|
+
value?: ValueKeyFn;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export default function treeMap(
|
|
14
|
+
export default function treeMap(value: ValueKeyFn): TreelikeTransform;
|
|
15
15
|
export default function treeMap(options: TreeMapOptions): TreelikeTransform;
|
|
16
|
-
export default function treeMap(treelike: Treelike,
|
|
16
|
+
export default function treeMap(treelike: Treelike, value: ValueKeyFn): AsyncTree;
|
|
17
17
|
export default function treeMap(treelike: Treelike, options: TreeMapOptions): AsyncTree;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { symbols } from "@weborigami/async-tree";
|
|
2
|
+
import { Scope, compile } from "@weborigami/language";
|
|
3
|
+
import processUnpackedContent from "../common/processUnpackedContent.js";
|
|
4
|
+
import * as utilities from "../common/utilities.js";
|
|
5
|
+
import builtins from "./@builtins.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An Origami expression file
|
|
9
|
+
*
|
|
10
|
+
* Unpacking an Origami file returns the result of evaluating the expression.
|
|
11
|
+
*/
|
|
12
|
+
export default {
|
|
13
|
+
mediaType: "text/plain",
|
|
14
|
+
|
|
15
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
16
|
+
async unpack(packed, options = {}) {
|
|
17
|
+
const attachedData = options.attachedData;
|
|
18
|
+
const parent =
|
|
19
|
+
options.parent ??
|
|
20
|
+
/** @type {any} */ (packed).parent ??
|
|
21
|
+
/** @type {any} */ (packed)[symbols.parent];
|
|
22
|
+
|
|
23
|
+
// Construct an object to represent the source code.
|
|
24
|
+
const sourceName = options.key;
|
|
25
|
+
let url;
|
|
26
|
+
if (sourceName && parent?.url) {
|
|
27
|
+
let parentHref = parent.url.href;
|
|
28
|
+
if (!parentHref.endsWith("/")) {
|
|
29
|
+
parentHref += "/";
|
|
30
|
+
}
|
|
31
|
+
url = new URL(sourceName, parentHref);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const source = {
|
|
35
|
+
text: utilities.toString(packed),
|
|
36
|
+
name: options.key,
|
|
37
|
+
url,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Compile the source code as an Origami expression and evaluate it.
|
|
41
|
+
const compiler = options.compiler ?? compile.expression;
|
|
42
|
+
const fn = compiler(source);
|
|
43
|
+
const parentScope = parent ? Scope.getScope(parent) : builtins;
|
|
44
|
+
let content = await fn.call(parentScope);
|
|
45
|
+
|
|
46
|
+
return processUnpackedContent(content, parent, attachedData);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { isPacked, symbols } from "@weborigami/async-tree";
|
|
2
|
+
import { evaluateYaml, toYaml } from "../common/serialize.js";
|
|
3
|
+
import * as utilities from "../common/utilities.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A text file with possible front matter
|
|
7
|
+
*
|
|
8
|
+
* The unpacking process will parse out any YAML or JSON front matter and attach
|
|
9
|
+
* it to the document as data. The first line of the text must be "---",
|
|
10
|
+
* followed by a block of JSON or YAML, followed by another line of "---". Any
|
|
11
|
+
* lines following will be treated as the document text.
|
|
12
|
+
*
|
|
13
|
+
* If there is no front matter, the document will be treated as plain text and
|
|
14
|
+
* returned as a String object.
|
|
15
|
+
*
|
|
16
|
+
* If there is front matter, any Origami expressions in the front matter will be
|
|
17
|
+
* evaluated. The result will be a plain JavaScript object with the evaluated
|
|
18
|
+
* data and a `@text` property containing the document text.
|
|
19
|
+
*/
|
|
20
|
+
export default {
|
|
21
|
+
mediaType: "text/plain",
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* If the input is already in some packed format, it will be returned as is.
|
|
25
|
+
*
|
|
26
|
+
* Otherwise, the properties of the object will be formatted as YAML. If the
|
|
27
|
+
* object has a `@text` property, that will be used as the body of the text
|
|
28
|
+
* document; otherwise, an empty string will be used.
|
|
29
|
+
*
|
|
30
|
+
* @param {any} object
|
|
31
|
+
* @returns {Promise<import("@weborigami/async-tree").Packed>}
|
|
32
|
+
*/
|
|
33
|
+
async pack(object) {
|
|
34
|
+
if (isPacked(object)) {
|
|
35
|
+
return object;
|
|
36
|
+
} else if (!object || typeof object !== "object") {
|
|
37
|
+
throw new TypeError("The input to pack must be a JavaScript object.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const text = object["@text"] ?? "";
|
|
41
|
+
|
|
42
|
+
/** @type {any} */
|
|
43
|
+
const dataWithoutText = Object.assign({}, object);
|
|
44
|
+
delete dataWithoutText["@text"];
|
|
45
|
+
if (Object.keys(dataWithoutText).length > 0) {
|
|
46
|
+
const frontMatter = (await toYaml(dataWithoutText)).trimEnd();
|
|
47
|
+
return `---\n${frontMatter}\n---\n${text}`;
|
|
48
|
+
} else {
|
|
49
|
+
return text;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
54
|
+
async unpack(packed, options = {}) {
|
|
55
|
+
const parent = options.parent ?? null;
|
|
56
|
+
const text = utilities.toString(packed);
|
|
57
|
+
if (!text) {
|
|
58
|
+
throw new Error("Tried to treat something as text but it wasn't text.");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const regex =
|
|
62
|
+
/^(---\r?\n(?<frontText>[\s\S]*?\r?\n?)---\r?\n)(?<body>[\s\S]*$)/;
|
|
63
|
+
const match = regex.exec(text);
|
|
64
|
+
let unpacked;
|
|
65
|
+
if (match) {
|
|
66
|
+
// Document object with front matter
|
|
67
|
+
const { body, frontText } = /** @type {any} */ (match.groups);
|
|
68
|
+
const frontData = await evaluateYaml(frontText, parent);
|
|
69
|
+
unpacked = Object.assign({}, frontData, { "@text": body });
|
|
70
|
+
} else {
|
|
71
|
+
// Plain text
|
|
72
|
+
unpacked = new String(text);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
unpacked[symbols.parent] = parent;
|
|
76
|
+
return unpacked;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import processUnpackedContent from "../common/processUnpackedContent.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A WebAssembly module
|
|
5
|
+
*
|
|
6
|
+
* Unpacking a WebAssembly module returns its exports.
|
|
7
|
+
*/
|
|
8
|
+
export default {
|
|
9
|
+
mediaType: "application/wasm",
|
|
10
|
+
|
|
11
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
12
|
+
async unpack(packed, options = {}) {
|
|
13
|
+
const wasmModule = await WebAssembly.instantiate(packed);
|
|
14
|
+
// @ts-ignore TypeScript thinks wasmModule is already an Instance.
|
|
15
|
+
return processUnpackedContent(wasmModule.instance.exports, options.parent);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as YAMLModule from "yaml";
|
|
2
|
+
import processUnpackedContent from "../common/processUnpackedContent.js";
|
|
3
|
+
import { evaluateYaml } from "../common/serialize.js";
|
|
4
|
+
import * as utilities from "../common/utilities.js";
|
|
5
|
+
|
|
6
|
+
// See notes at serialize.js
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const YAML = YAMLModule.default ?? YAMLModule.YAML;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A YAML file
|
|
12
|
+
*
|
|
13
|
+
* Unpacking a YAML file returns the parsed data.
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export default {
|
|
17
|
+
mediaType: "application/yaml",
|
|
18
|
+
|
|
19
|
+
/** @type {import("@weborigami/language").UnpackFunction} */
|
|
20
|
+
async unpack(packed, options = {}) {
|
|
21
|
+
const parent = options.parent ?? null;
|
|
22
|
+
const yaml = utilities.toString(packed);
|
|
23
|
+
if (!yaml) {
|
|
24
|
+
throw new Error("Tried to parse something as YAML but it wasn't text.");
|
|
25
|
+
}
|
|
26
|
+
const data = await evaluateYaml(yaml, options.parent);
|
|
27
|
+
return processUnpackedContent(data, parent);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -59,11 +59,15 @@ export default function ExplorableSiteTransform(Base) {
|
|
|
59
59
|
const original = value.unpack.bind(value);
|
|
60
60
|
value.unpack = async () => {
|
|
61
61
|
const content = await original();
|
|
62
|
-
if (!Tree.
|
|
62
|
+
if (!Tree.isTraversable(content)) {
|
|
63
63
|
return content;
|
|
64
64
|
}
|
|
65
65
|
/** @type {any} */
|
|
66
66
|
let tree = Tree.from(content);
|
|
67
|
+
if (!tree.parent && !tree.scope) {
|
|
68
|
+
const scope = Scope.getScope(this);
|
|
69
|
+
tree = Scope.treeWithScope(tree, scope);
|
|
70
|
+
}
|
|
67
71
|
tree = transformObject(ExplorableSiteTransform, tree);
|
|
68
72
|
return tree;
|
|
69
73
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ObjectTree } from "@weborigami/async-tree";
|
|
1
2
|
import { Scope } from "@weborigami/language";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -14,9 +15,9 @@ import { Scope } from "@weborigami/language";
|
|
|
14
15
|
*/
|
|
15
16
|
export default function addValueKeyToScope(scope, value, key) {
|
|
16
17
|
// Add the key and value to the scope as ambients.
|
|
17
|
-
const ambients = {
|
|
18
|
+
const ambients = new ObjectTree({
|
|
18
19
|
"@key": key,
|
|
19
20
|
_: value,
|
|
20
|
-
};
|
|
21
|
+
});
|
|
21
22
|
return new Scope(ambients, scope);
|
|
22
23
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cachedKeyFunctions, map } from "@weborigami/async-tree";
|
|
2
2
|
import { toFunction } from "./utilities.js";
|
|
3
3
|
|
|
4
4
|
export default function arrowFunctionsMap() {
|
|
@@ -6,12 +6,12 @@ export default function arrowFunctionsMap() {
|
|
|
6
6
|
return map({
|
|
7
7
|
deep,
|
|
8
8
|
description: "arrowFunctions",
|
|
9
|
-
|
|
10
|
-
...
|
|
9
|
+
value: valueFn,
|
|
10
|
+
...cachedKeyFunctions(keyFn, deep),
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function
|
|
14
|
+
function keyFn(sourceKey, tree) {
|
|
15
15
|
return parseArrowKey(sourceKey) ?? sourceKey;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ function parseArrowKey(sourceKey) {
|
|
|
23
23
|
return match?.groups.lhs;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function
|
|
26
|
+
function valueFn(sourceValue, sourceKey, tree) {
|
|
27
27
|
let resultValue;
|
|
28
28
|
if (parseArrowKey(sourceKey)) {
|
|
29
29
|
// Treat the value as a function to be invoked.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isPlainObject } from "@weborigami/async-tree";
|
|
2
|
+
import txtHandler from "../builtins/txt_handler.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* In Origami, a text document object is any object with a `@text` property and
|
|
6
|
+
* a pack() method that formats that object as text with YAML front matter. This
|
|
7
|
+
* function is a helper for constructing such text document objects.
|
|
8
|
+
*
|
|
9
|
+
* @typedef {import("@weborigami/async-tree").StringLike} StringLike
|
|
10
|
+
* @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
|
|
11
|
+
*
|
|
12
|
+
* @param {StringLike|PlainObject} input
|
|
13
|
+
* @param {any} [data]
|
|
14
|
+
*/
|
|
15
|
+
export default function documentObject(input, data) {
|
|
16
|
+
let text;
|
|
17
|
+
let inputData;
|
|
18
|
+
if (isPlainObject(input)) {
|
|
19
|
+
text = input["@text"];
|
|
20
|
+
inputData = input;
|
|
21
|
+
} else {
|
|
22
|
+
text = String(input);
|
|
23
|
+
inputData = null;
|
|
24
|
+
}
|
|
25
|
+
const base = {
|
|
26
|
+
pack() {
|
|
27
|
+
return txtHandler.pack(this);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const result = Object.create(base);
|
|
31
|
+
Object.assign(result, inputData, data, { "@text": text });
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
@@ -5,4 +5,5 @@ export function evaluateYaml(text: string, parent?: AsyncTree|null): Promise<Jso
|
|
|
5
5
|
export function parseYaml(text: string): JsonValue|AsyncTree;
|
|
6
6
|
export function toJson(obj: JsonValue | AsyncTree): Promise<string>;
|
|
7
7
|
export function toJsonValue(obj: any): Promise<JsonValue>;
|
|
8
|
+
export function toValue(obj: any, jsonValuesOnly?: boolean): Promise<JsonValue>;
|
|
8
9
|
export function toYaml(obj: JsonValue | AsyncTree): Promise<string>;
|