@weborigami/origami 0.0.73 → 0.2.0

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 (194) hide show
  1. package/main.js +12 -0
  2. package/package.json +5 -7
  3. package/src/builtins.js +62 -0
  4. package/src/builtinsTree.js +36 -0
  5. package/src/calc/calc.js +71 -0
  6. package/src/cli/cli.js +6 -4
  7. package/src/{misc → common}/assertTreeIsDefined.js +4 -1
  8. package/src/common/constructHref.js +20 -0
  9. package/src/common/constructSiteTree.js +34 -0
  10. package/src/common/fetchAndHandleExtension.js +26 -0
  11. package/src/{misc → common}/getTreeArgument.js +11 -5
  12. package/src/common/processUnpackedContent.js +4 -13
  13. package/src/common/utilities.d.ts +1 -2
  14. package/src/common/utilities.js +24 -31
  15. package/src/deprecated.js +140 -0
  16. package/src/{common → dev}/ExplorableSiteTransform.js +1 -1
  17. package/src/{misc → dev}/OriCommandTransform.js +2 -2
  18. package/src/{builtins/@code.js → dev/code.js} +2 -2
  19. package/src/{builtins/@debug.js → dev/debug.js} +4 -7
  20. package/src/dev/dev.js +9 -0
  21. package/src/{builtins/@explore.js → dev/explore.js} +24 -30
  22. package/src/{misc → dev}/explore.js.inline +4 -4
  23. package/src/{misc → dev}/explore.ori +4 -4
  24. package/src/{builtins/@log.js → dev/log.js} +1 -1
  25. package/src/{builtins/@serve.js → dev/serve.js} +5 -8
  26. package/src/{builtins/@svg.js → dev/svg.js} +9 -6
  27. package/src/{misc → dev}/treeDot.js +2 -5
  28. package/src/{builtins/@watch.js → dev/watch.js} +8 -6
  29. package/src/handlers/handlerExports.js +16 -0
  30. package/src/handlers/handlers.js +37 -0
  31. package/src/{builtins → handlers}/js.handler.js +1 -1
  32. package/src/{builtins → handlers}/json.handler.js +9 -1
  33. package/src/handlers/mjs.handler.js +2 -0
  34. package/src/{builtins → handlers}/ori.handler.js +5 -7
  35. package/src/{builtins → handlers}/oridocument.handler.js +1 -1
  36. package/src/{builtins → handlers}/wasm.handler.js +1 -1
  37. package/src/{builtins → handlers}/yaml.handler.js +8 -1
  38. package/src/handlers/yml.handler.js +2 -0
  39. package/src/help/help.js +103 -0
  40. package/src/help/help.yaml +428 -0
  41. package/src/{builtins/@image → image}/format.js +2 -2
  42. package/src/{builtins/@image → image}/formatFn.js +1 -1
  43. package/src/image/image.js +2 -0
  44. package/src/{builtins/@image → image}/resize.js +2 -2
  45. package/src/{builtins/@image → image}/resizeFn.js +1 -1
  46. package/src/internal.js +24 -0
  47. package/src/{builtins/@js.js → js.js} +7 -6
  48. package/src/{builtins/@node.js → node.js} +1 -6
  49. package/src/{builtins/@basename.js → origami/basename.js} +2 -2
  50. package/src/{builtins/@config.js → origami/config.js} +1 -4
  51. package/src/{builtins/@json.js → origami/json.js} +2 -5
  52. package/src/{builtins/@jsonParse.js → origami/jsonParse.js} +0 -3
  53. package/src/{builtins/@once.js → origami/once.js} +2 -2
  54. package/src/{builtins/@ori.js → origami/ori.js} +4 -7
  55. package/src/origami/origami.js +29 -0
  56. package/src/{builtins/@pack.js → origami/pack.js} +2 -2
  57. package/src/{builtins/@project.js → origami/project.js} +7 -11
  58. package/src/{builtins/@regexMatch.js → origami/regexMatch.js} +1 -1
  59. package/src/origami/repeat.js +5 -0
  60. package/src/{builtins/@shell.js → origami/shell.js} +0 -3
  61. package/src/{builtins/@stdin.js → origami/stdin.js} +0 -3
  62. package/src/{builtins/@string.js → origami/string.js} +2 -2
  63. package/src/{builtins/@unpack.js → origami/unpack.js} +2 -2
  64. package/src/{builtins/@yaml.js → origami/yaml.js} +2 -5
  65. package/src/{builtins/@yamlParse.js → origami/yamlParse.js} +0 -3
  66. package/src/protocols/explore.js +19 -0
  67. package/src/{builtins/@files.js → protocols/files.js} +2 -5
  68. package/src/protocols/http.js +18 -0
  69. package/src/protocols/https.js +18 -0
  70. package/src/protocols/httpstree.js +19 -0
  71. package/src/protocols/httptree.js +19 -0
  72. package/src/protocols/inherited.js +18 -0
  73. package/src/protocols/new.js +42 -0
  74. package/src/{builtins/@package.js → protocols/package.js} +32 -10
  75. package/src/protocols/scope.js +24 -0
  76. package/src/server/constructResponse.js +5 -5
  77. package/src/{builtins/@siteAudit.js → site/audit.js} +4 -4
  78. package/src/{builtins/@crawl.js → site/crawler/crawl.js} +3 -6
  79. package/src/{crawler → site/crawler}/findPaths.js +2 -3
  80. package/src/{crawler → site/crawler}/utilities.js +2 -3
  81. package/src/{builtins/@index.js → site/index.js} +4 -7
  82. package/src/{builtins/@jsonKeys.js → site/jsonKeys.js} +5 -5
  83. package/src/{builtins/@rss.js → site/rss.js} +2 -5
  84. package/src/site/site.js +9 -0
  85. package/src/{builtins/@sitemap.js → site/sitemap.js} +8 -12
  86. package/src/{builtins/@static.js → site/static.js} +7 -7
  87. package/src/{builtins/@document.js → text/document.js} +2 -2
  88. package/src/{builtins/@inline.js → text/inline.js} +10 -13
  89. package/src/{builtins/@mdHtml.js → text/mdHtml.js} +7 -10
  90. package/src/text/origamiHighlightDefinition.js +57 -0
  91. package/src/text/text.js +4 -0
  92. package/src/{builtins/@addNextPrevious.js → tree/addNextPrevious.js} +7 -2
  93. package/src/{builtins/@cache.js → tree/cache.js} +2 -5
  94. package/src/{builtins/@clean.js → tree/clear.js} +4 -4
  95. package/src/{builtins/@concat.js → tree/concat.js} +2 -5
  96. package/src/{builtins/@copy.js → tree/copy.js} +3 -10
  97. package/src/{builtins/@deepMapFn.js → tree/deepMap.js} +13 -6
  98. package/src/{builtins/@deepMerge.js → tree/deepMerge.js} +4 -7
  99. package/src/{builtins/@deepReverse.js → tree/deepReverse.js} +8 -2
  100. package/src/tree/deepTake.js +26 -0
  101. package/src/{builtins/@deepValues.js → tree/deepValues.js} +2 -6
  102. package/src/{builtins/@defineds.js → tree/defineds.js} +7 -2
  103. package/src/{builtins/@filter.js → tree/filter.js} +3 -6
  104. package/src/{builtins/@first.js → tree/first.js} +2 -5
  105. package/src/{builtins/@fnTree.js → tree/fromFn.js} +3 -6
  106. package/src/{builtins/@globs.js → tree/globs.js} +3 -6
  107. package/src/tree/group.js +26 -0
  108. package/src/{builtins/@inners.js → tree/inners.js} +2 -5
  109. package/src/{builtins/@keys.js → tree/keys.js} +2 -5
  110. package/src/{builtins/@length.js → tree/length.js} +2 -2
  111. package/src/{builtins → tree}/map.d.ts +3 -6
  112. package/src/tree/map.js +154 -0
  113. package/src/{builtins/@mapFn.js → tree/mapFn.js} +14 -6
  114. package/src/{builtins/@match.js → tree/match.js} +2 -5
  115. package/src/{builtins/@merge.js → tree/merge.js} +2 -5
  116. package/src/tree/paginate.js +61 -0
  117. package/src/{builtins/@parent.js → tree/parent.js} +2 -5
  118. package/src/{builtins/@plain.js → tree/plain.js} +2 -5
  119. package/src/{builtins/@reverse.js → tree/reverse.js} +2 -5
  120. package/src/{builtins/@setDeep.js → tree/setDeep.js} +0 -3
  121. package/src/{builtins/@shuffle.js → tree/shuffle.js} +3 -9
  122. package/src/{builtins/@sortFn.js → tree/sort.js} +12 -17
  123. package/src/tree/take.js +19 -0
  124. package/src/tree/tree.js +50 -0
  125. package/src/{builtins/@values.js → tree/values.js} +2 -5
  126. package/exports/PathTransform.d.ts +0 -5
  127. package/exports/PathTransform.js +0 -20
  128. package/exports/buildExports.js +0 -112
  129. package/exports/exports.js +0 -148
  130. package/src/builtins/@builtins.js +0 -15
  131. package/src/builtins/@deepMap.js +0 -19
  132. package/src/builtins/@deepTake.js +0 -21
  133. package/src/builtins/@deepTakeFn.js +0 -21
  134. package/src/builtins/@equals.js +0 -6
  135. package/src/builtins/@exploreSite.js +0 -16
  136. package/src/builtins/@false.js +0 -1
  137. package/src/builtins/@fetch.js +0 -7
  138. package/src/builtins/@group.js +0 -20
  139. package/src/builtins/@groupFn.js +0 -33
  140. package/src/builtins/@help.js +0 -49
  141. package/src/builtins/@http.js +0 -19
  142. package/src/builtins/@https.js +0 -19
  143. package/src/builtins/@if.js +0 -28
  144. package/src/builtins/@inherited.js +0 -17
  145. package/src/builtins/@map.js +0 -19
  146. package/src/builtins/@math.js +0 -17
  147. package/src/builtins/@not.js +0 -6
  148. package/src/builtins/@or.js +0 -6
  149. package/src/builtins/@paginate.js +0 -18
  150. package/src/builtins/@paginateFn.js +0 -58
  151. package/src/builtins/@repeat.js +0 -8
  152. package/src/builtins/@sort.js +0 -23
  153. package/src/builtins/@table.js +0 -69
  154. package/src/builtins/@take.js +0 -20
  155. package/src/builtins/@takeFn.js +0 -20
  156. package/src/builtins/@tree.js +0 -4
  157. package/src/builtins/@treeHttp.js +0 -19
  158. package/src/builtins/@treeHttps.js +0 -19
  159. package/src/builtins/@true.js +0 -1
  160. package/src/builtins/mjs.handler.js +0 -2
  161. package/src/builtins/yml.handler.js +0 -2
  162. package/src/builtins/~.js +0 -9
  163. package/src/cli/showUsage.js +0 -86
  164. package/src/common/CommandModulesTransform.d.ts +0 -5
  165. package/src/common/CommandModulesTransform.js +0 -39
  166. package/src/common/arrowsMapFn.js +0 -35
  167. package/src/misc/origamiHighlightDefinition.js +0 -36
  168. /package/src/{misc → common}/assertTreeIsDefined.d.ts +0 -0
  169. /package/src/{common → dev}/ExplorableSiteTransform.d.ts +0 -0
  170. /package/src/{misc → dev}/OriCommandTransform.d.ts +0 -0
  171. /package/src/{builtins/@breakpoint.js → dev/breakpoint.js} +0 -0
  172. /package/src/{builtins/@changes.js → dev/changes.js} +0 -0
  173. /package/src/{misc → dev}/explore.css +0 -0
  174. /package/src/{builtins → handlers}/css.handler.js +0 -0
  175. /package/src/{builtins → handlers}/htm.handler.js +0 -0
  176. /package/src/{builtins → handlers}/html.handler.js +0 -0
  177. /package/src/{builtins → handlers}/jpeg.handler.js +0 -0
  178. /package/src/{builtins → handlers}/jpg.handler.js +0 -0
  179. /package/src/{builtins → handlers}/md.handler.js +0 -0
  180. /package/src/{builtins → handlers}/txt.handler.js +0 -0
  181. /package/src/{builtins → handlers}/xhtml.handler.js +0 -0
  182. /package/src/{builtins/@naturalOrder.js → origami/naturalOrder.js} +0 -0
  183. /package/src/{builtins/@post.js → origami/post.js} +0 -0
  184. /package/src/{builtins/@regexMatchFn.js → origami/regexMatchFn.js} +0 -0
  185. /package/src/{builtins/@slash.js → origami/slash.js} +0 -0
  186. /package/src/{builtins/@version.js → origami/version.js} +0 -0
  187. /package/src/{crawler → site/crawler}/crawlResources.js +0 -0
  188. /package/src/{builtins/@redirect.js → site/redirect.js} +0 -0
  189. /package/src/{builtins/@slug.js → site/slug.js} +0 -0
  190. /package/src/{builtins/@indent.js → text/indent.js} +0 -0
  191. /package/src/{common → tree}/FilterTree.js +0 -0
  192. /package/src/{common → tree}/GlobTree.js +0 -0
  193. /package/src/{common → tree}/ShuffleTransform.js +0 -0
  194. /package/src/{builtins/@calendarTree.js → tree/calendar.js} +0 -0
