@weborigami/origami 0.1.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/origami",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
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.1.0",
21
- "@weborigami/language": "0.1.0",
22
- "@weborigami/types": "0.1.0",
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",
package/src/calc/calc.js CHANGED
@@ -7,6 +7,7 @@ export function add(...args) {
7
7
  }
8
8
 
9
9
  export function and(...args) {
10
+ console.warn(`Warning: "and" is deprecated. Use the "&&" operator instead.`);
10
11
  return args.every((arg) => arg);
11
12
  }
12
13
 
@@ -15,6 +16,9 @@ export function divide(a, b) {
15
16
  }
16
17
 
17
18
  export function equals(a, b) {
19
+ console.warn(
20
+ `Warning: "equals" is deprecated. Use the "===" operator instead.`
21
+ );
18
22
  return a === b;
19
23
  }
20
24
 
@@ -27,6 +31,10 @@ export function equals(a, b) {
27
31
  * @param {any} [falseResult]
28
32
  */
29
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
+
30
38
  assertTreeIsDefined(this, "calc:if");
31
39
  let condition = await value;
32
40
  if (Tree.isAsyncTree(condition)) {
@@ -49,10 +57,12 @@ export function multiply(...args) {
49
57
  }
50
58
 
51
59
  export function not(value) {
60
+ console.warn(`Warning: "not" is deprecated. Use the "!" operator instead.`);
52
61
  return !value;
53
62
  }
54
63
 
55
64
  export function or(...args) {
65
+ console.warn(`Warning: "or" is deprecated. Use the "||" operator instead.`);
56
66
  return args.find((arg) => arg);
57
67
  }
58
68
 
@@ -1,5 +1,5 @@
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
5
  export function toFunction(object: any): Function;
@@ -3,7 +3,29 @@ import {
3
3
  toString as asyncTreeToString,
4
4
  isPlainObject,
5
5
  isUnpackable,
6
+ trailingSlash,
6
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
+ }
7
29
 
8
30
  // Return true if the text appears to contain non-printable binary characters;
9
31
  // used to infer whether a file is binary or text.
@@ -30,8 +52,6 @@ export function isTransformApplied(Transform, obj) {
30
52
  return false;
31
53
  }
32
54
 
33
- export const keySymbol = Symbol("key");
34
-
35
55
  /**
36
56
  * Convert the given object to a function.
37
57
  *
@@ -4,7 +4,7 @@ import { OrigamiFiles } from "@weborigami/language";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import assertTreeIsDefined from "../common/assertTreeIsDefined.js";
7
- import { keySymbol } from "../common/utilities.js";
7
+ import { getDescriptor } from "../common/utilities.js";
8
8
  import { builtinsTree } from "../internal.js";
9
9
  import debug from "./debug.js";
10
10
 
@@ -61,7 +61,7 @@ async function getScopeData(scope) {
61
61
  // Skip builtins.
62
62
  continue;
63
63
  }
64
- const name = tree[keySymbol];
64
+ const name = getDescriptor(tree);
65
65
  const treeKeys = Array.from(await tree.keys());
66
66
  // Skip system-ish files that start with a period.
67
67
  const keys = treeKeys.filter((key) => !key.startsWith?.("."));
@@ -18,7 +18,7 @@
18
18
  </div>
19
19
  ${ map(scope, (scopeTree) => `
20
20
  <ul>
21
- <h2>${ scopeTree/name }</h2>
21
+ <h2>${ scopeTree/name ?? "" }</h2>
22
22
  ${ map(scopeTree/keys, (key) => `
23
23
  <li>
24
24
  <a href="./!explore/${ key }" target="frame">${ key }</a>
@@ -6,7 +6,7 @@ import {
6
6
  trailingSlash,
7
7
  } from "@weborigami/async-tree";
8
8
  import * as serialize from "../common/serialize.js";
9
- import { keySymbol } from "../common/utilities.js";
9
+ import { getDescriptor } from "../common/utilities.js";
10
10
 
11
11
  /**
12
12
  * Render a tree in DOT format.
@@ -21,7 +21,7 @@ import { keySymbol } from "../common/utilities.js";
21
21
  */
22
22
  export default async function dot(treelike, options = {}) {
23
23
  const tree = Tree.from(treelike, { deep: true });
24
- const rootLabel = tree[keySymbol] ?? "";
24
+ const rootLabel = getDescriptor(tree) ?? "";
25
25
  const treeArcs = await statements(tree, "", rootLabel, options);
26
26
  return `digraph g {
27
27
  bgcolor="transparent";
@@ -1,30 +1,30 @@
1
1
  calc:
2
- description: Perform math and logical operations
2
+ description: Perform math operations
3
3
  commands:
4
4
  add:
5
5
  args: (a, b, ...)
6
6
  description: Add the numbers
7
- and:
8
- args: (a, b, ...)
9
- description: Return true if all the arguments are true
7
+ # and:
8
+ # args: (a, b, ...)
9
+ # description: Return true if all the arguments are true
10
10
  divide:
11
11
  args: (a, b)
12
12
  description: Divide a by b
13
- equals:
14
- args: (a, b)
15
- description: Return true if a equals b
16
- if:
17
- args: (a, b, c)
18
- description: If a is true return b, otherwise c
13
+ # equals:
14
+ # args: (a, b)
15
+ # description: Return true if a equals b
16
+ # if:
17
+ # args: (a, b, c)
18
+ # description: If a is true return b, otherwise c
19
19
  multiply:
20
20
  args: (a, b, ...)
21
21
  description: Multiply the numbers
22
- not:
23
- args: (value)
24
- description: Return true if a is false and vice versa
25
- or:
26
- args: (a, b, ...)
27
- description: Return true if any of the arguments are true
22
+ # not:
23
+ # args: (value)
24
+ # description: Return true if a is false and vice versa
25
+ # or:
26
+ # args: (a, b, ...)
27
+ # description: Return true if any of the arguments are true
28
28
  subtract:
29
29
  args: (a, b)
30
30
  description: Subtract b from a
@@ -399,6 +399,9 @@ tree:
399
399
  reverse:
400
400
  args: (tree)
401
401
  description: Reverse the order of the tree's keys
402
+ root:
403
+ args: (tree)
404
+ description: The root node of the given tree
402
405
  setDeep:
403
406
  args: (target, source)
404
407
  description: Applies the source tree to the target
@@ -7,22 +7,39 @@ import project from "../origami/project.js";
7
7
  */
8
8
  export default async function packageNamespace(...keys) {
9
9
  const parent = this ?? (await project.call(null));
10
- const parentScope = scope(parent);
11
10
 
12
- const packageKeys = [keys.shift()];
13
- if (packageKeys[0]?.startsWith("@")) {
14
- // First key is an npm organization, get the next key too.
15
- packageKeys.push(keys.shift());
11
+ let name = keys.shift();
12
+ let organization;
13
+ if (name?.startsWith("@")) {
14
+ // First key is an npm organization
15
+ organization = name;
16
+ if (keys.length === 0) {
17
+ // Return a function that will process the next key
18
+ return async (name, ...keys) =>
19
+ getPackage(parent, organization, name, keys);
20
+ }
21
+ name = keys.shift();
22
+ }
23
+
24
+ return getPackage(parent, organization, name, keys);
25
+ }
26
+
27
+ async function getPackage(parent, organization, name, keys) {
28
+ const packagePath = ["node_modules"];
29
+ if (organization) {
30
+ packagePath.push(organization);
16
31
  }
32
+ packagePath.push(name);
17
33
 
34
+ const parentScope = scope(parent);
18
35
  const packageRoot = await Tree.traverse(
19
36
  // @ts-ignore
20
37
  parentScope,
21
- "node_modules",
22
- ...packageKeys
38
+ ...packagePath
23
39
  );
40
+
24
41
  if (!packageRoot) {
25
- throw new Error(`Can't find node_modules/${packageKeys.join("/")}`);
42
+ throw new Error(`Can't find ${packagePath.join("/")}`);
26
43
  }
27
44
 
28
45
  const mainPath = await Tree.traverse(packageRoot, "package.json", "main");
@@ -44,5 +61,10 @@ export default async function packageNamespace(...keys) {
44
61
  keys.length > 0
45
62
  ? await Tree.traverse(packageExports, ...keys)
46
63
  : packageExports;
64
+
65
+ if (Tree.isAsyncTree(result)) {
66
+ result.parent = parent;
67
+ }
68
+
47
69
  return result;
48
70
  }
@@ -9,6 +9,16 @@ import { ops } from "@weborigami/language";
9
9
  */
10
10
  export default async function scope(...keys) {
11
11
  const key = keys.shift();
12
- const value = await ops.scope.call(this, key);
12
+ let value;
13
+ try {
14
+ // Look up key in scope but don't throw if it's undefined
15
+ value = await ops.scope.call(this, key);
16
+ } catch (error) {
17
+ if (error instanceof ReferenceError) {
18
+ value = undefined;
19
+ } else {
20
+ throw error;
21
+ }
22
+ }
13
23
  return keys.length > 0 ? await Tree.traverse(value, ...keys) : value;
14
24
  }
package/src/site/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import getTreeArgument from "../common/getTreeArgument.js";
2
- import { keySymbol } from "../common/utilities.js";
2
+ import { getDescriptor } from "../common/utilities.js";
3
3
 
4
4
  /**
5
5
  * Return a default index.html page for the current tree.
@@ -26,7 +26,7 @@ export default async function index(treelike) {
26
26
  links.push(link);
27
27
  }
28
28
 
29
- const heading = tree[keySymbol] ?? "Index";
29
+ const heading = getDescriptor(tree) ?? "Index";
30
30
  const list = ` <ul>\n${links.join("\n")}\n </ul>`;
31
31
 
32
32
  const html = `<!DOCTYPE html>
@@ -36,7 +36,7 @@ export default function origamiHighlightDefinition(hljs) {
36
36
  // Treat identifier containing a period before an open paren or backtick as a variable
37
37
  className: "variable",
38
38
  begin:
39
- /\b[^(){}\[\]<>\-=,/:\`"'«»\\ →⇒\t\n\r]+\.[^(){}\[\]<>\-=,/:\`"'«»\\ →⇒\t\n\r]+(?=(\(|\`))\b/,
39
+ /\b[^(){}\[\]<>\-=,/:\`"'«»\\ →⇒\t\n\r]+\.[^(){}\[\]<>\?!&\|\-=,/:\`"'«»\\ →⇒\t\n\r]+(?=(\(|\`))\b/,
40
40
  },
41
41
  {
42
42
  className: "built_in",
@@ -46,7 +46,11 @@ export default function origamiHighlightDefinition(hljs) {
46
46
  {
47
47
  // Treat remaining identifiers as variables
48
48
  className: "variable",
49
- begin: /\b[^(){}\[\]<>\-=,/:\`"'«»\\ →⇒\t\n\r]+\b/,
49
+ begin: /\b[^(){}\[\]<>\?!&\|\-=,/:\`"'«»\\ →⇒\t\n\r]+\b/,
50
+ },
51
+ {
52
+ className: "operator",
53
+ begin: /===|!==|==|!=|=>|⇒|->|→|=|\.\.\.|…|&&|\|\||!|\?\?/,
50
54
  },
51
55
  ],
52
56
  };
package/src/tree/tree.js CHANGED
@@ -44,6 +44,7 @@ export const isTreelike = Tree.isTreelike;
44
44
  export const mapReduce = Tree.mapReduce;
45
45
  export const paths = Tree.paths;
46
46
  export const remove = Tree.remove;
47
+ export const root = Tree.root;
47
48
  export const traverse = Tree.traverse;
48
49
  export const traverseOrThrow = Tree.traverseOrThrow;
49
50
  export const traversePath = Tree.traversePath;