@weborigami/origami 0.0.54 → 0.0.56

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.
@@ -6,11 +6,9 @@ import PathTransform from "./PathTransform.js";
6
6
 
7
7
  // For builtins that should be renamed or not exported
8
8
  const specialBuiltinNames = {
9
- "!": null,
10
- "@false": null,
11
- "@new": null,
12
- "@true": null,
13
- "~": "homeFiles",
9
+ constructor: null,
10
+ false: null,
11
+ true: null,
14
12
  };
15
13
 
16
14
  // Top-level template for the export file
@@ -44,8 +42,6 @@ async function exportStatementForCode(codeBuffer, key) {
44
42
 
45
43
  // @ts-ignore
46
44
  const path = codeBuffer[PathTransform.pathKey] ?? "";
47
- const pathParts = path.split("/");
48
- pathParts.pop(); // Drop key
49
45
 
50
46
  const exportsDefault =
51
47
  code.match(/^export default /m) || code.match(/^export { default } /m);
@@ -54,47 +50,46 @@ async function exportStatementForCode(codeBuffer, key) {
54
50
  return `export * from "../src/${path}";\n`;
55
51
  }
56
52
 
57
- // Export a single default export.
53
+ // Single export
58
54
 
59
55
  // We construct an identifier for the export based on the path to the file and
60
56
  // the file name. This omits the first part of the path, which is the name of
61
- // a folder that's a direct child of the `src` folder. The remaining parts are
62
- // joined in camelCase to form the export name. We remove the `@` prefix from
63
- // any parts that start with it. As an example, the file inside the src folder
64
- // at `builtins/@tree/concat.js` will be identified as `treeConcat`.
65
- let exportIdentifierParts = pathParts.slice(1);
57
+ // a folder that's a direct child of the `src` folder. We omit the `.js`
58
+ // extension, and remove any characters that aren't valid in JS identifiers.
59
+ // We use camelCase to combine the parts. As an example, the file inside the
60
+ // src folder at `builtins/@image/format.js` will be identified as
61
+ // `imageFormat`.
66
62
 
67
- // The file name is the last part of the path; remove the .js extension.
68
- let name = key.slice(0, -3);
63
+ // Split the name into parts wherever there are characters that can't be in
64
+ // JavaScript identifiers; drop any empty parts.
65
+ const parts = path.split(/[^a-zA-Z0-9]/g).filter(Boolean);
66
+
67
+ // Drop the first (folder) part and the last (`.js`) part.
68
+ parts.shift();
69
+ parts.pop();
70
+
71
+ // Join the parts in camelCase to form the identifier.
72
+ let identifier = parts
73
+ .map((part, index) =>
74
+ index === 0 ? part : part[0].toUpperCase() + part.slice(1)
75
+ )
76
+ .join("");
77
+
78
+ if (!identifier) {
79
+ // Name is entirely non-JS characters, like `~`. For now we ignore it.
80
+ return "";
81
+ }
69
82
 
70
83
  // Ignore certain builtins like `@true` and `@false` that would conflict with
71
84
  // JavaScript keywords. Developers can use those JavaScript keywords directly.
72
- const specialName = specialBuiltinNames[name];
85
+ const specialName = specialBuiltinNames[identifier];
73
86
  if (specialName === null) {
74
87
  return "";
75
88
  }
76
89
  if (specialName) {
77
- name = specialName;
90
+ identifier = specialName;
78
91
  }
79
92
 
80
- // Split the name into parts based on dots.
81
- const nameParts = name.split(".");
82
-
83
- // Add the name to the parts.
84
- exportIdentifierParts.push(...nameParts);
85
-
86
- // Remove characters that can't be in JavaScript identifiers.
87
- exportIdentifierParts = exportIdentifierParts.map((part) =>
88
- part.replace(/[^a-zA-Z0-9]/g, "")
89
- );
90
-
91
- // Join the parts in camelCase to form the identifier.
92
- const identifier = exportIdentifierParts
93
- .map((part, index) =>
94
- index === 0 ? part : part[0].toUpperCase() + part.slice(1)
95
- )
96
- .join("");
97
-
98
93
  return `export { default as ${identifier} } from "../src/${path}";\n`;
99
94
  }
100
95
 
@@ -8,7 +8,6 @@ export { default as changes } from "../src/builtins/@changes.js";
8
8
  export { default as clean } from "../src/builtins/@clean.js";
9
9
  export { default as concat } from "../src/builtins/@concat.js";
10
10
  export { default as config } from "../src/builtins/@config.js";
