@weborigami/origami 0.6.16 → 0.7.0-beta.1
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/package.json +13 -13
- package/src/cli/cli.js +10 -5
- package/src/common/hashBytes.js +26 -0
- package/src/common/serialize.js +3 -0
- package/src/dev/OriCommandTransform.js +3 -3
- package/src/dev/changes.js +15 -52
- package/src/dev/debug2/debug2.js +0 -34
- package/src/dev/debug2/debugChild.js +73 -43
- package/src/dev/debug2/debugCommands.js +1 -0
- package/src/dev/debug2/debugParent.js +30 -42
- package/src/dev/debug2/debugTransform.js +32 -20
- package/src/dev/debug2/expressionTree.js +10 -6
- package/src/dev/debug2/oriEval.js +2 -2
- package/src/dev/dev.js +1 -0
- package/src/dev/explore.js +1 -0
- package/src/dev/help.yaml +29 -11
- package/src/dev/syscache.js +56 -0
- package/src/handlers/xml_handler.js +1 -1
- package/src/origami/{domNodeToObject.js → domObject.js} +16 -4
- package/src/origami/fetch.js +1 -22
- package/src/origami/hash.js +17 -0
- package/src/origami/htmlDom.js +21 -0
- package/src/origami/htmlParse.js +6 -13
- package/src/origami/mdHtml.js +1 -0
- package/src/origami/once.js +4 -1
- package/src/origami/ori.js +10 -11
- package/src/origami/origami.js +7 -1
- package/src/origami/randomFrom.js +15 -0
- package/src/origami/randomsFrom.js +65 -0
- package/src/origami/volatile.js +1 -0
- package/src/origami/xmlDom.js +32 -0
- package/src/origami/xmlParse.js +6 -24
- package/src/server/constructResponse.js +47 -12
- package/src/server/server.js +69 -42
- package/src/origami/project.js +0 -6
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
setParent,
|
|
5
5
|
Tree,
|
|
6
6
|
} from "@weborigami/async-tree";
|
|
7
|
-
import { evaluate,
|
|
7
|
+
import { evaluate, getGlobalsForTree } from "@weborigami/language";
|
|
8
8
|
import debugTransform from "./debugTransform.js";
|
|
9
9
|
|
|
10
10
|
// So we can distinguish different trees in the debugger
|
|
@@ -16,18 +16,22 @@ let version = 0;
|
|
|
16
16
|
*
|
|
17
17
|
* @param {Object} options
|
|
18
18
|
* @param {string} options.expression
|
|
19
|
-
* @param {
|
|
19
|
+
* @param {import("@weborigami/language").OrigamiFileMap} options.parent
|
|
20
20
|
*/
|
|
21
21
|
export default async function expressionTree(options) {
|
|
22
|
-
const { expression,
|
|
22
|
+
const { expression, parent } = options;
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
|
|
24
|
+
const globals = getGlobalsForTree(parent);
|
|
25
|
+
|
|
26
|
+
const source = {
|
|
27
|
+
text: expression,
|
|
28
|
+
cachePath: "_tree",
|
|
29
|
+
};
|
|
26
30
|
|
|
27
31
|
let maplike;
|
|
28
32
|
try {
|
|
29
33
|
// Evaluate the expression
|
|
30
|
-
maplike = await evaluate(
|
|
34
|
+
maplike = await evaluate(source, { globals, mode: "shell", parent });
|
|
31
35
|
if (isUnpackable(maplike)) {
|
|
32
36
|
maplike = await maplike.unpack();
|
|
33
37
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { trailingSlash, Tree } from "@weborigami/async-tree";
|
|
2
|
-
import { evaluate,
|
|
2
|
+
import { evaluate, getGlobalsForTree } from "@weborigami/language";
|
|
3
3
|
import debugTransform from "./debugTransform.js";
|
|
4
4
|
|
|
5
5
|
const mapParentToResult = new WeakMap();
|
|
@@ -16,7 +16,7 @@ const mapParentToResult = new WeakMap();
|
|
|
16
16
|
* counter to force reevaluation of the same expression.
|
|
17
17
|
*/
|
|
18
18
|
export default async function oriEval(parent) {
|
|
19
|
-
const globals =
|
|
19
|
+
const globals = getGlobalsForTree(parent);
|
|
20
20
|
return async (key) => {
|
|
21
21
|
const normalizedKey = trailingSlash.remove(key);
|
|
22
22
|
let result = mapParentToResult.get(parent);
|
package/src/dev/dev.js
CHANGED
|
@@ -18,5 +18,6 @@ export { default as log } from "./log.js";
|
|
|
18
18
|
export { default as serve } from "./serve.js";
|
|
19
19
|
export { default as stdin } from "./stdin.js";
|
|
20
20
|
export { default as svg } from "./svg.js";
|
|
21
|
+
export { default as syscache } from "./syscache.js";
|
|
21
22
|
export { default as version } from "./version.js";
|
|
22
23
|
export { default as watch } from "./watch.js";
|
package/src/dev/explore.js
CHANGED
|
@@ -44,6 +44,7 @@ async function getScopeData(scope) {
|
|
|
44
44
|
async function loadTemplate() {
|
|
45
45
|
const folderPath = path.resolve(fileURLToPath(import.meta.url), "..");
|
|
46
46
|
const folder = new OrigamiFileMap(folderPath);
|
|
47
|
+
await folder.initializeGlobals();
|
|
47
48
|
const templateFile = await folder.get("explore.ori");
|
|
48
49
|
const template = await Handlers.ori_handler.unpack(templateFile, {
|
|
49
50
|
parent: folder,
|
package/src/dev/help.yaml
CHANGED
|
@@ -13,12 +13,12 @@ Dev:
|
|
|
13
13
|
clear:
|
|
14
14
|
args: (tree)
|
|
15
15
|
description: Remove all values from the tree (alias of Tree.clear)
|
|
16
|
-
crawl:
|
|
17
|
-
args: (tree, base)
|
|
18
|
-
description: A tree of a site's discoverable resources
|
|
19
16
|
copy:
|
|
20
17
|
args: (source, target)
|
|
21
18
|
description: Copy the source tree to the target
|
|
19
|
+
crawl:
|
|
20
|
+
args: (tree, base)
|
|
21
|
+
description: A tree of a site's discoverable resources
|
|
22
22
|
debug:
|
|
23
23
|
args: (tree)
|
|
24
24
|
description: Add debug features to the tree
|
|
@@ -63,11 +63,20 @@ Origami:
|
|
|
63
63
|
document:
|
|
64
64
|
args: (text, [data])
|
|
65
65
|
description: Create a document object with the text and data
|
|
66
|
+
domObject:
|
|
67
|
+
args: (dom)
|
|
68
|
+
description: Convert a DOM tree to a plain JavaScript object
|
|
66
69
|
extension:
|
|
67
70
|
description: Helpers for working with file extensions
|
|
68
71
|
fetch:
|
|
69
72
|
args: (url, options)
|
|
70
73
|
description: Fetch a resource from a URL with support for extensions
|
|
74
|
+
hash:
|
|
75
|
+
args: (data)
|
|
76
|
+
description: A hex string hash of the data
|
|
77
|
+
htmlDom:
|
|
78
|
+
args: (html)
|
|
79
|
+
description: Parse HTML into a DOM tree
|
|
71
80
|
htmlEscape:
|
|
72
81
|
args: (text)
|
|
73
82
|
description: Escape HTML entities in the text
|
|
@@ -79,9 +88,6 @@ Origami:
|
|
|
79
88
|
inline:
|
|
80
89
|
args: (text)
|
|
81
90
|
description: Inline Origami expressions found in the text
|
|
82
|
-
htmlParse:
|
|
83
|
-
args: (html)
|
|
84
|
-
description: Parse HTML into a plain JavaScript object
|
|
85
91
|
json:
|
|
86
92
|
args: (obj)
|
|
87
93
|
description: Render the object in JSON format
|
|
@@ -99,9 +105,9 @@ Origami:
|
|
|
99
105
|
description: The outline structure of the markdown document
|
|
100
106
|
naturalOrder:
|
|
101
107
|
description: A comparison function for natural sort order
|
|
102
|
-
once:
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
# once:
|
|
109
|
+
# args: (fn)
|
|
110
|
+
# description: Run the function only once, return the same result
|
|
105
111
|
ori:
|
|
106
112
|
args: (text)
|
|
107
113
|
description: Evaluate the text as an Origami expression
|
|
@@ -110,6 +116,12 @@ Origami:
|
|
|
110
116
|
description: POST the given data to the URL
|
|
111
117
|
projectRoot:
|
|
112
118
|
description: The root folder for the current Origami project
|
|
119
|
+
randomFrom:
|
|
120
|
+
args: (data)
|
|
121
|
+
description: Returns a random value based on the data
|
|
122
|
+
randomsFrom:
|
|
123
|
+
args: (data)
|
|
124
|
+
description: Returns a function to produce random values based on the data
|
|
113
125
|
redirect:
|
|
114
126
|
args: (url, options)
|
|
115
127
|
description: Redirect to the given URL
|
|
@@ -139,12 +151,15 @@ Origami:
|
|
|
139
151
|
toFunction:
|
|
140
152
|
args: (obj)
|
|
141
153
|
description: Coerce a tree or packed function definition to a function
|
|
154
|
+
tsv:
|
|
155
|
+
args: (tree)
|
|
156
|
+
description: Render the tree as a TSV file
|
|
142
157
|
unpack:
|
|
143
158
|
args: (buffer)
|
|
144
159
|
description: Unpack the buffer into a usable form
|
|
145
|
-
|
|
160
|
+
xmlDom:
|
|
146
161
|
args: (xml)
|
|
147
|
-
description: Parse XML into a
|
|
162
|
+
description: Parse XML into a DOM tree
|
|
148
163
|
yaml:
|
|
149
164
|
args: (obj)
|
|
150
165
|
description: Render the object in YAML format
|
|
@@ -193,6 +208,9 @@ Tree:
|
|
|
193
208
|
clear:
|
|
194
209
|
args: (map)
|
|
195
210
|
description: Remove all values from the map
|
|
211
|
+
combine:
|
|
212
|
+
args: (tree1, tree2, combineFn)
|
|
213
|
+
description: Pairwise application of combineFn to the trees' values
|
|
196
214
|
concat:
|
|
197
215
|
args: (...trees)
|
|
198
216
|
description: Merge trees, renumbering numeric keys
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { activeProjectRoot, systemCache, volatile } from "@weborigami/language";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import * as YAMLModule from "yaml";
|
|
4
|
+
|
|
5
|
+
// The "yaml" package doesn't seem to provide a default export that the browser can
|
|
6
|
+
// recognize, so we have to handle two ways to accommodate Node and the browser.
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
const YAML = YAMLModule.default ?? YAMLModule.YAML;
|
|
9
|
+
|
|
10
|
+
export default function syscache() {
|
|
11
|
+
const projectRoot = activeProjectRoot.get();
|
|
12
|
+
|
|
13
|
+
/** @type {any} */
|
|
14
|
+
const entries = [...systemCache.entries()].map(([path, entry]) => {
|
|
15
|
+
const result = {};
|
|
16
|
+
if (entry.downstreams) {
|
|
17
|
+
result.downstreams = preferRelativePaths(projectRoot, entry.downstreams);
|
|
18
|
+
}
|
|
19
|
+
if (entry.upstreams) {
|
|
20
|
+
result.upstreams = preferRelativePaths(projectRoot, entry.upstreams);
|
|
21
|
+
}
|
|
22
|
+
return [preferRelativePath(projectRoot, path), result];
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Sort the entries by key
|
|
26
|
+
entries.sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
27
|
+
|
|
28
|
+
const result = volatile(new Map(entries));
|
|
29
|
+
|
|
30
|
+
// When served, render as YAML and preserve trailing slashes
|
|
31
|
+
Object.defineProperty(result, "pack", {
|
|
32
|
+
configurable: true,
|
|
33
|
+
enumerable: false,
|
|
34
|
+
get() {
|
|
35
|
+
return () => volatile(YAML.stringify(result));
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function preferRelativePath(projectRoot, inputPath) {
|
|
43
|
+
if (!path.isAbsolute(inputPath)) {
|
|
44
|
+
return inputPath;
|
|
45
|
+
}
|
|
46
|
+
const prefix = `${projectRoot.path}${path.sep}`;
|
|
47
|
+
if (!inputPath.startsWith(prefix)) {
|
|
48
|
+
return inputPath;
|
|
49
|
+
}
|
|
50
|
+
const relativePath = inputPath.slice(prefix.length);
|
|
51
|
+
return relativePath;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function preferRelativePaths(projectRoot, paths) {
|
|
55
|
+
return Array.from(paths).map((path) => preferRelativePath(projectRoot, path));
|
|
56
|
+
}
|
|
@@ -1,17 +1,29 @@
|
|
|
1
|
+
import { isUnpackable } from "@weborigami/async-tree";
|
|
2
|
+
|
|
1
3
|
const ELEMENT_NODE = 1;
|
|
2
4
|
const TEXT_NODE = 3;
|
|
3
5
|
const CDATA_SECTION_NODE = 4;
|
|
4
6
|
const DOCUMENT_NODE = 9;
|
|
5
7
|
const DOCUMENT_FRAGMENT_NODE = 11;
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Given a DOM node, return a plain object representation of it.
|
|
11
|
+
*/
|
|
12
|
+
export default async function domObject(input) {
|
|
13
|
+
if (isUnpackable(input)) {
|
|
14
|
+
input = await input.unpack();
|
|
15
|
+
}
|
|
16
|
+
return nodeObject(input);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function nodeObject(node) {
|
|
8
20
|
switch (node.nodeType) {
|
|
9
21
|
case DOCUMENT_NODE:
|
|
10
22
|
return {
|
|
11
23
|
name: "#document",
|
|
12
24
|
children: [...node.childNodes]
|
|
13
25
|
.filter((child) => !isWhitespaceOnly(child))
|
|
14
|
-
.map(
|
|
26
|
+
.map(nodeObject),
|
|
15
27
|
};
|
|
16
28
|
|
|
17
29
|
case DOCUMENT_FRAGMENT_NODE:
|
|
@@ -19,7 +31,7 @@ export default function domNodeToObject(node) {
|
|
|
19
31
|
name: "#document-fragment",
|
|
20
32
|
children: [...node.childNodes]
|
|
21
33
|
.filter((child) => !isWhitespaceOnly(child))
|
|
22
|
-
.map(
|
|
34
|
+
.map(nodeObject),
|
|
23
35
|
};
|
|
24
36
|
|
|
25
37
|
case ELEMENT_NODE: {
|
|
@@ -55,7 +67,7 @@ export default function domNodeToObject(node) {
|
|
|
55
67
|
result.text = text;
|
|
56
68
|
}
|
|
57
69
|
} else if (relevantChildren.length > 0) {
|
|
58
|
-
result.children = relevantChildren.map(
|
|
70
|
+
result.children = relevantChildren.map(nodeObject);
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
return result;
|
package/src/origami/fetch.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { handleExtension } from "@weborigami/language";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Extend the JavaScript `fetch` function to implicity return an ArrayBuffer
|
|
6
|
-
* with an unpack() method if the resource has a known file extension.
|
|
7
|
-
*/
|
|
8
|
-
export default async function fetchBuiltin(resource, options, state) {
|
|
9
|
-
resource = args.string(resource, "Origami.fetch");
|
|
10
|
-
const response = await fetch(resource, options);
|
|
11
|
-
if (!response.ok) {
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const value = await response.arrayBuffer();
|
|
16
|
-
|
|
17
|
-
const url = new URL(resource);
|
|
18
|
-
const key = url.pathname;
|
|
19
|
-
|
|
20
|
-
return handleExtension(value, key, state?.parent);
|
|
21
|
-
}
|
|
22
|
-
fetchBuiltin.needsState = true;
|
|
1
|
+
export { fetchAndHandleExtension as default } from "@weborigami/language";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import hashBytes from "../common/hashBytes.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given string or Uint8Array data, return a hex-encoded hash of that data.
|
|
5
|
+
*
|
|
6
|
+
* @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
|
|
7
|
+
*
|
|
8
|
+
* @param {Uint8Array|Stringlike} data
|
|
9
|
+
*/
|
|
10
|
+
export default function hash(data) {
|
|
11
|
+
const bytes = hashBytes(data);
|
|
12
|
+
const text = Array.from(bytes)
|
|
13
|
+
.slice(0, 20) // Limit to first 20 bytes (160 bits) for a shorter hash string
|
|
14
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
15
|
+
.join("");
|
|
16
|
+
return text;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { args } from "@weborigami/async-tree";
|
|
2
|
+
import loadJsDom from "../common/loadJsDom.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Return the DOM structure for the given HTML.
|
|
6
|
+
*
|
|
7
|
+
* @param {import("@weborigami/async-tree").Stringlike} html
|
|
8
|
+
*/
|
|
9
|
+
export default async function htmlDom(html) {
|
|
10
|
+
html = args.stringlike(html, "Origami.htmlDom");
|
|
11
|
+
const { JSDOM } = await loadJsDom();
|
|
12
|
+
let dom = JSDOM.fragment(html);
|
|
13
|
+
if (
|
|
14
|
+
(dom.nodeType === 9 || dom.nodeType === 11) &&
|
|
15
|
+
dom.children.length === 1
|
|
16
|
+
) {
|
|
17
|
+
// Document or DocumentFragment with a single child: return the child
|
|
18
|
+
dom = dom.children[0];
|
|
19
|
+
}
|
|
20
|
+
return dom;
|
|
21
|
+
}
|
package/src/origami/htmlParse.js
CHANGED
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { args } from "@weborigami/async-tree";
|
|
2
|
-
import
|
|
3
|
-
import domNodeToObject from "./domNodeToObject.js";
|
|
2
|
+
import htmlDom from "./htmlDom.js";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
* Return the DOM structure for the given HTML
|
|
5
|
+
* Return the DOM structure for the given HTML.
|
|
7
6
|
*
|
|
8
7
|
* @param {import("@weborigami/async-tree").Stringlike} html
|
|
9
8
|
*/
|
|
10
9
|
export default async function htmlParse(html) {
|
|
10
|
+
console.warn("Origami.htmlParse is deprecated. Use Origami.htmlDom instead.");
|
|
11
|
+
|
|
11
12
|
html = args.stringlike(html, "Origami.htmlParse");
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
let object = domNodeToObject(dom);
|
|
15
|
-
if (
|
|
16
|
-
(object.name === "#document" || object.name === "#document-fragment") &&
|
|
17
|
-
object.children.length === 1
|
|
18
|
-
) {
|
|
19
|
-
object = object.children[0];
|
|
20
|
-
}
|
|
21
|
-
return object;
|
|
13
|
+
const dom = await htmlDom(html);
|
|
14
|
+
return dom;
|
|
22
15
|
}
|
package/src/origami/mdHtml.js
CHANGED
package/src/origami/once.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { args } from "@weborigami/async-tree";
|
|
1
|
+
import { args, interop } from "@weborigami/async-tree";
|
|
2
2
|
|
|
3
3
|
const fnPromiseMap = new Map();
|
|
4
4
|
const codePromiseMap = new Map();
|
|
@@ -9,6 +9,9 @@ const codePromiseMap = new Map();
|
|
|
9
9
|
* @param {Function} fn
|
|
10
10
|
*/
|
|
11
11
|
export default async function once(fn) {
|
|
12
|
+
interop.warn(
|
|
13
|
+
`Now that Origami caches most results, Origami.once is no longer needed and will be removed in a future release. If you believe you have a need for it, please mention your use case in the Origami chat.`,
|
|
14
|
+
);
|
|
12
15
|
fn = args.fn(fn, "Origami.once");
|
|
13
16
|
const code = /** @type {any} */ (fn).code;
|
|
14
17
|
if (code) {
|
package/src/origami/ori.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
args,
|
|
3
|
+
assignPropertyDescriptors,
|
|
4
|
+
getRealmObjectPrototype,
|
|
5
|
+
Tree,
|
|
6
|
+
} from "@weborigami/async-tree";
|
|
7
|
+
import { compile, getGlobalsForTree } from "@weborigami/language";
|
|
3
8
|
import { toYaml } from "../common/serialize.js";
|
|
4
9
|
import * as dev from "../dev/dev.js";
|
|
5
10
|
|
|
@@ -17,18 +22,12 @@ export default async function ori(expression, options = {}) {
|
|
|
17
22
|
|
|
18
23
|
expression = args.stringlike(expression, "Origami.ori");
|
|
19
24
|
|
|
20
|
-
// Add Dev builtins as top-level globals
|
|
21
|
-
const globals = {
|
|
22
|
-
...(await projectGlobals(parent)),
|
|
23
|
-
...dev,
|
|
24
|
-
};
|
|
25
|
+
// Add Dev builtins as top-level globals; avoid invoking getters
|
|
26
|
+
const globals = assignPropertyDescriptors({}, getGlobalsForTree(parent), dev);
|
|
25
27
|
|
|
26
|
-
// Compile the expression
|
|
27
|
-
// passing a function to the `watch` builtin will always look the current
|
|
28
|
-
// value of things in scope.
|
|
28
|
+
// Compile the expression
|
|
29
29
|
const fn = compile.expression(expression, {
|
|
30
30
|
globals,
|
|
31
|
-
enableCaching: false,
|
|
32
31
|
mode: "shell",
|
|
33
32
|
parent,
|
|
34
33
|
});
|
package/src/origami/origami.js
CHANGED
|
@@ -3,7 +3,10 @@ export { default as help } from "../dev/help.js"; // Alias
|
|
|
3
3
|
export { default as basename } from "./basename.js";
|
|
4
4
|
export { default as csv } from "./csv.js";
|
|
5
5
|
export { default as document } from "./document.js";
|
|
6
|
+
export { default as domObject } from "./domObject.js";
|
|
6
7
|
export { default as fetch } from "./fetch.js";
|
|
8
|
+
export { default as hash } from "./hash.js";
|
|
9
|
+
export { default as htmlDom } from "./htmlDom.js";
|
|
7
10
|
export { default as htmlEscape } from "./htmlEscape.js";
|
|
8
11
|
export { default as htmlParse } from "./htmlParse.js";
|
|
9
12
|
export { default as format } from "./image/format.js";
|
|
@@ -21,8 +24,9 @@ export { default as once } from "./once.js";
|
|
|
21
24
|
export { default as ori } from "./ori.js";
|
|
22
25
|
export { default as pack } from "./pack.js";
|
|
23
26
|
export { default as post } from "./post.js";
|
|
24
|
-
export { default as project } from "./project.js";
|
|
25
27
|
export { default as projectRoot } from "./projectRoot.js";
|
|
28
|
+
export { default as randomFrom } from "./randomFrom.js";
|
|
29
|
+
export { default as randomsFrom } from "./randomsFrom.js";
|
|
26
30
|
export { default as redirect } from "./redirect.js";
|
|
27
31
|
export { default as repeat } from "./repeat.js";
|
|
28
32
|
export { default as rss } from "./rss.js";
|
|
@@ -34,6 +38,8 @@ export { default as static } from "./static.js";
|
|
|
34
38
|
export { default as string } from "./string.js";
|
|
35
39
|
export { default as tsv } from "./tsv.js";
|
|
36
40
|
export { default as unpack } from "./unpack.js";
|
|
41
|
+
export { default as volatile } from "./volatile.js";
|
|
42
|
+
export { default as xmlDom } from "./xmlDom.js";
|
|
37
43
|
export { default as xmlParse } from "./xmlParse.js";
|
|
38
44
|
export { default as yaml } from "./yaml.js";
|
|
39
45
|
export { default as yamlParse } from "./yamlParse.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import hashBytes from "../common/hashBytes.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a block of seed data, derive a pseudo-random 32-bit integer.
|
|
5
|
+
*
|
|
6
|
+
* @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
|
|
7
|
+
*
|
|
8
|
+
* @param {Uint8Array|Stringlike} data
|
|
9
|
+
* @return {number}
|
|
10
|
+
*/
|
|
11
|
+
export default function randomFrom(data) {
|
|
12
|
+
// Extract the first 32-bit integer from the hash to use as the random number
|
|
13
|
+
const hash = hashBytes(data);
|
|
14
|
+
return hash.readUInt32LE(0);
|
|
15
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import hashBytes from "../common/hashBytes.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a block of seed data, return a function that produces a sequence of
|
|
5
|
+
* pseudo-random 32-bit integers.
|
|
6
|
+
*
|
|
7
|
+
* @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
|
|
8
|
+
*
|
|
9
|
+
* @param {Uint8Array|Stringlike} data
|
|
10
|
+
* @return {function(): number}
|
|
11
|
+
*/
|
|
12
|
+
export default function randomsFrom(data) {
|
|
13
|
+
const hash = hashBytes(data);
|
|
14
|
+
|
|
15
|
+
// Extract four 32-bit integers from the hash to use as the initial state of
|
|
16
|
+
// the pseudo-random number generator
|
|
17
|
+
const a = hash.readUInt32LE(0);
|
|
18
|
+
const b = hash.readUInt32LE(4);
|
|
19
|
+
const c = hash.readUInt32LE(8);
|
|
20
|
+
const d = hash.readUInt32LE(12);
|
|
21
|
+
|
|
22
|
+
const prng = xoshiro128ss(a, b, c, d);
|
|
23
|
+
return prng;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Rotate left (circular left shift) for 32-bit integers
|
|
27
|
+
function rotl(x, k) {
|
|
28
|
+
return ((x << k) | (x >>> (32 - k))) >>> 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Pseudo-random number generator based on the xoshiro128** algorithm. See
|
|
33
|
+
* the 256-bit variant: https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
|
|
34
|
+
*
|
|
35
|
+
* Unlike a typical implementation, this directly returns a 32-bit integer
|
|
36
|
+
* instead of a float.
|
|
37
|
+
*
|
|
38
|
+
* @param {number} a
|
|
39
|
+
* @param {number} b
|
|
40
|
+
* @param {number} c
|
|
41
|
+
* @param {number} d
|
|
42
|
+
* @returns {function(): number}
|
|
43
|
+
*/
|
|
44
|
+
function xoshiro128ss(a, b, c, d) {
|
|
45
|
+
let s0 = a >>> 0;
|
|
46
|
+
let s1 = b >>> 0;
|
|
47
|
+
let s2 = c >>> 0;
|
|
48
|
+
let s3 = d >>> 0;
|
|
49
|
+
|
|
50
|
+
return function () {
|
|
51
|
+
const result = (rotl(Math.imul(s1, 5), 7) * 9) >>> 0;
|
|
52
|
+
|
|
53
|
+
const t = (s1 << 9) >>> 0;
|
|
54
|
+
|
|
55
|
+
s2 ^= s0;
|
|
56
|
+
s3 ^= s1;
|
|
57
|
+
s1 ^= s2;
|
|
58
|
+
s0 ^= s3;
|
|
59
|
+
|
|
60
|
+
s2 ^= t;
|
|
61
|
+
s3 = rotl(s3, 11);
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { volatile as default } from "@weborigami/language";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { args } from "@weborigami/async-tree";
|
|
2
|
+
import loadJsDom from "../common/loadJsDom.js";
|
|
3
|
+
|
|
4
|
+
let parser;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return the DOM for the given XML.
|
|
8
|
+
*
|
|
9
|
+
* @param {import("@weborigami/async-tree").Stringlike} xml
|
|
10
|
+
*/
|
|
11
|
+
export default async function xmlDom(xml) {
|
|
12
|
+
xml = args.stringlike(xml, "Origami.xmlDom");
|
|
13
|
+
const parser = await getParser();
|
|
14
|
+
let dom = parser.parseFromString(xml, "application/xml");
|
|
15
|
+
if (
|
|
16
|
+
(dom.nodeType === 9 || dom.nodeType === 11) &&
|
|
17
|
+
dom.children.length === 1
|
|
18
|
+
) {
|
|
19
|
+
// Document or DocumentFragment with a single child: return the child
|
|
20
|
+
dom = dom.children[0];
|
|
21
|
+
}
|
|
22
|
+
return dom;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function getParser() {
|
|
26
|
+
if (!parser) {
|
|
27
|
+
const { JSDOM } = await loadJsDom();
|
|
28
|
+
const dom = new JSDOM();
|
|
29
|
+
parser = new dom.window.DOMParser();
|
|
30
|
+
}
|
|
31
|
+
return parser;
|
|
32
|
+
}
|
package/src/origami/xmlParse.js
CHANGED
|
@@ -1,33 +1,15 @@
|
|
|
1
1
|
import { args } from "@weborigami/async-tree";
|
|
2
|
-
import
|
|
3
|
-
import domNodeToObject from "./domNodeToObject.js";
|
|
4
|
-
|
|
5
|
-
let parser;
|
|
2
|
+
import xmlDom from "./xmlDom.js";
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
|
-
* Return the DOM for the given XML
|
|
5
|
+
* Return the DOM structure for the given XML.
|
|
9
6
|
*
|
|
10
7
|
* @param {import("@weborigami/async-tree").Stringlike} xml
|
|
11
8
|
*/
|
|
12
9
|
export default async function xmlParse(xml) {
|
|
13
|
-
|
|
14
|
-
const parser = await getParser();
|
|
15
|
-
const dom = parser.parseFromString(xml, "application/xml");
|
|
16
|
-
let object = domNodeToObject(dom);
|
|
17
|
-
if (
|
|
18
|
-
(object.name === "#document" || object.name === "#document-fragment") &&
|
|
19
|
-
object.children.length === 1
|
|
20
|
-
) {
|
|
21
|
-
object = object.children[0];
|
|
22
|
-
}
|
|
23
|
-
return object;
|
|
24
|
-
}
|
|
10
|
+
console.warn("Origami.xmlParse is deprecated. Use Origami.xmlDom instead.");
|
|
25
11
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const dom = new JSDOM();
|
|
30
|
-
parser = new dom.window.DOMParser();
|
|
31
|
-
}
|
|
32
|
-
return parser;
|
|
12
|
+
xml = args.stringlike(xml, "Origami.xmlParse");
|
|
13
|
+
const dom = await xmlDom(xml);
|
|
14
|
+
return dom;
|
|
33
15
|
}
|