@weborigami/origami 0.6.16 → 0.6.17
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 +3 -3
- package/src/common/hashBytes.js +26 -0
- package/src/dev/changes2.js +38 -0
- package/src/dev/dev.js +1 -0
- package/src/dev/help.yaml +15 -3
- package/src/origami/hash.js +17 -0
- package/src/origami/mdHtml.js +1 -0
- package/src/origami/origami.js +3 -0
- package/src/origami/randomFrom.js +15 -0
- package/src/origami/randomsFrom.js +65 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/origami",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"description": "Web Origami language, CLI, framework, and server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@hpcc-js/wasm-graphviz": "^1.21.0",
|
|
21
|
-
"@weborigami/async-tree": "0.6.
|
|
21
|
+
"@weborigami/async-tree": "0.6.17",
|
|
22
22
|
"@weborigami/json-feed-to-rss": "1.0.1",
|
|
23
|
-
"@weborigami/language": "0.6.
|
|
23
|
+
"@weborigami/language": "0.6.17",
|
|
24
24
|
"css-tree": "3.1.0",
|
|
25
25
|
"highlight.js": "11.11.1",
|
|
26
26
|
"jsdom": "28.1.0",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { toString } from "@weborigami/async-tree";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Given data, return a 256-bit hash of that data. The data can be a string or a
|
|
6
|
+
* Uint8Array.
|
|
7
|
+
*
|
|
8
|
+
* @typedef {import("@weborigami/async-tree").Stringlike} Stringlike
|
|
9
|
+
*
|
|
10
|
+
* @param {Uint8Array|Stringlike} data
|
|
11
|
+
*/
|
|
12
|
+
export default function hashBytes(data) {
|
|
13
|
+
let bytes;
|
|
14
|
+
if (data instanceof Uint8Array) {
|
|
15
|
+
bytes = data;
|
|
16
|
+
} else {
|
|
17
|
+
const text = toString(data);
|
|
18
|
+
if (!text) {
|
|
19
|
+
throw new TypeError("Data must be a string or Uint8Array");
|
|
20
|
+
}
|
|
21
|
+
bytes = new TextEncoder().encode(text);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const hash = createHash("sha256").update(bytes).digest();
|
|
25
|
+
return hash;
|
|
26
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { args, isStringlike, toString, Tree } from "@weborigami/async-tree";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given an old tree and a new tree, return a tree of changes indicated
|
|
5
|
+
* by the values: "added", "changed", or "deleted".
|
|
6
|
+
*
|
|
7
|
+
* @typedef {import("@weborigami/async-tree").Maplike} Maplike
|
|
8
|
+
*
|
|
9
|
+
* @param {Maplike} oldMaplike
|
|
10
|
+
* @param {Maplike} newMaplike
|
|
11
|
+
*/
|
|
12
|
+
export default async function changes(oldMaplike, newMaplike) {
|
|
13
|
+
const oldTree = await args.map(oldMaplike, "Dev.changes", {
|
|
14
|
+
deep: true,
|
|
15
|
+
position: 1,
|
|
16
|
+
});
|
|
17
|
+
const newTree = await args.map(newMaplike, "Dev.changes", {
|
|
18
|
+
deep: true,
|
|
19
|
+
position: 2,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const combination = await Tree.combine(oldTree, newTree, compare);
|
|
23
|
+
return combination;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function compare(oldValue, newValue) {
|
|
27
|
+
if (oldValue !== undefined && newValue === undefined) {
|
|
28
|
+
return "deleted";
|
|
29
|
+
} else if (oldValue === undefined && newValue !== undefined) {
|
|
30
|
+
return "added";
|
|
31
|
+
} else if (isStringlike(oldValue) && isStringlike(newValue)) {
|
|
32
|
+
const oldText = toString(oldValue);
|
|
33
|
+
const newText = toString(newValue);
|
|
34
|
+
return oldText === newText ? undefined : "changed";
|
|
35
|
+
} else {
|
|
36
|
+
return oldValue === newValue ? undefined : "changed";
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/dev/dev.js
CHANGED
|
@@ -6,6 +6,7 @@ export { default as indexPage } from "../origami/indexPage.js";
|
|
|
6
6
|
export { default as yaml } from "../origami/yaml.js";
|
|
7
7
|
export { default as breakpoint } from "./breakpoint.js";
|
|
8
8
|
export { default as changes } from "./changes.js";
|
|
9
|
+
export { default as changes2 } from "./changes2.js";
|
|
9
10
|
export { default as code } from "./code.js";
|
|
10
11
|
export { default as copy } from "./copy.js";
|
|
11
12
|
export { default as audit } from "./crawler/audit.js";
|
package/src/dev/help.yaml
CHANGED
|
@@ -68,9 +68,15 @@ Origami:
|
|
|
68
68
|
fetch:
|
|
69
69
|
args: (url, options)
|
|
70
70
|
description: Fetch a resource from a URL with support for extensions
|
|
71
|
+
hash:
|
|
72
|
+
args: (data)
|
|
73
|
+
description: A hex string hash of the data
|
|
71
74
|
htmlEscape:
|
|
72
75
|
args: (text)
|
|
73
76
|
description: Escape HTML entities in the text
|
|
77
|
+
htmlParse:
|
|
78
|
+
args: (html)
|
|
79
|
+
description: Parse HTML into a plain JavaScript object
|
|
74
80
|
image:
|
|
75
81
|
description: Collection of functions for working with images
|
|
76
82
|
indexPage:
|
|
@@ -79,9 +85,6 @@ Origami:
|
|
|
79
85
|
inline:
|
|
80
86
|
args: (text)
|
|
81
87
|
description: Inline Origami expressions found in the text
|
|
82
|
-
htmlParse:
|
|
83
|
-
args: (html)
|
|
84
|
-
description: Parse HTML into a plain JavaScript object
|
|
85
88
|
json:
|
|
86
89
|
args: (obj)
|
|
87
90
|
description: Render the object in JSON format
|
|
@@ -110,6 +113,12 @@ Origami:
|
|
|
110
113
|
description: POST the given data to the URL
|
|
111
114
|
projectRoot:
|
|
112
115
|
description: The root folder for the current Origami project
|
|
116
|
+
randomFrom:
|
|
117
|
+
args: (data)
|
|
118
|
+
description: Returns a random value based on the data
|
|
119
|
+
randomsFrom:
|
|
120
|
+
args: (data)
|
|
121
|
+
description: Returns a function to produce random values based on the data
|
|
113
122
|
redirect:
|
|
114
123
|
args: (url, options)
|
|
115
124
|
description: Redirect to the given URL
|
|
@@ -193,6 +202,9 @@ Tree:
|
|
|
193
202
|
clear:
|
|
194
203
|
args: (map)
|
|
195
204
|
description: Remove all values from the map
|
|
205
|
+
combine:
|
|
206
|
+
args: (tree1, tree2, combineFn)
|
|
207
|
+
description: Pairwise application of combineFn to the trees' values
|
|
196
208
|
concat:
|
|
197
209
|
args: (...trees)
|
|
198
210
|
description: Merge trees, renumbering numeric keys
|
|
@@ -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
|
+
}
|
package/src/origami/mdHtml.js
CHANGED
package/src/origami/origami.js
CHANGED
|
@@ -4,6 +4,7 @@ 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
6
|
export { default as fetch } from "./fetch.js";
|
|
7
|
+
export { default as hash } from "./hash.js";
|
|
7
8
|
export { default as htmlEscape } from "./htmlEscape.js";
|
|
8
9
|
export { default as htmlParse } from "./htmlParse.js";
|
|
9
10
|
export { default as format } from "./image/format.js";
|
|
@@ -23,6 +24,8 @@ export { default as pack } from "./pack.js";
|
|
|
23
24
|
export { default as post } from "./post.js";
|
|
24
25
|
export { default as project } from "./project.js";
|
|
25
26
|
export { default as projectRoot } from "./projectRoot.js";
|
|
27
|
+
export { default as randomFrom } from "./randomFrom.js";
|
|
28
|
+
export { default as randomsFrom } from "./randomsFrom.js";
|
|
26
29
|
export { default as redirect } from "./redirect.js";
|
|
27
30
|
export { default as repeat } from "./repeat.js";
|
|
28
31
|
export { default as rss } from "./rss.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
|
+
}
|