11
- export { default as constructor } from "../src/builtins/@constructor.js";
12
11
  export { default as copy } from "../src/builtins/@copy.js";
13
12
  export { default as crawl } from "../src/builtins/@crawl.js";
14
13
  export { default as debug } from "../src/builtins/@debug.js";
@@ -106,22 +105,21 @@ export { default as values } from "../src/builtins/@values.js";
106
105
  export { default as watch } from "../src/builtins/@watch.js";
107
106
  export { default as yaml } from "../src/builtins/@yaml.js";
108
107
  export { default as yamlParse } from "../src/builtins/@yamlParse.js";
109
- export { default as homeFiles } from "../src/builtins/~.js";
110
- export { default as csshandler } from "../src/builtins/css_handler.js";
111
- export { default as htmhandler } from "../src/builtins/htm_handler.js";
112
- export { default as htmlhandler } from "../src/builtins/html_handler.js";
113
- export { default as jpeghandler } from "../src/builtins/jpeg_handler.js";
114
- export { default as jpghandler } from "../src/builtins/jpg_handler.js";
115
- export { default as jshandler } from "../src/builtins/js_handler.js";
116
- export { default as jsonhandler } from "../src/builtins/json_handler.js";
117
- export { default as mdhandler } from "../src/builtins/md_handler.js";
118
- export { default as mjshandler } from "../src/builtins/mjs_handler.js";
119
- export { default as orihandler } from "../src/builtins/ori_handler.js";
120
- export { default as txthandler } from "../src/builtins/txt_handler.js";
121
- export { default as wasmhandler } from "../src/builtins/wasm_handler.js";
122
- export { default as xhtmlhandler } from "../src/builtins/xhtml_handler.js";
123
- export { default as yamlhandler } from "../src/builtins/yaml_handler.js";
124
- export { default as ymlhandler } from "../src/builtins/yml_handler.js";
108
+ export { default as cssHandler } from "../src/builtins/css_handler.js";
109
+ export { default as htmHandler } from "../src/builtins/htm_handler.js";
110
+ export { default as htmlHandler } from "../src/builtins/html_handler.js";
111
+ export { default as jpegHandler } from "../src/builtins/jpeg_handler.js";
112
+ export { default as jpgHandler } from "../src/builtins/jpg_handler.js";
113
+ export { default as jsHandler } from "../src/builtins/js_handler.js";
114
+ export { default as jsonHandler } from "../src/builtins/json_handler.js";
115
+ export { default as mdHandler } from "../src/builtins/md_handler.js";
116
+ export { default as mjsHandler } from "../src/builtins/mjs_handler.js";
117
+ export { default as oriHandler } from "../src/builtins/ori_handler.js";
118
+ export { default as txtHandler } from "../src/builtins/txt_handler.js";
119
+ export { default as wasmHandler } from "../src/builtins/wasm_handler.js";
120
+ export { default as xhtmlHandler } from "../src/builtins/xhtml_handler.js";
121
+ export { default as yamlHandler } from "../src/builtins/yaml_handler.js";
122
+ export { default as ymlHandler } from "../src/builtins/yml_handler.js";
125
123
  export { default as defaultModuleExport } from "../src/cli/defaultModuleExport.js";
126
124
  export { default as showUsage } from "../src/cli/showUsage.js";
127
125
  export { default as addValueKeyToScope } from "../src/common/addValueKeyToScope.js";
@@ -140,7 +138,6 @@ export { default as assertScopeIsDefined } from "../src/misc/assertScopeIsDefine
140
138
  export { default as getTreeArgument } from "../src/misc/getTreeArgument.js";
141
139
  export { default as OriCommandTransform } from "../src/misc/OriCommandTransform.js";
142
140
  export { default as treeDot } from "../src/misc/treeDot.js";
143
- export { default as yamlOrigamiTag } from "../src/misc/yamlOrigamiTag.js";
144
141
  export { default as constructResponse } from "../src/server/constructResponse.js";
145
142
  export * from "../src/server/mediaTypes.js";
146
143
  export * from "../src/server/server.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.0.54",
3
+ "version": "0.0.56",
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.4.5"
18
18
  },