package/main.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from "./src/calc/calc.js";
2
+ export { default as documentObject } from "./src/common/documentObject.js";
3
+ export { toString } from "./src/common/utilities.js";
4
+ export * from "./src/dev/dev.js";
5
+ export * from "./src/handlers/handlerExports.js";
6
+ export * from "./src/handlers/handlers.js";
7
+ export * from "./src/image/image.js";
8
+ export { builtinsTree } from "./src/internal.js";
9
+ export * from "./src/origami/origami.js";
10
+ export * from "./src/site/site.js";
11
+ export * from "./src/text/text.js";
12
+ export * from "./src/tree/tree.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.0.73",
3
+ "version": "0.2.0",
4
4
  "description": "Web Origami language, CLI, framework, and server",
5
5
  "type": "module",
6
6
  "repository": {
@@ -10,16 +10,16 @@
10
10
  "bin": {
11
11
  "ori": "src/cli/cli.js"
12
12
  },
13
- "main": "./exports/exports.js",
13
+ "main": "./main.js",
14
14
  "types": "./index.ts",
15
15
  "devDependencies": {
16
16
  "@types/node": "22.7.4",
17
17
  "typescript": "5.6.2"
18
18
  },
19
19
  "dependencies": {
20
- "@weborigami/async-tree": "0.0.73",
21
- "@weborigami/language": "0.0.73",
22
- "@weborigami/types": "0.0.73",
20
+ "@weborigami/async-tree": "0.2.0",
21
+ "@weborigami/language": "0.2.0",
22
+ "@weborigami/types": "0.2.0",
23
23
  "exif-parser": "0.1.12",
24
24
  "graphviz-wasm": "3.0.2",
25
25
  "highlight.js": "11.10.0",
@@ -31,8 +31,6 @@
31
31
  "yaml": "2.5.1"
32
32
  },
33
33
  "scripts": {
34
- "build": "ori exports/buildExports.js src > exports/exports.js",
35
- "prepublishOnly": "npm run build",
36
34
  "test": "node --test --test-reporter=spec",
37
35
  "typecheck": "node node_modules/typescript/bin/tsc"
38
36
  }
@@ -0,0 +1,62 @@
1
+ import * as calc from "./calc/calc.js";
2
+ import deprecated from "./deprecated.js";
3
+ import * as dev from "./dev/dev.js";
4
+ import * as handlers from "./handlers/handlers.js";
5
+ import help from "./help/help.js";
6
+ import * as image from "./image/image.js";
7
+ import js from "./js.js";
8
+ import node from "./node.js";
9
+ import * as origami from "./origami/origami.js";
10
+ import explore from "./protocols/explore.js";
11
+ import files from "./protocols/files.js";
12
+ import http from "./protocols/http.js";
13
+ import https from "./protocols/https.js";
14
+ import httpstree from "./protocols/httpstree.js";
15
+ import httptree from "./protocols/httptree.js";
16
+ import inherited from "./protocols/inherited.js";
17
+ import instantiate from "./protocols/new.js";
18
+ import packageNamespace from "./protocols/package.js";
19
+ import scope from "./protocols/scope.js";
20
+ import * as site from "./site/site.js";
21
+ import * as text from "./text/text.js";
22
+ import * as tree from "./tree/tree.js";
23
+
24
+ /** @type {any} */
25
+ export default {
26
+ "calc:": adjustReservedWords(calc),
27
+ "dev:": dev,
28
+ "explore:": explore,
29
+ "files:": files,
30
+ "help:": help,
31
+ "http:": http,
32
+ "https:": https,
33
+ "httpstree:": httpstree,
34
+ "httptree:": httptree,
35
+ "image:": image,
36
+ "inherited:": inherited,
37
+ "js:": js,
38
+ "new:": instantiate,
39
+ "node:": node,
40
+ "origami:": origami,
41
+ "package:": packageNamespace,
42
+ "scope:": scope,
43
+ "site:": adjustReservedWords(site),
44
+ "text:": text,
45
+ "tree:": tree,
46
+
47
+ // Some builtins need to be exposed at top level
48
+ ...handlers.default,
49
+
50
+ // Deprecated builtins
51
+ ...deprecated,
52
+ };
53
+
54
+ // Handle cases where a builtin name conflicts with a JS reserved word
55
+ function adjustReservedWords(obj) {
56
+ const result = {};
57
+ for (const [key, value] of Object.entries(obj)) {
58
+ const name = value.key ?? key;
59
+ result[name] = value;
60
+ }
61
+ return result;
62
+ }
@@ -0,0 +1,36 @@
1
+ import { trailingSlash } from "@weborigami/async-tree";
2
+ import builtins from "./builtins.js";
3
+
4
+ const expanded = { ...builtins };
5
+
6
+ // For all builtins like `tree:keys`, add a shorthand `keys`.
7
+ for (const [key, value] of Object.entries(expanded)) {
8
+ const isNamespace = key.endsWith(":");
9
+ if (isNamespace) {
10
+ for (const [subKey, subValue] of Object.entries(value)) {
11
+ // HACK: Skip description keys until we can make them all non-enumerable.
12
+ if (subKey === "description") {
13
+ continue;
14
+ }
15
+ if (subKey in expanded) {
16
+ throw new Error(`Internal Origami error: Duplicate key: ${subKey}`);
17
+ }
18
+ expanded[subKey] = subValue;
19
+ }
20
+ }
21
+ }
22
+
23
+ // We create our own tree instead of using ObjectTree, since that binds the
24
+ // functions would be bound to the object. We want to leave them unbound.
25
+ class BuiltinsTree {
26
+ async get(key) {
27
+ const normalizedKey = trailingSlash.remove(key);
28
+ return expanded[normalizedKey];
29
+ }
30
+
31
+ async keys() {
32
+ return Object.keys(expanded);
33
+ }
34
+ }
35
+
36
+ export default new BuiltinsTree();
@@ -0,0 +1,71 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+ import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
3
+
4
+ export function add(...args) {
5
+ const numbers = args.map((arg) => Number(arg));
6
+ return numbers.reduce((acc, val) => acc + val, 0);
7
+ }
8
+
9
+ export function and(...args) {
10
+ console.warn(`Warning: "and" is deprecated. Use the "&&" operator instead.`);
11
+ return args.every((arg) => arg);
12
+ }
13
+
14
+ export function divide(a, b) {
15
+ return Number(a) / Number(b);
16
+ }
17
+
18
+ export function equals(a, b) {
19
+ console.warn(
20
+ `Warning: "equals" is deprecated. Use the "===" operator instead.`
21
+ );
22
+ return a === b;
23
+ }
24
+
25
+ /**
26
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
27
+ *
28
+ * @this {AsyncTree|null}
29
+ * @param {any} value
30
+ * @param {any} trueResult
31
+ * @param {any} [falseResult]
32
+ */
33
+ export async function ifBuiltin(value, trueResult, falseResult) {
34
+ console.warn(
35
+ `Warning: "if" is deprecated. Use the conditional "a ? b : c" operator instead.`
36
+ );
37
+
38
+ assertTreeIsDefined(this, "calc:if");
39
+ let condition = await value;
40
+ if (Tree.isAsyncTree(condition)) {
41
+ const keys = Array.from(await condition.keys());
42
+ condition = keys.length > 0;
43
+ }
44
+
45
+ // 0 is true, null/undefined/false is false
46
+ let result = condition || condition === 0 ? trueResult : falseResult;
47
+ if (typeof result === "function") {
48
+ result = await result.call(this);
49
+ }
50
+ return result;
51
+ }
52
+ ifBuiltin.key = "if";
53
+
54
+ export function multiply(...args) {
55
+ const numbers = args.map((arg) => Number(arg));
56
+ return numbers.reduce((acc, val) => acc * val, 1);
57
+ }
58
+
59
+ export function not(value) {
60
+ console.warn(`Warning: "not" is deprecated. Use the "!" operator instead.`);
61
+ return !value;
62
+ }
63
+
64
+ export function or(...args) {
65
+ console.warn(`Warning: "or" is deprecated. Use the "||" operator instead.`);
66
+ return args.find((arg) => arg);
67
+ }
68
+
69
+ export function subtract(a, b) {
70
+ return Number(a) - Number(b);
71
+ }
package/src/cli/cli.js CHANGED
@@ -4,9 +4,9 @@ import { Tree } from "@weborigami/async-tree";
4
4
  import { formatError } from "@weborigami/language";
5
5
  import path from "node:path";
6
6
  import process, { stdout } from "node:process";
7
- import ori from "../builtins/@ori.js";
8
- import project from "../builtins/@project.js";
9
- import showUsage from "./showUsage.js";
7
+ import help from "../help/help.js";
8
+ import ori from "../origami/ori.js";
9
+ import project from "../origami/project.js";
10
10
 
11
11
  const TypedArray = Object.getPrototypeOf(Uint8Array);
12
12
 
@@ -20,7 +20,8 @@ async function main(...args) {
20
20
  if (!expression) {
21
21
  // HACK: the config is the parent of the project tree.
22
22
  const config = projectTree.parent;
23
- await showUsage(config);
23
+ const usage = await help.call(config);
24
+ console.log(usage);
24
25
  return;
25
26
  }
26
27
 
@@ -30,6 +31,7 @@ async function main(...args) {
30
31
  const tree = await Tree.traversePath(projectTree, relative);
31
32
 
32
33
  const result = await ori.call(tree, expression);
34
+
33
35
  if (result !== undefined) {
34
36
  const output =
35
37
  result instanceof ArrayBuffer
@@ -1,5 +1,8 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+
1
3
  export default function assertTreeIsDefined(tree, methodName) {
2
- if (tree === undefined) {
4
+ const isValid = tree === null || Tree.isAsyncTree(tree);
5
+ if (!isValid) {
3
6
  throw new Error(
4
7
  `${methodName} must be called with a tree target. If you don't want to pass a tree, invoke with: ${methodName}.call(null)`
5
8
  );
@@ -0,0 +1,20 @@
1
+ import { pathFromKeys } from "@weborigami/async-tree";
2
+
3
+ /**
4
+ * Given a protocol, a host, and a list of keys, construct an href.
5
+ *
6
+ * @param {string} protocol
7
+ * @param {string} host
8
+ * @param {string[]} keys
9
+ */
10
+ export default function constructHref(protocol, host, ...keys) {
11
+ const path = pathFromKeys(keys);
12
+ let href = [host, path].join("/");
13
+ if (!href.startsWith(protocol)) {
14
+ if (!href.startsWith("//")) {
15
+ href = `//${href}`;
16
+ }
17
+ href = `${protocol}${href}`;
18
+ }
19
+ return href;
20
+ }
@@ -0,0 +1,34 @@
1
+ import { trailingSlash } from "@weborigami/async-tree";
2
+ import { HandleExtensionsTransform } from "@weborigami/language";
3
+ import constructHref from "./constructHref.js";
4
+
5
+ /**
6
+ * Given a protocol, a host, and a list of keys, construct an href.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ *
10
+ * @param {string} protocol
11
+ * @param {import("../../index.ts").Constructor<AsyncTree>} treeClass
12
+ * @param {AsyncTree|null} parent
13
+ * @param {string} host
14
+ * @param {string[]} keys
15
+ */
16
+ export default function constructSiteTree(
17
+ protocol,
18
+ treeClass,
19
+ parent,
20
+ host,
21
+ ...keys
22
+ ) {
23
+ // If the last key doesn't end in a slash, remove it for now.
24
+ let lastKey;
25
+ if (keys.length > 0 && keys.at(-1) && !trailingSlash.has(keys.at(-1))) {
26
+ lastKey = keys.pop();
27
+ }
28
+
29
+ const href = constructHref(protocol, host, ...keys);
30
+ let result = new (HandleExtensionsTransform(treeClass))(href);
31
+ result.parent = parent;
32
+
33
+ return lastKey ? result.get(lastKey) : result;
34
+ }
@@ -0,0 +1,26 @@
1
+ import { handleExtension } from "@weborigami/language";
2
+
3
+ /**
4
+ * Fetch the resource at the given href.
5
+ *
6
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
+ *
8
+ * @this {AsyncTree|null}
9
+ * @param {string} href
10
+ */
11
+ export default async function fetchAndHandleExtension(href) {
12
+ const response = await fetch(href);
13
+ if (!response.ok) {
14
+ return undefined;
15
+ }
16
+ let buffer = await response.arrayBuffer();
17
+
18
+ // Attach any loader defined for the file type.
19
+ const url = new URL(href);
20
+ const filename = url.pathname.split("/").pop();
21
+ if (this && filename) {
22
+ buffer = await handleExtension(this, buffer, filename);
23
+ }
24
+
25
+ return buffer;
26
+ }
@@ -25,7 +25,7 @@ export default async function getTreeArgument(
25
25
  args,
26
26
  treelike,
27
27
  methodName,
28
- deep = false
28
+ deep
29
29
  ) {
30
30
  assertTreeIsDefined(parent, methodName);
31
31
 
@@ -34,16 +34,22 @@ export default async function getTreeArgument(
34
34
  treelike = await treelike.unpack();
35
35
  }
36
36
  if (Tree.isTreelike(treelike)) {
37
- let tree = Tree.from(treelike, { deep });
37
+ const options = deep !== undefined ? { deep } : undefined;
38
+ let tree = Tree.from(treelike, options);
38
39
  // If the tree was created from a treelike object and does not yet have a
39
40
  // parent, make the current tree its parent.
40
- if (!tree.parent) {
41
+ if (!tree.parent && parent !== undefined) {
42
+ if (parent !== null && !Tree.isAsyncTree(parent)) {
43
+ throw new Error(
44
+ `The parent argument passed to ${methodName} must be a tree.`
45
+ );
46
+ }
41
47
  tree.parent = parent;
42
48
  }
43
49
  return tree;
44
50
  }
45
51
  throw new Error(
46
- `${methodName}: The first argument must be a tree, like an array, object, or files.`
52
+ `The first argument to ${methodName} must be a tree, like an array, object, or files.`
47
53
  );
48
54
  }
49
55
 
@@ -57,5 +63,5 @@ export default async function getTreeArgument(
57
63
  return parent;
58
64
  }
59
65
 
60
- throw new Error(`${methodName}: The first argument was undefined.`);
66
+ throw new Error(`The first argument to ${methodName} was undefined.`);
61
67
  }
@@ -1,5 +1,5 @@
1
1
  import { symbols, Tree } from "@weborigami/async-tree";
2
- import builtins from "../builtins/@builtins.js";
2
+ import { builtinsTree } from "../internal.js";
3
3
 
4
4
  /**
5
5
  * Perform any necessary post-processing on the unpacked content of a file. This
@@ -9,21 +9,12 @@ import builtins from "../builtins/@builtins.js";
9
9
  *
10
10
  * @param {any} content
11
11
  * @param {AsyncTree|null} parent
12
- * @param {any} [attachedData]
13
12
  * @returns
14
13
  */
15
- export default function processUnpackedContent(content, parent, attachedData) {
14
+ export default function processUnpackedContent(content, parent) {
16
15
  if (typeof content === "function") {
17
- // Bind the function to a target that's the attached data (if it exists) or
18
- // the parent.
19
- const base = parent ?? builtins;
20
- let target;
21
- if (attachedData) {
22
- target = Tree.from(attachedData);
23
- target.parent = base;
24
- } else {
25
- target = base;
26
- }
16
+ // Bind the function to the parent as the `this` context.
17
+ const target = parent ?? builtinsTree;
27
18
  const result = content.bind(target);
28
19
  if (content.code) {
29
20
  result.code = content.code;
@@ -1,8 +1,7 @@
1
1
 
2
- export const keySymbol: unique symbol;
2
+ export function getDescriptor(object: any): string;
3
3
  export function hasNonPrintableCharacters(text: string): boolean;
4
4
  export function isTransformApplied(Transform: Function, object: any): boolean;
5
- export function replaceExtension(key: string, sourceExtension: string, resultExtension: string): string;
6
5
  export function toFunction(object: any): Function;
7
6
  export function toString(object: any): string|null;
8
7
  export function transformObject(Transform: Function, object: any): any;
@@ -5,6 +5,27 @@ import {
5
5
  isUnpackable,
6
6
  trailingSlash,
7
7
  } from "@weborigami/async-tree";
8
+ import { symbols } from "@weborigami/language";
9
+ import { basename } from "node:path";
10
+
11
+ // For a given tree, return some user-friendly descriptor
12
+ export function getDescriptor(tree) {
13
+ if ("path" in tree) {
14
+ return trailingSlash.add(basename(tree.path));
15
+ }
16
+
17
+ const source = tree[symbols.sourceSymbol];
18
+ if (source) {
19
+ // If the source looks like an identifier, use that.
20
+ // TODO: Use real identifier parsing.
21
+ const identifierRegex = /^[A-Za-z0-9_\-\.]+\/?$/;
22
+ if (identifierRegex.test(source)) {
23
+ return trailingSlash.add(source);
24
+ }
25
+ }
26
+
27
+ return null;
28
+ }
8
29
 
9
30
  // Return true if the text appears to contain non-printable binary characters;
10
31
  // used to infer whether a file is binary or text.
@@ -31,40 +52,12 @@ export function isTransformApplied(Transform, obj) {
31
52
  return false;
32
53
  }
33
54
 
34
- export const keySymbol = Symbol("key");
35
-
36
- /**
37
- * If the given key ends in the source extension (which will generally include a
38
- * period), replace that extension with the result extension (which again should
39
- * generally include a period). Otherwise, return the key as is.
40
- *
41
- * If the key ends in a trailing slash, that will be preserved in the result.
42
- *
43
- * @param {string} key
44
- * @param {string} sourceExtension
45
- * @param {string} resultExtension
46
- */
47
- export function replaceExtension(key, sourceExtension, resultExtension) {
48
- if (!key) {
49
- return undefined;
50
- }
51
-
52
- const normalizedKey = trailingSlash.remove(key);
53
- if (!normalizedKey.endsWith(sourceExtension)) {
54
- return normalizedKey;
55
- }
56
-
57
- const replaced =
58
- normalizedKey.slice(0, -sourceExtension.length) + resultExtension;
59
- return trailingSlash.toggle(replaced, trailingSlash.has(key));
60
- }
61
-
62
55
  /**
63
56
  * Convert the given object to a function.
64
57
  *
65
58
  * @typedef {import("../../index.ts").Invocable} Invocable
66
59
  * @param {any} obj
67
- * @returns {Function}
60
+ * @returns {Function|null}
68
61
  */
69
62
  export function toFunction(obj) {
70
63
  if (typeof obj === "function") {
@@ -88,8 +81,8 @@ export function toFunction(obj) {
88
81
  // Return a function that invokes the tree's getter.
89
82
  return Tree.toFunction(obj);
90
83
  } else {
91
- // Return a constant function.
92
- return () => obj;
84
+ // Not a function
85
+ return null;
93
86
  }
94
87
  }
95
88
 
@@ -0,0 +1,140 @@
1
+ import { Tree } from "@weborigami/async-tree";
2
+ import * as calc from "./calc/calc.js";
3
+ import * as dev from "./dev/dev.js";
4
+ import * as image from "./image/image.js";
5
+ import js from "./js.js";
6
+ import node from "./node.js";
7
+ import * as origami from "./origami/origami.js";
8
+ import files from "./protocols/files.js";
9
+ import * as site from "./site/site.js";
10
+ import * as text from "./text/text.js";
11
+ import * as tree from "./tree/tree.js";
12
+
13
+ const warningsDisplayedForKeys = new Set();
14
+
15
+ export function command(namespace, newKey, oldKey, fn) {
16
+ const wrappedFn = function (...args) {
17
+ const keys = newKey
18
+ ? `"${namespace}${newKey}" or just "${newKey}"`
19
+ : `"${namespace}"`;
20
+ if (!warningsDisplayedForKeys.has(oldKey)) {
21
+ console.warn(
22
+ `ori: Warning: "${oldKey}" is deprecated. Use ${keys} instead.`
23
+ );
24
+ warningsDisplayedForKeys.add(oldKey);
25
+ }
26
+ return fn instanceof Function
27
+ ? // @ts-ignore
28
+ fn.call(this, ...args)
29
+ : Tree.traverseOrThrow(fn, ...args);
30
+ };
31
+ if (fn.key) {
32
+ wrappedFn.key = fn.key;
33
+ }
34
+ if (fn.inverseKey) {
35
+ wrappedFn.inverseKey = fn.inverseKey;
36
+ }
37
+ return wrappedFn;
38
+ }
39
+
40
+ export function commands(namespace, object) {
41
+ const deprecatedEntries = Object.entries(object).map(([key, fn]) => [
42
+ `@${fn.key ?? key}`,
43
+ command(namespace, fn.key ?? key, `@${fn.key ?? key}`, fn),
44
+ ]);
45
+ return Object.fromEntries(deprecatedEntries);
46
+ }
47
+
48
+ export default {
49
+ ...commands("calc:", calc),
50
+ ...commands("dev:", dev),
51
+ "@false": command("js:", "false", "@false", js.false),
52
+ "@fetch": command("js:", "fetch", "@fetch", js.fetch),
53
+ "@files": command("files:", null, "@files/", files),
54
+ "@image": command("image:", null, "@image/", image),
55
+ "@js": command("js:", null, "@js/", js),
56
+ "@math": command("calc:", null, "@math/", calc),
57
+ "@mdHtml": command("text:", "mdHtml", "@mdHtml", text.mdHtml),
58
+ "@node": command("node:", null, "@node/", node),
59
+ ...commands("origami:", origami),
60
+ ...commands("site:", site),
61
+ ...commands("text:", text),
62
+ ...commands("tree:", tree),
63
+ "@tree": command("tree:", null, "@tree/", Tree),
64
+ "@true": command("js:", "true", "@true", js.true),
65
+
66
+ // Renamed commands
67
+ "@clean": command("tree:", "clear", "@clean", tree.clear),
68
+
69
+ // Deprecated commands
70
+ "@deepTakeFn": command(
71
+ "tree:",
72
+ "deepTake",
73
+ "@deepTakeFn",
74
+ (options) =>
75
+ /** @this {any} */
76
+ function (treelike) {
77
+ return tree.deepTake.call(this, treelike, options);
78
+ }
79
+ ),
80
+ "@deepMapFn": command(
81
+ "tree:",
82
+ "deepMap",
83
+ "@deepMapFn",
84
+ (options) =>
85
+ /** @this {any} */
86
+ function (treelike) {
87
+ return tree.deepMap.call(this, treelike, options);
88
+ }
89
+ ),
90
+ "@groupFn": command(
91
+ "tree:",
92
+ "group",
93
+ "@groupFn",
94
+ (options) =>
95
+ /** @this {any} */
96
+ function (treelike) {
97
+ return tree.group.call(this, treelike, options);
98
+ }
99
+ ),
100
+ "@mapFn": command(
101
+ "tree:",
102
+ "map",
103
+ "@mapFn",
104
+ (options) =>
105
+ /** @this {any} */
106
+ function (treelike) {
107
+ return tree.map.call(this, treelike, options);
108
+ }
109
+ ),
110
+ "@paginateFn": command(
111
+ "tree:",
112
+ "paginate",
113
+ "@paginateFn",
114
+ (options) =>
115
+ /** @this {any} */
116
+ function (treelike) {
117
+ return tree.paginate.call(this, treelike, options);
118
+ }
119
+ ),
120
+ "@sortFn": command(
121
+ "tree:",
122
+ "sort",
123
+ "@sortFn",
124
+ (options) =>
125
+ /** @this {any} */
126
+ function (treelike) {
127
+ return tree.sort.call(this, treelike, options);
128
+ }
129
+ ),
130
+ "@takeFn": command(
131
+ "tree:",
132
+ "take",
133
+ "@takeFn",
134
+ (options) =>
135
+ /** @this {any} */
136
+ function (treelike) {
137
+ return tree.take.call(this, treelike, options);
138
+ }
139
+ ),
140
+ };
@@ -1,6 +1,6 @@
1
1
  import { Tree, jsonKeys } from "@weborigami/async-tree";
2
- import index from "../builtins/@index.js";
3
2
  import { isTransformApplied, transformObject } from "../common/utilities.js";
3
+ import index from "../site/index.js";
4
4
 
5
5
  /**
6
6
  * Wraps a tree (typically a SiteTree) to turn a standard site into an
@@ -1,5 +1,5 @@
1
1
  /** @typedef {import("@weborigami/types").AsyncTree} AsyncTree */
2
- import ori from "../builtins/@ori.js";
2
+ import ori from "../origami/ori.js";
3
3
 
4
4
  /**
5
5
  * Add support for commands prefixed with `!`.
@@ -7,7 +7,7 @@ import ori from "../builtins/@ori.js";
7
7
  * E.g., asking this tree for `!yaml` will invoke the yaml() builtin function
8
8
  * in the context of this tree.
9
9
  *
10
- * @typedef {import("../../index.js").Constructor<AsyncTree>} AsyncTreeConstructor
10
+ * @typedef {import("../../index.ts").Constructor<AsyncTree>} AsyncTreeConstructor
11
11
  * @param {AsyncTreeConstructor} Base
12
12
  */
13
13
  export default function OriCommandTransform(Base) {