@weborigami/origami 0.0.71-beta.1 → 0.0.71
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/exports.js +2 -7
- package/package.json +4 -4
- package/src/builtins/@calendarTree.js +1 -5
- package/src/builtins/@code.js +1 -1
- package/src/builtins/@crawl.js +1 -2
- package/src/builtins/{@keysTree.js → @exploreSite.js} +2 -2
- package/src/builtins/@sitemap.js +2 -4
- package/src/builtins/@svg.js +2 -1
- package/src/builtins/@unpack.js +1 -1
- package/src/crawler/crawlResources.js +8 -4
- package/src/crawler/findPaths.js +12 -4
- package/src/misc/getTreeArgument.js +1 -2
- package/src/misc/treeDot.js +1 -1
- package/src/server/constructResponse.js +31 -37
- package/src/builtins/@constructor.js +0 -13
- package/src/builtins/@exceptions.js +0 -45
- package/src/builtins/@invoke.js +0 -36
- package/src/builtins/@mdTree.js +0 -69
- package/src/builtins/@mkdir.js +0 -3
- package/src/builtins/@perf.js +0 -19
package/exports/exports.js
CHANGED
|
@@ -4,7 +4,7 @@ export { default as basename } from "../src/builtins/@basename.js";
|
|
|
4
4
|
export { default as breakpoint } from "../src/builtins/@breakpoint.js";
|
|
5
5
|
export { default as builtins } from "../src/builtins/@builtins.js";
|
|
6
6
|
export { default as cache } from "../src/builtins/@cache.js";
|
|
7
|
-
export
|
|
7
|
+
export * from "../src/builtins/@calendarTree.js";
|
|
8
8
|
export { default as changes } from "../src/builtins/@changes.js";
|
|
9
9
|
export { default as clean } from "../src/builtins/@clean.js";
|
|
10
10
|
export { default as code } from "../src/builtins/@code.js";
|
|
@@ -23,8 +23,8 @@ export { default as deepValues } from "../src/builtins/@deepValues.js";
|
|
|
23
23
|
export { default as defineds } from "../src/builtins/@defineds.js";
|
|
24
24
|
export { default as document } from "../src/builtins/@document.js";
|
|
25
25
|
export { default as equals } from "../src/builtins/@equals.js";
|
|
26
|
-
export { default as exceptions } from "../src/builtins/@exceptions.js";
|
|
27
26
|
export { default as explore } from "../src/builtins/@explore.js";
|
|
27
|
+
export { default as exploreSite } from "../src/builtins/@exploreSite.js";
|
|
28
28
|
export { default as fetch } from "../src/builtins/@fetch.js";
|
|
29
29
|
export { default as files } from "../src/builtins/@files.js";
|
|
30
30
|
export { default as filter } from "../src/builtins/@filter.js";
|
|
@@ -46,13 +46,11 @@ export { default as index } from "../src/builtins/@index.js";
|
|
|
46
46
|
export { default as inherited } from "../src/builtins/@inherited.js";
|
|
47
47
|
export { default as inline } from "../src/builtins/@inline.js";
|
|
48
48
|
export { default as inners } from "../src/builtins/@inners.js";
|
|
49
|
-
export { default as invoke } from "../src/builtins/@invoke.js";
|
|
50
49
|
export { default as js } from "../src/builtins/@js.js";
|
|
51
50
|
export { default as json } from "../src/builtins/@json.js";
|
|
52
51
|
export { default as jsonKeys } from "../src/builtins/@jsonKeys.js";
|
|
53
52
|
export { default as jsonParse } from "../src/builtins/@jsonParse.js";
|
|
54
53
|
export { default as keys } from "../src/builtins/@keys.js";
|
|
55
|
-
export { default as keysTree } from "../src/builtins/@keysTree.js";
|
|
56
54
|
export { default as length } from "../src/builtins/@length.js";
|
|
57
55
|
export { default as log } from "../src/builtins/@log.js";
|
|
58
56
|
export { default as map } from "../src/builtins/@map.js";
|
|
@@ -60,9 +58,7 @@ export { default as mapFn } from "../src/builtins/@mapFn.js";
|
|
|
60
58
|
export { default as match } from "../src/builtins/@match.js";
|
|
61
59
|
export * from "../src/builtins/@math.js";
|
|
62
60
|
export { default as mdHtml } from "../src/builtins/@mdHtml.js";
|
|
63
|
-
export { default as mdTree } from "../src/builtins/@mdTree.js";
|
|
64
61
|
export { default as merge } from "../src/builtins/@merge.js";
|
|
65
|
-
export { default as mkdir } from "../src/builtins/@mkdir.js";
|
|
66
62
|
export * from "../src/builtins/@naturalOrder.js";
|
|
67
63
|
export { default as node } from "../src/builtins/@node.js";
|
|
68
64
|
export { default as not } from "../src/builtins/@not.js";
|
|
@@ -74,7 +70,6 @@ export { default as package } from "../src/builtins/@package.js";
|
|
|
74
70
|
export { default as paginate } from "../src/builtins/@paginate.js";
|
|
75
71
|
export { default as paginateFn } from "../src/builtins/@paginateFn.js";
|
|
76
72
|
export { default as parent } from "../src/builtins/@parent.js";
|
|
77
|
-
export { default as perf } from "../src/builtins/@perf.js";
|
|
78
73
|
export { default as plain } from "../src/builtins/@plain.js";
|
|
79
74
|
export { default as post } from "../src/builtins/@post.js";
|
|
80
75
|
export { default as project } from "../src/builtins/@project.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/origami",
|
|
3
|
-
"version": "0.0.71
|
|
3
|
+
"version": "0.0.71",
|
|
4
4
|
"description": "Web Origami language, CLI, framework, and server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"typescript": "5.6.2"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@weborigami/async-tree": "0.0.71
|
|
21
|
-
"@weborigami/language": "0.0.71
|
|
22
|
-
"@weborigami/types": "0.0.71
|
|
20
|
+
"@weborigami/async-tree": "0.0.71",
|
|
21
|
+
"@weborigami/language": "0.0.71",
|
|
22
|
+
"@weborigami/types": "0.0.71",
|
|
23
23
|
"exif-parser": "0.1.12",
|
|
24
24
|
"graphviz-wasm": "3.0.2",
|
|
25
25
|
"highlight.js": "11.10.0",
|
package/src/builtins/@code.js
CHANGED
|
@@ -9,7 +9,7 @@ import getTreeArgument from "../misc/getTreeArgument.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export default async function code(value) {
|
|
11
11
|
if (value === undefined) {
|
|
12
|
-
value = await getTreeArgument(this, arguments, value, "@
|
|
12
|
+
value = await getTreeArgument(this, arguments, value, "@code");
|
|
13
13
|
}
|
|
14
14
|
if (value === undefined) {
|
|
15
15
|
return undefined;
|
package/src/builtins/@crawl.js
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
} from "@weborigami/async-tree";
|
|
9
9
|
import { InvokeFunctionsTransform } from "@weborigami/language";
|
|
10
10
|
import crawlResources from "../crawler/crawlResources.js";
|
|
11
|
-
import { normalizeKeys } from "../crawler/utilities.js";
|
|
12
11
|
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -74,7 +73,7 @@ export default async function crawlBuiltin(treelike, baseHref) {
|
|
|
74
73
|
// Add indirect resource functions to the resource tree. When requested,
|
|
75
74
|
// these functions will obtain the resource from the original site.
|
|
76
75
|
for (const resourcePath of resourcePaths) {
|
|
77
|
-
const resourceKeys =
|
|
76
|
+
const resourceKeys = keysFromPath(resourcePath);
|
|
78
77
|
const fn = () => {
|
|
79
78
|
return Tree.traverse(tree, ...resourceKeys);
|
|
80
79
|
};
|
|
@@ -10,7 +10,7 @@ import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
|
|
|
10
10
|
* @param {string} host
|
|
11
11
|
* @param {...string} keys
|
|
12
12
|
*/
|
|
13
|
-
export default function
|
|
14
|
-
assertTreeIsDefined(this, "
|
|
13
|
+
export default function exploreSite(host, ...keys) {
|
|
14
|
+
assertTreeIsDefined(this, "exploreSite");
|
|
15
15
|
return ops.explorableSite.call(this, host, ...keys);
|
|
16
16
|
}
|
package/src/builtins/@sitemap.js
CHANGED
|
@@ -6,12 +6,10 @@ import fileTypeOrigami from "./ori_handler.js";
|
|
|
6
6
|
|
|
7
7
|
const templateText = `(urls) => \`<?xml version="1.0" encoding="UTF-8"?>
|
|
8
8
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
9
|
-
\${ @map(urls, (url) => \`
|
|
10
|
-
<url>
|
|
9
|
+
\${ @map(urls, (url) => \` <url>
|
|
11
10
|
<loc>\${ url }</loc>
|
|
12
11
|
</url>
|
|
13
|
-
\`) }
|
|
14
|
-
</urlset>
|
|
12
|
+
\`) }</urlset>
|
|
15
13
|
\`
|
|
16
14
|
`;
|
|
17
15
|
|
package/src/builtins/@svg.js
CHANGED
|
@@ -20,7 +20,7 @@ export default async function svg(treelike, options = {}) {
|
|
|
20
20
|
await graphviz.loadWASM();
|
|
21
21
|
graphvizLoaded = true;
|
|
22
22
|
}
|
|
23
|
-
const tree = await getTreeArgument(this, arguments, treelike, "@svg");
|
|
23
|
+
const tree = await getTreeArgument(this, arguments, treelike, "@svg", true);
|
|
24
24
|
const dotText = await dot.call(this, tree, options);
|
|
25
25
|
if (dotText === undefined) {
|
|
26
26
|
return undefined;
|
|
@@ -28,6 +28,7 @@ export default async function svg(treelike, options = {}) {
|
|
|
28
28
|
const svgText = await graphviz.layout(dotText, "svg");
|
|
29
29
|
/** @type {any} */
|
|
30
30
|
const result = new String(svgText);
|
|
31
|
+
result.mediaType = "image/svg+xml";
|
|
31
32
|
result.unpack = () => tree;
|
|
32
33
|
return result;
|
|
33
34
|
}
|
package/src/builtins/@unpack.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
Tree,
|
|
6
6
|
} from "@weborigami/async-tree";
|
|
7
7
|
import findPaths from "./findPaths.js";
|
|
8
|
-
import { normalizeKeys } from "./utilities.js";
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Crawl the paths for the given tree, starting at the given base URL, and yield
|
|
@@ -131,15 +130,20 @@ async function processPath(tree, path, baseUrl) {
|
|
|
131
130
|
|
|
132
131
|
// Traverse tree to get value.
|
|
133
132
|
let value = await Tree.traverse(tree, ...keys);
|
|
134
|
-
const normalizedKeys =
|
|
133
|
+
const normalizedKeys = keys.slice();
|
|
135
134
|
let normalizedPath = path;
|
|
136
135
|
if (Tree.isTreelike(value)) {
|
|
137
|
-
// Path is actually a directory
|
|
138
|
-
|
|
136
|
+
// Path is actually a directory. See if we can get the empty string or
|
|
137
|
+
// "index.html".
|
|
138
|
+
value =
|
|
139
|
+
(await Tree.traverse(value, "")) ??
|
|
140
|
+
(await Tree.traverse(value, "index.html"));
|
|
139
141
|
if (value !== undefined) {
|
|
140
142
|
if (path.length > 0) {
|
|
141
143
|
// Mark the path as ending in a slash
|
|
142
144
|
normalizedPath = trailingSlash.add(path);
|
|
145
|
+
const key = normalizedKeys.pop();
|
|
146
|
+
normalizedKeys.push(trailingSlash.add(key));
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
// Add index.html to keys if it's not already there
|
package/src/crawler/findPaths.js
CHANGED
|
@@ -16,7 +16,11 @@ function filterPaths(paths, baseUrl, localPath) {
|
|
|
16
16
|
// fumble the use of http and https, treating them interchangeably.
|
|
17
17
|
const relativePaths = absoluteUrls.map((url) => {
|
|
18
18
|
if (url.host === baseUrl.host && url.pathname.startsWith(basePathname)) {
|
|
19
|
-
|
|
19
|
+
const path = url.pathname.slice(basePathname.length);
|
|
20
|
+
// The process of creating the URLs will have escaped characters. We
|
|
21
|
+
// remove them. This has the side-effect of removing them if they existed
|
|
22
|
+
// in the original path; it would be better if we avoided that.
|
|
23
|
+
return decodeURIComponent(path);
|
|
20
24
|
} else {
|
|
21
25
|
return null;
|
|
22
26
|
}
|
|
@@ -39,7 +43,6 @@ export default function findPaths(value, key, baseUrl, localPath) {
|
|
|
39
43
|
// We guess the value is HTML is if its key has an .html extension or
|
|
40
44
|
// doesn't have an extension, or the value starts with `<`.
|
|
41
45
|
const ext = key ? extname(key).toLowerCase() : "";
|
|
42
|
-
const maybeHtml = ext === "" || text?.trim().startsWith("<");
|
|
43
46
|
let foundPaths;
|
|
44
47
|
if (ext === ".html" || ext === ".htm" || ext === ".xhtml") {
|
|
45
48
|
foundPaths = findPathsInHtml(text);
|
|
@@ -53,7 +56,8 @@ export default function findPaths(value, key, baseUrl, localPath) {
|
|
|
53
56
|
foundPaths = findPathsInRobotsTxt(text);
|
|
54
57
|
} else if (key === "sitemap.xml") {
|
|
55
58
|
foundPaths = findPathsInSitemapXml(text);
|
|
56
|
-
} else if (
|
|
59
|
+
} else if (ext === "" && text?.trim().startsWith("<")) {
|
|
60
|
+
// Probably HTML
|
|
57
61
|
foundPaths = findPathsInHtml(text);
|
|
58
62
|
} else {
|
|
59
63
|
// Doesn't have an extension we want to process
|
|
@@ -90,7 +94,7 @@ function findPathsInCss(css) {
|
|
|
90
94
|
while ((match = urlRegex.exec(css))) {
|
|
91
95
|
const href = normalizeHref(match.groups?.href);
|
|
92
96
|
if (href) {
|
|
93
|
-
resourcePaths.push();
|
|
97
|
+
resourcePaths.push(href);
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -217,6 +221,10 @@ function findPathsInHtml(html) {
|
|
|
217
221
|
}
|
|
218
222
|
}
|
|
219
223
|
|
|
224
|
+
// Also look for JS `import` statements that might be in <script type="module"> tags.
|
|
225
|
+
const jsResults = findPathsInJs(html);
|
|
226
|
+
crawlablePaths.push(...jsResults.crawlablePaths);
|
|
227
|
+
|
|
220
228
|
return { crawlablePaths, resourcePaths };
|
|
221
229
|
}
|
|
222
230
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Tree, isUnpackable } from "@weborigami/async-tree";
|
|
2
|
-
import { isTreelike } from "@weborigami/async-tree/src/Tree.js";
|
|
3
2
|
import assertTreeIsDefined from "./assertTreeIsDefined.js";
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -34,7 +33,7 @@ export default async function getTreeArgument(
|
|
|
34
33
|
if (isUnpackable(treelike)) {
|
|
35
34
|
treelike = await treelike.unpack();
|
|
36
35
|
}
|
|
37
|
-
if (isTreelike(treelike)) {
|
|
36
|
+
if (Tree.isTreelike(treelike)) {
|
|
38
37
|
let tree = Tree.from(treelike, { deep });
|
|
39
38
|
// If the tree was created from a treelike object and does not yet have a
|
|
40
39
|
// parent, make the current tree its parent.
|
package/src/misc/treeDot.js
CHANGED
|
@@ -20,7 +20,7 @@ import { keySymbol } from "../common/utilities.js";
|
|
|
20
20
|
* @param {PlainObject} [options]
|
|
21
21
|
*/
|
|
22
22
|
export default async function dot(treelike, options = {}) {
|
|
23
|
-
const tree = Tree.from(treelike);
|
|
23
|
+
const tree = Tree.from(treelike, { deep: true });
|
|
24
24
|
const rootLabel = tree[keySymbol] ?? "";
|
|
25
25
|
const treeArcs = await statements(tree, "", rootLabel, options);
|
|
26
26
|
return `digraph g {
|
|
@@ -10,8 +10,6 @@ import * as serialize from "../common/serialize.js";
|
|
|
10
10
|
import { toString } from "../common/utilities.js";
|
|
11
11
|
import { mediaTypeForExtension } from "./mediaTypes.js";
|
|
12
12
|
|
|
13
|
-
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
|
14
|
-
|
|
15
13
|
/**
|
|
16
14
|
* Given a resource that was returned from a route, construct an appropriate
|
|
17
15
|
* HTTP Response indicating what should be sent to the client. Return null
|
|
@@ -78,22 +76,18 @@ export default async function constructResponse(request, resource) {
|
|
|
78
76
|
mediaType = "text/yaml";
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Assume text is encoded in UTF-8.
|
|
96
|
-
if (SiteTree.mediaTypeIsText(mediaType)) {
|
|
79
|
+
// By default, the body will be the resource we got
|
|
80
|
+
let body = resource;
|
|
81
|
+
if (!mediaType) {
|
|
82
|
+
// Maybe it's HTML?
|
|
83
|
+
const text = toString(resource);
|
|
84
|
+
if (text && maybeHtml(text)) {
|
|
85
|
+
mediaType = "text/html";
|
|
86
|
+
body = text;
|
|
87
|
+
}
|
|
88
|
+
} else if (mediaType && SiteTree.mediaTypeIsText(mediaType)) {
|
|
89
|
+
// Assume text is encoded in UTF-8.
|
|
90
|
+
body = toString(resource);
|
|
97
91
|
mediaType += "; charset=utf-8";
|
|
98
92
|
}
|
|
99
93
|
|
|
@@ -108,26 +102,26 @@ export default async function constructResponse(request, resource) {
|
|
|
108
102
|
return null;
|
|
109
103
|
}
|
|
110
104
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
},
|
|
115
|
-
});
|
|
105
|
+
const options = mediaType ? { headers: { "Content-Type": mediaType } } : {};
|
|
106
|
+
const response = new Response(body, options);
|
|
107
|
+
return response;
|
|
116
108
|
}
|
|
117
109
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (object instanceof ArrayBuffer) {
|
|
126
|
-
// Convert to Uint8Array so we can write it to the Response.
|
|
127
|
-
return new Uint8Array(object);
|
|
128
|
-
} else if (object instanceof TypedArray) {
|
|
129
|
-
// Return typed arrays as is.
|
|
130
|
-
return object;
|
|
110
|
+
// Return true if the resource appears to represent HTML
|
|
111
|
+
function maybeHtml(text) {
|
|
112
|
+
if (!text) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (text.startsWith("<!DOCTYPE html>")) {
|
|
116
|
+
return true;
|
|
131
117
|
}
|
|
132
|
-
|
|
118
|
+
// Check if the text starts with an HTML tag.
|
|
119
|
+
// - start with possible whitespace
|
|
120
|
+
// - followed by '<'
|
|
121
|
+
// - followed by a letter
|
|
122
|
+
// - followed by letters, digits, hyphens, underscores, colons, or periods
|
|
123
|
+
// - followed by '>', or
|
|
124
|
+
// - followed by whitespace, anything that's not '>', then a '>'
|
|
125
|
+
const tagRegex = /^\s*<[a-zA-Z][a-zA-Z0-9-_:\.]+(>|[\s]+[^>]*>)/;
|
|
126
|
+
return tagRegex.test(text);
|
|
133
127
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ops } from "@weborigami/language";
|
|
2
|
-
import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
6
|
-
*
|
|
7
|
-
* @this {AsyncTree|null}
|
|
8
|
-
* @param {...any} keys
|
|
9
|
-
*/
|
|
10
|
-
export default function constructor(...keys) {
|
|
11
|
-
assertTreeIsDefined(this, "constructor");
|
|
12
|
-
return ops.constructor.call(this, ...keys);
|
|
13
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Tree } from "@weborigami/async-tree";
|
|
2
|
-
import getTreeArgument from "../misc/getTreeArgument.js";
|
|
3
|
-
import defineds from "./@defineds.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
7
|
-
* @typedef {import("@weborigami/async-tree").Treelike} Treelike
|
|
8
|
-
* @this {AsyncTree|null}
|
|
9
|
-
* @param {Treelike} treelike
|
|
10
|
-
*/
|
|
11
|
-
export default async function exceptions(treelike) {
|
|
12
|
-
const tree = await getTreeArgument(this, arguments, treelike, "@exceptions");
|
|
13
|
-
const exceptionsTree = new ExceptionsTree(tree);
|
|
14
|
-
return defineds.call(this, exceptionsTree);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @implements {AsyncTree}
|
|
19
|
-
*/
|
|
20
|
-
class ExceptionsTree {
|
|
21
|
-
constructor(tree) {
|
|
22
|
-
this.tree = tree;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async get(key) {
|
|
26
|
-
try {
|
|
27
|
-
const value = await this.tree.get(key);
|
|
28
|
-
return Tree.isAsyncTree(value)
|
|
29
|
-
? Reflect.construct(this.constructor, [value])
|
|
30
|
-
: undefined;
|
|
31
|
-
} catch (/** @type {any} */ error) {
|
|
32
|
-
return error.name && error.message
|
|
33
|
-
? `${error.name}: ${error.message}`
|
|
34
|
-
: error.name ?? error.message ?? error;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async keys() {
|
|
39
|
-
return this.tree.keys();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
exceptions.usage = `@exceptions tree\tReturn a tree of exceptions thrown in the tree`;
|
|
44
|
-
exceptions.documentation =
|
|
45
|
-
"https://weborigami.org/cli/builtins.html#exceptions";
|
package/src/builtins/@invoke.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { isUnpackable } from "@weborigami/async-tree";
|
|
2
|
-
import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Invoke the given text as an Origami function.
|
|
6
|
-
*
|
|
7
|
-
* This built-in exists to facilitate executing an Origami file as a script via
|
|
8
|
-
* a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) directive.
|
|
9
|
-
*
|
|
10
|
-
* You can execute a foo.ori file as a script by adding the following shebang
|
|
11
|
-
* directive to the top of the file:
|
|
12
|
-
*
|
|
13
|
-
* ```sh
|
|
14
|
-
* #!/usr/bin/env ori @invoke
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* Then mark the file as executable:
|
|
18
|
-
*
|
|
19
|
-
* ```sh
|
|
20
|
-
* chmod +x foo.ori
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* @this {import("@weborigami/types").AsyncTree|null}
|
|
24
|
-
*/
|
|
25
|
-
export default async function invoke(fn) {
|
|
26
|
-
assertTreeIsDefined(this, "invoke");
|
|
27
|
-
if (fn === undefined) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
"An Origami function was called with an initial argument, but its value is undefined."
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
if (isUnpackable(fn)) {
|
|
33
|
-
fn = await fn.unpack();
|
|
34
|
-
}
|
|
35
|
-
return typeof fn === "function" ? fn.call(this) : fn;
|
|
36
|
-
}
|
package/src/builtins/@mdTree.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { toString } from "../common/utilities.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns the tree structure of a markdown document.
|
|
5
|
-
*
|
|
6
|
-
* @typedef {import("@weborigami/async-tree").StringLike} StringLike
|
|
7
|
-
* @typedef {import("@weborigami/async-tree").Unpackable<StringLike>}
|
|
8
|
-
* UnpackableStringlike
|
|
9
|
-
*
|
|
10
|
-
* @this {import("@weborigami/types").AsyncTree|null|void}
|
|
11
|
-
* @param {StringLike|UnpackableStringlike} input
|
|
12
|
-
*/
|
|
13
|
-
export default function mdStructure(input) {
|
|
14
|
-
const markdown = toString(input);
|
|
15
|
-
if (markdown === null) {
|
|
16
|
-
throw new Error("No markdown text provided.");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// The document acts as an entry for heading level zero. All level one
|
|
20
|
-
// headings will end up as its children.
|
|
21
|
-
const document = {};
|
|
22
|
-
const activeHeadings = [document];
|
|
23
|
-
|
|
24
|
-
// Split the text by lines that contain markdown headings.
|
|
25
|
-
const lines = markdown.split("\n");
|
|
26
|
-
lines.forEach((line) => {
|
|
27
|
-
const match = line.match(/^(?<levelMarkers>#{1,6})\s(?<heading>.*)$/);
|
|
28
|
-
if (!match?.groups) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const { levelMarkers, heading } = match.groups;
|
|
32
|
-
const level = levelMarkers.length;
|
|
33
|
-
|
|
34
|
-
// If we've gone up a level (or more), pop completed entries off the stack.
|
|
35
|
-
while (activeHeadings.length > level) {
|
|
36
|
-
activeHeadings.pop();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// If we've skipped a level (or more), add intermediate entries using
|
|
40
|
-
// symbols to avoid name collisions.
|
|
41
|
-
while (activeHeadings.length < level) {
|
|
42
|
-
const entry = {};
|
|
43
|
-
const parentEntry = activeHeadings[activeHeadings.length - 1];
|
|
44
|
-
parentEntry[Symbol()] = entry;
|
|
45
|
-
activeHeadings.push(entry);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Add a new entry to the list of children under construction.
|
|
49
|
-
const entry = {};
|
|
50
|
-
const parentEntry = activeHeadings[activeHeadings.length - 1];
|
|
51
|
-
parentEntry[heading] = entry;
|
|
52
|
-
activeHeadings.push(entry);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return pruneEmptyObjects(document) ?? {};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Replace empty objects in the tree with nulls.
|
|
59
|
-
function pruneEmptyObjects(tree) {
|
|
60
|
-
const keys = [...Object.keys(tree), ...Object.getOwnPropertySymbols(tree)];
|
|
61
|
-
if (keys.length === 0) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
const result = {};
|
|
65
|
-
for (const key of keys) {
|
|
66
|
-
result[key] = pruneEmptyObjects(tree[key]);
|
|
67
|
-
}
|
|
68
|
-
return result;
|
|
69
|
-
}
|
package/src/builtins/@mkdir.js
DELETED
package/src/builtins/@perf.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import assertTreeIsDefined from "../misc/assertTreeIsDefined.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Return the number of milliseconds required to execute the given function the
|
|
5
|
-
* specified number of times.
|
|
6
|
-
*
|
|
7
|
-
* @this {import("@weborigami/types").AsyncTree|null}
|
|
8
|
-
* @param {Function} fn
|
|
9
|
-
*/
|
|
10
|
-
export default async function perf(fn, count = 1) {
|
|
11
|
-
assertTreeIsDefined(this, "perf");
|
|
12
|
-
const start = performance.now();
|
|
13
|
-
for (let i = 0; i < count; i++) {
|
|
14
|
-
await fn.call(this);
|
|
15
|
-
}
|
|
16
|
-
const end = performance.now();
|
|
17
|
-
const milliseconds = Math.round(end - start);
|
|
18
|
-
return `${milliseconds} ms`;
|
|
19
|
-
}
|