19
19
  "dependencies": {
20
- "@weborigami/async-tree": "0.0.54",
21
- "@weborigami/language": "0.0.54",
22
- "@weborigami/types": "0.0.54",
20
+ "@weborigami/async-tree": "0.0.56",
21
+ "@weborigami/language": "0.0.56",
22
+ "@weborigami/types": "0.0.56",
23
23
  "exif-parser": "0.1.12",
24
24
  "graphviz-wasm": "3.0.2",
25
25
  "highlight.js": "11.9.0",
@@ -8,7 +8,7 @@ import getTreeArgument from "../misc/getTreeArgument.js";
8
8
  * @param {import("@weborigami/async-tree").Treelike} treelike
9
9
  */
10
10
  export default async function clean(treelike) {
11
- const tree = await getTreeArgument(this, arguments, treelike, "@sequence");
11
+ const tree = await getTreeArgument(this, arguments, treelike, "@clean");
12
12
  if (!Tree.isAsyncMutableTree(tree)) {
13
13
  throw new TypeError("@clean: the given tree is read-only.");
14
14
  }
@@ -1,13 +1,19 @@
1
- import reverse from "./@reverse.js";
1
+ import { deepReverse } from "@weborigami/async-tree";
2
+ import { Scope } from "@weborigami/language";
3
+ import getTreeArgument from "../misc/getTreeArgument.js";
2
4
 
3
5
  /**
4
- * Shorthand for reversing a tree with the `deep` option set to true.
5
- *
6
- * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
7
-
8
- * @this {AsyncTree|null}
9
- * @param {*} treelike
6
+ * Reverse the order of keys at all levels of the tree.
7
+ *
8
+ * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
+ * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
+ *
11
+ * @this {AsyncTree|null}
12
+ * @param {Treelike} [treelike]
10
13
  */
11
- export default function deepReverse(treelike) {
12
- return reverse.call(this, treelike, { deep: true });
14
+ export default async function deepReverseBuiltin(treelike) {
15
+ const tree = await getTreeArgument(this, arguments, treelike, "@deepReverse");
16
+ let reversed = deepReverse(tree);
17
+ reversed = Scope.treeWithScope(reversed, this);
18
+ return reversed;
13
19
  }
@@ -55,25 +55,5 @@ export default async function treeMerge(...trees) {
55
55
  return result;
56
56
  }
57
57
 
58
- /**
59
- * Merge the indicated plain objects. If a key is present in multiple objects,
60
- * the value from the first object is used.
61
- *
62
- * This is similar to calling Object.assign() with the objects in reverse order,
63
- * but we want to ensure the keys end up in the same order they're encountered
64
- * in the objects.
65
- *
66
- * @param {...any} objects
67
- */
68
- function mergeObjects(...objects) {
69
- const result = {};
70
- for (const obj of objects) {
71
- for (const key of Object.keys(obj)) {
72
- result[key] ??= obj[key];
73
- }
74
- }
75
- return result;
76
- }
77
-
78
58
  treeMerge.usage = `@merge <...trees>\tMerge the given trees`;
79
59
  treeMerge.documentation = "https://weborigami.org/cli/builtins.html#@merge";
@@ -1,4 +1,4 @@
1
- import { Tree } from "@weborigami/async-tree";
1
+ import { reverse } from "@weborigami/async-tree";
2
2
  import { Scope } from "@weborigami/language";
3
3
  import getTreeArgument from "../misc/getTreeArgument.js";
4
4
 
@@ -7,40 +7,16 @@ import getTreeArgument from "../misc/getTreeArgument.js";
7
7
  *
8
8
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
9
9
  * @typedef {import("@weborigami/async-tree").Treelike} Treelike
10
- * @typedef {import("@weborigami/async-tree").PlainObject} PlainObject
11
10
  *
12
11
  * @this {AsyncTree|null}
13
12
  * @param {Treelike} [treelike]
14
- * @param {PlainObject} [options]
15
13
  */
16
- export default async function reverse(treelike, options = {}) {
14
+ export default async function reverseBuiltin(treelike) {
17
15
  const tree = await getTreeArgument(this, arguments, treelike, "@reverse");
18
- const scope = this;
19
- const deep = options.deep ?? false;
20
-
21
- /** @type {AsyncTree} */
22
- let reversed = {
23
- async get(key) {
24
- let value = await tree.get(key);
25
-
26
- if (deep && Tree.isAsyncTree(value)) {
27
- value = reverse.call(scope, value, options);
28
- }
29
-
30
- return value;
31
- },
32
-
33
- async keys() {
34
- const keys = Array.from(await tree.keys());
35
- keys.reverse();
36
- return keys;
37
- },
38
- };
39
-
16
+ let reversed = reverse(tree);
40
17
  reversed = Scope.treeWithScope(reversed, this);
41
-
42
18
  return reversed;
43
19
  }
44
20
 
45
- reverse.usage = `@reverse <tree>\tReverses the order of the tree's top-level keys`;
46
- reverse.documentation = "https://weborigami.org/cli/builtins.html#reverse";
21
+ reverseBuiltin.usage = `@reverse <tree>\tReverses the order of the tree's top-level keys`;
22
+ reverseBuiltin.documentation = "https://weborigami.org/builtins/@reverse.html";
@@ -1,5 +1,5 @@
1
1
  import { isPacked, symbols } from "@weborigami/async-tree";
2
- import { evaluateYaml, toYaml } from "../common/serialize.js";
2
+ import { parseYaml, toYaml } from "../common/serialize.js";
3
3
  import * as utilities from "../common/utilities.js";
4
4
 
5
5
  /**
@@ -51,7 +51,7 @@ export default {
51
51
  },
52
52
 
53
53
  /** @type {import("@weborigami/language").UnpackFunction} */
54
- async unpack(packed, options = {}) {
54
+ unpack(packed, options = {}) {
55
55
  const parent = options.parent ?? null;
56
56
  const text = utilities.toString(packed);
57
57
  if (text === null) {
@@ -65,7 +65,7 @@ export default {
65
65
  if (match) {
66
66
  // Document object with front matter
67
67
  const { body, frontText } = /** @type {any} */ (match.groups);
68
- const frontData = await evaluateYaml(frontText, parent);
68
+ const frontData = parseYaml(frontText);
69
69
  unpacked = Object.assign({}, frontData, { "@text": body });
70
70
  } else {
71
71
  // Plain text
@@ -1,6 +1,6 @@
1
1
  import * as YAMLModule from "yaml";
2
2
  import processUnpackedContent from "../common/processUnpackedContent.js";
3
- import { evaluateYaml } from "../common/serialize.js";
3
+ import { parseYaml } from "../common/serialize.js";
4
4
  import * as utilities from "../common/utilities.js";
5
5
 
6
6
  // See notes at serialize.js
@@ -17,13 +17,13 @@ export default {
17
17
  mediaType: "application/yaml",
18
18
 
19
19
  /** @type {import("@weborigami/language").UnpackFunction} */
20
- async unpack(packed, options = {}) {
20
+ unpack(packed, options = {}) {
21
21
  const parent = options.parent ?? null;
22
22
  const yaml = utilities.toString(packed);
23
23
  if (!yaml) {
24
24
  throw new Error("Tried to parse something as YAML but it wasn't text.");
25
25
  }
26
- const data = await evaluateYaml(yaml, options.parent);
26
+ const data = parseYaml(yaml);
27
27
  return processUnpackedContent(data, parent);
28
28
  },
29
29
  };
@@ -5,10 +5,8 @@
5
5
  * @typedef {import("@weborigami/types").AsyncTree} AsyncTree
6
6
  */
7
7
 
8
- import { Tree, isPlainObject, isStringLike } from "@weborigami/async-tree";
9
- import { OrigamiTree } from "@weborigami/language";
8
+ import { Tree, isStringLike } from "@weborigami/async-tree";
10
9
  import * as YAMLModule from "yaml";
11
- import yamlOrigamiTag from "../misc/yamlOrigamiTag.js";
12
10
 
13
11
  const textDecoder = new TextDecoder();
14
12
  const TypedArray = Object.getPrototypeOf(Uint8Array);
@@ -48,35 +46,12 @@ function isJsonValue(obj) {
48
46
  );
49
47
  }
50
48
 
51
- // Return true if the given object has any functions in it.
52
- function objectContainsFunctions(obj) {
53
- for (const key in obj) {
54
- const value = obj[key];
55
- if (typeof value === "function") {
56
- return true;
57
- } else if (isPlainObject(value)) {
58
- const valueContainsExpression = objectContainsFunctions(value);
59
- if (valueContainsExpression) {
60
- return true;
61
- }
62
- }
63
- }
64
- return false;
65
- }
66
-
67
49
  /**
68
50
  * @param {string} text
69
51
  * @returns {JsonValue|AsyncTree}
70
52
  */
71
53
  export function parseYaml(text) {
72
- const data = YAML.parse(text, {
73
- customTags: [yamlOrigamiTag],
74
- });
75
- if (objectContainsFunctions(data)) {
76
- return new OrigamiTree(data);
77
- } else {
78
- return data;
79
- }
54
+ return YAML.parse(text);
80
55
  }
81
56
 
82
57
  /**
@@ -1,13 +1,10 @@
1
1
  import {
2
2
  Tree,
3
+ toString as asyncTreeToString,
3
4
  isPlainObject,
4
- isStringLike,
5
5
  isUnpackable,
6
6
  } from "@weborigami/async-tree";
7
7
 
8
- const textDecoder = new TextDecoder();
9
- const TypedArray = Object.getPrototypeOf(Uint8Array);
10
-
11
8
  // Return true if the text appears to contain non-printable binary characters;
12
9
  // used to infer whether a file is binary or text.
13
10
  export function hasNonPrintableCharacters(text) {
@@ -86,17 +83,8 @@ export function toFunction(obj) {
86
83
  }
87
84
 
88
85
  /**
89
- * Return a string form of the object, handling two cases not generally handled
90
- * by a .toString() method:
91
- *
92
- * 1. If the object is a plain JavaScript object with a `@text` property, return
93
- * the value of that property.
94
- * 2. If the object is an ArrayBuffer or TypedArray, decode the array as UTF-8.
95
- *
96
- * Finally, if the object is otherwise a plain JavaScript object with the
97
- * useless default toString() method, return null instead of "[object Object]".
98
- * In practice, it's generally more useful to have this method fail than to
99
- * return a useless string.
86
+ * Extend the async-tree toString method: objects that have a `@text` property
87
+ * will return the value of that property as a string.
100
88
  *
101
89
  * @param {any} object
102
90
  * @returns {string|null}
@@ -104,15 +92,8 @@ export function toFunction(obj) {
104
92
  export function toString(object) {
105
93
  if (isPlainObject(object) && "@text" in object) {
106
94
  return object["@text"];
107
- } else if (object instanceof ArrayBuffer || object instanceof TypedArray) {
108
- // Treat the buffer as UTF-8 text.
109
- const decoded = textDecoder.decode(object);
110
- // If the result has non-printable characters, it's probably not a string.
111
- return hasNonPrintableCharacters(decoded) ? null : decoded;
112
- } else if (isStringLike(object)) {
113
- return String(object);
114
95
  } else {
115
- return null;
96
+ return asyncTreeToString(object);
116
97
  }
117
98
  }
118
99
 
@@ -1,7 +1,11 @@
1
- import { Tree, isPlainObject, isStringLike } from "@weborigami/async-tree";
2
- import { extname } from "@weborigami/language";
1
+ import {
2
+ Tree,
3
+ isPlainObject,
4
+ isStringLike,
5
+ toString,
6
+ } from "@weborigami/async-tree";
3
7
  import * as serialize from "../common/serialize.js";
4
- import { hasNonPrintableCharacters, keySymbol } from "../common/utilities.js";
8
+ import { keySymbol } from "../common/utilities.js";
5
9
 
6
10
  /**
7
11
  * Render a tree in DOT format.
@@ -61,23 +65,15 @@ async function statements(tree, nodePath, nodeLabel, options) {
61
65
  : error.name ?? error.message ?? error;
62
66
  }
63
67
 
64
- // We expand certain types of files known to contain trees.
65
- const extension = key ? extname(key).toLowerCase() : "";
66
- const expand =
67
- {
68
- ".json": true,
69
- ".yaml": true,
70
- }[extension] ?? extension === "";
71
-
72
68
  const expandable =
73
69
  value instanceof Array || isPlainObject(value) || Tree.isAsyncTree(value);
74
- if (expand && expandable) {
70
+ if (expandable) {
75
71
  const subtree = Tree.from(value);
76
72
  const subStatements = await statements(subtree, destPath, null, options);
77
73
  result = result.concat(subStatements);
78
74
  } else {
79
75
  const label = isStringLike(value)
80
- ? String(value)
76
+ ? toString(value)
81
77
  : value !== undefined
82
78
  ? await serialize.toYaml(value)
83
79
  : "";
@@ -102,8 +98,8 @@ async function statements(tree, nodePath, nodeLabel, options) {
102
98
  // Trim labels.
103
99
  let i = 0;
104
100
  for (const key of Object.keys(nodes)) {
105
- let label = String(nodes[key].label);
106
- if (hasNonPrintableCharacters(label)) {
101
+ let label = nodes[key].label;
102
+ if (label === null) {
107
103
  nodes[key].label = "[binary data]";
108
104
  } else if (label) {
109
105
  let clippedStart = false;
@@ -1,17 +0,0 @@
1
- import { compile, expressionFunction } from "@weborigami/language";
2
-
3
- /**
4
- * A YAML tag for an Origami expression.
5
- */
6
- export default {
7
- identify: expressionFunction.isExpressionFunction,
8
-
9
- resolve(str) {
10
- const code = compile.expression(str);
11
- return code instanceof Array
12
- ? expressionFunction.createExpressionFunction(code)
13
- : code;
14
- },
15
-
16
- tag: "!ori",
17
- };