@weborigami/language 0.6.6 → 0.6.8
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/index.ts +8 -2
- package/main.js +2 -1
- package/package.json +2 -2
- package/src/compiler/compile.js +1 -0
- package/src/compiler/origami.pegjs +2 -2
- package/src/compiler/parse.js +140 -80
- package/src/handlers/ori_handler.js +1 -1
- package/src/handlers/oridocument_handler.js +1 -1
- package/src/handlers/txt_handler.js +1 -1
- package/src/handlers/yaml_handler.js +2 -2
- package/src/project/coreGlobals.js +25 -3
- package/src/project/projectConfig.js +13 -17
- package/src/project/projectGlobals.js +35 -11
- package/src/project/projectRoot.js +1 -1
- package/src/project/projectRootFromPath.js +35 -34
- package/src/protocols/fetchAndHandleExtension.js +4 -2
- package/src/protocols/files.js +8 -6
- package/src/protocols/http.js +4 -2
- package/src/protocols/https.js +4 -2
- package/src/runtime/WatchFilesMixin.js +5 -7
- package/src/runtime/assignPropertyDescriptors.js +23 -0
- package/src/runtime/evaluate.js +4 -4
- package/src/runtime/expressionFunction.js +1 -3
- package/src/runtime/expressionObject.js +3 -0
- package/src/runtime/handleExtension.js +4 -22
- package/src/runtime/mergeTrees.js +5 -16
- package/test/project/projectConfig.test.js +14 -16
- package/test/project/projectRootFromPath.test.js +2 -2
- package/test/protocols/package.test.js +4 -3
- package/test/runtime/evaluate.test.js +3 -3
- package/src/project/builtins.js +0 -5
package/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origami is a JavaScript project, but we use TypeScript as an internal tool to
|
|
3
|
+
* confirm our code is type safe.
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { SyncOrAsyncMap, UnpackFunction } from "@weborigami/async-tree";
|
|
2
7
|
|
|
8
|
+
// Re-export all exports from main.js
|
|
3
9
|
export * from "./main.js";
|
|
4
10
|
|
|
5
11
|
/**
|
|
@@ -57,8 +63,8 @@ export type Position = {
|
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
export type RuntimeState = {
|
|
60
|
-
/** The container (e.g., file system) that holds the code */
|
|
61
|
-
|
|
66
|
+
/** The container (e.g., file system folder) that holds the code */
|
|
67
|
+
parent?: SyncOrAsyncMap | null;
|
|
62
68
|
/** The object to which this code is attached */
|
|
63
69
|
object?: SyncOrAsyncMap | null;
|
|
64
70
|
/** The current stack of function parameter assignments */
|
package/main.js
CHANGED
|
@@ -2,8 +2,9 @@ export * from "./src/runtime/internal.js";
|
|
|
2
2
|
|
|
3
3
|
export * as compile from "./src/compiler/compile.js";
|
|
4
4
|
export { default as isOrigamiFrontMatter } from "./src/compiler/isOrigamiFrontMatter.js";
|
|
5
|
+
export { parse } from "./src/compiler/parse.js";
|
|
6
|
+
export * from "./src/compiler/parserHelpers.js";
|
|
5
7
|
export * as Handlers from "./src/handlers/handlers.js";
|
|
6
|
-
export { default as builtins } from "./src/project/builtins.js";
|
|
7
8
|
export { default as coreGlobals } from "./src/project/coreGlobals.js";
|
|
8
9
|
export { default as jsGlobals } from "./src/project/jsGlobals.js";
|
|
9
10
|
export { default as projectConfig } from "./src/project/projectConfig.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/language",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"description": "Web Origami expression language compiler and runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"typescript": "5.9.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/async-tree": "0.6.
|
|
14
|
+
"@weborigami/async-tree": "0.6.8",
|
|
15
15
|
"exif-parser": "0.1.12",
|
|
16
16
|
"watcher": "2.3.1",
|
|
17
17
|
"yaml": "2.8.1"
|
package/src/compiler/compile.js
CHANGED
package/src/compiler/parse.js
CHANGED
|
@@ -455,13 +455,14 @@ function peg$parse(input, options) {
|
|
|
455
455
|
const peg$r15 = /^[0-7]/;
|
|
456
456
|
const peg$r16 = /^[gimuy]/;
|
|
457
457
|
const peg$r17 = /^[^\/\n\r]/;
|
|
458
|
-
const peg$r18 = /^[
|
|
459
|
-
const peg$r19 = /^[
|
|
460
|
-
const peg$r20 = /^[
|
|
461
|
-
const peg$r21 = /^[
|
|
462
|
-
const peg$r22 = /^[
|
|
463
|
-
const peg$r23 = /^[a-
|
|
464
|
-
const peg$r24 = /^[
|
|
458
|
+
const peg$r18 = /^[s]/;
|
|
459
|
+
const peg$r19 = /^[^\n\r]/;
|
|
460
|
+
const peg$r20 = /^[!+]/;
|
|
461
|
+
const peg$r21 = /^[\/)\]}]/;
|
|
462
|
+
const peg$r22 = /^[^\/,)\]}]/;
|
|
463
|
+
const peg$r23 = /^[a-z]/;
|
|
464
|
+
const peg$r24 = /^[a-z0-9+-.]/;
|
|
465
|
+
const peg$r25 = /^[:]/;
|
|
465
466
|
|
|
466
467
|
const peg$e0 = peg$literalExpectation("+", false);
|
|
467
468
|
const peg$e1 = peg$literalExpectation("<", false);
|
|
@@ -566,32 +567,33 @@ function peg$parse(input, options) {
|
|
|
566
567
|
const peg$e100 = peg$literalExpectation("<=", false);
|
|
567
568
|
const peg$e101 = peg$literalExpectation(">=", false);
|
|
568
569
|
const peg$e102 = peg$literalExpectation("instanceof", false);
|
|
569
|
-
const peg$e103 = peg$
|
|
570
|
-
const peg$e104 = peg$literalExpectation("
|
|
571
|
-
const peg$e105 = peg$
|
|
572
|
-
const peg$e106 = peg$
|
|
573
|
-
const peg$e107 = peg$literalExpectation("
|
|
574
|
-
const peg$e108 = peg$literalExpectation("
|
|
575
|
-
const peg$e109 = peg$
|
|
576
|
-
const peg$e110 = peg$
|
|
577
|
-
const peg$e111 = peg$literalExpectation("
|
|
578
|
-
const peg$e112 = peg$
|
|
579
|
-
const peg$e113 = peg$otherExpectation("string");
|
|
580
|
-
const peg$e114 = peg$
|
|
581
|
-
const peg$e115 = peg$
|
|
582
|
-
const peg$e116 = peg$otherExpectation("template
|
|
583
|
-
const peg$e117 = peg$otherExpectation("template
|
|
584
|
-
const peg$e118 = peg$
|
|
585
|
-
const peg$e119 = peg$
|
|
586
|
-
const peg$e120 = peg$
|
|
587
|
-
const peg$e121 = peg$
|
|
588
|
-
const peg$e122 = peg$literalExpectation("
|
|
589
|
-
const peg$e123 = peg$literalExpectation("
|
|
590
|
-
const peg$e124 = peg$
|
|
591
|
-
const peg$e125 = peg$
|
|
592
|
-
const peg$e126 = peg$
|
|
593
|
-
const peg$e127 = peg$classExpectation([["a", "z"]
|
|
594
|
-
const peg$e128 = peg$classExpectation(["
|
|
570
|
+
const peg$e103 = peg$classExpectation(["s"], false, false, false);
|
|
571
|
+
const peg$e104 = peg$literalExpectation("in", false);
|
|
572
|
+
const peg$e105 = peg$literalExpectation("#!", false);
|
|
573
|
+
const peg$e106 = peg$classExpectation(["\n", "\r"], true, false, false);
|
|
574
|
+
const peg$e107 = peg$literalExpectation("<<", false);
|
|
575
|
+
const peg$e108 = peg$literalExpectation(">>>", false);
|
|
576
|
+
const peg$e109 = peg$literalExpectation(">>", false);
|
|
577
|
+
const peg$e110 = peg$otherExpectation("lambda function");
|
|
578
|
+
const peg$e111 = peg$literalExpectation("\u2192", false);
|
|
579
|
+
const peg$e112 = peg$literalExpectation("->", false);
|
|
580
|
+
const peg$e113 = peg$otherExpectation("single quote string");
|
|
581
|
+
const peg$e114 = peg$otherExpectation("string");
|
|
582
|
+
const peg$e115 = peg$literalExpectation("${", false);
|
|
583
|
+
const peg$e116 = peg$otherExpectation("template document");
|
|
584
|
+
const peg$e117 = peg$otherExpectation("template literal");
|
|
585
|
+
const peg$e118 = peg$otherExpectation("template substitution");
|
|
586
|
+
const peg$e119 = peg$classExpectation(["!", "+"], false, false, false);
|
|
587
|
+
const peg$e120 = peg$literalExpectation("~", false);
|
|
588
|
+
const peg$e121 = peg$classExpectation(["/", ")", "]", "}"], false, false, false);
|
|
589
|
+
const peg$e122 = peg$literalExpectation("await", false);
|
|
590
|
+
const peg$e123 = peg$literalExpectation("typeof", false);
|
|
591
|
+
const peg$e124 = peg$literalExpectation("void", false);
|
|
592
|
+
const peg$e125 = peg$classExpectation(["/", ",", ")", "]", "}"], true, false, false);
|
|
593
|
+
const peg$e126 = peg$otherExpectation("slash-separated path");
|
|
594
|
+
const peg$e127 = peg$classExpectation([["a", "z"]], false, false, false);
|
|
595
|
+
const peg$e128 = peg$classExpectation([["a", "z"], ["0", "9"], ["+", "."]], false, false, false);
|
|
596
|
+
const peg$e129 = peg$classExpectation([":"], false, false, false);
|
|
595
597
|
|
|
596
598
|
function peg$f0() {
|
|
597
599
|
return null;
|
|
@@ -6353,7 +6355,7 @@ function peg$parse(input, options) {
|
|
|
6353
6355
|
}
|
|
6354
6356
|
|
|
6355
6357
|
function peg$parserelationalOperator() {
|
|
6356
|
-
let s0;
|
|
6358
|
+
let s0, s1, s2, s3;
|
|
6357
6359
|
|
|
6358
6360
|
if (input.substr(peg$currPos, 2) === peg$c59) {
|
|
6359
6361
|
s0 = peg$c59;
|
|
@@ -6387,20 +6389,78 @@ function peg$parse(input, options) {
|
|
|
6387
6389
|
if (peg$silentFails === 0) { peg$fail(peg$e3); }
|
|
6388
6390
|
}
|
|
6389
6391
|
if (s0 === peg$FAILED) {
|
|
6392
|
+
s0 = peg$currPos;
|
|
6390
6393
|
if (input.substr(peg$currPos, 10) === peg$c61) {
|
|
6391
|
-
|
|
6394
|
+
s1 = peg$c61;
|
|
6392
6395
|
peg$currPos += 10;
|
|
6393
6396
|
} else {
|
|
6394
|
-
|
|
6397
|
+
s1 = peg$FAILED;
|
|
6395
6398
|
if (peg$silentFails === 0) { peg$fail(peg$e102); }
|
|
6396
6399
|
}
|
|
6400
|
+
if (s1 !== peg$FAILED) {
|
|
6401
|
+
s2 = peg$currPos;
|
|
6402
|
+
peg$silentFails++;
|
|
6403
|
+
s3 = input.charAt(peg$currPos);
|
|
6404
|
+
if (peg$r18.test(s3)) {
|
|
6405
|
+
peg$currPos++;
|
|
6406
|
+
} else {
|
|
6407
|
+
s3 = peg$FAILED;
|
|
6408
|
+
if (peg$silentFails === 0) { peg$fail(peg$e103); }
|
|
6409
|
+
}
|
|
6410
|
+
peg$silentFails--;
|
|
6411
|
+
if (s3 !== peg$FAILED) {
|
|
6412
|
+
peg$currPos = s2;
|
|
6413
|
+
s2 = undefined;
|
|
6414
|
+
} else {
|
|
6415
|
+
s2 = peg$FAILED;
|
|
6416
|
+
}
|
|
6417
|
+
if (s2 !== peg$FAILED) {
|
|
6418
|
+
s1 = [s1, s2];
|
|
6419
|
+
s0 = s1;
|
|
6420
|
+
} else {
|
|
6421
|
+
peg$currPos = s0;
|
|
6422
|
+
s0 = peg$FAILED;
|
|
6423
|
+
}
|
|
6424
|
+
} else {
|
|
6425
|
+
peg$currPos = s0;
|
|
6426
|
+
s0 = peg$FAILED;
|
|
6427
|
+
}
|
|
6397
6428
|
if (s0 === peg$FAILED) {
|
|
6429
|
+
s0 = peg$currPos;
|
|
6398
6430
|
if (input.substr(peg$currPos, 2) === peg$c62) {
|
|
6399
|
-
|
|
6431
|
+
s1 = peg$c62;
|
|
6400
6432
|
peg$currPos += 2;
|
|
6401
6433
|
} else {
|
|
6434
|
+
s1 = peg$FAILED;
|
|
6435
|
+
if (peg$silentFails === 0) { peg$fail(peg$e104); }
|
|
6436
|
+
}
|
|
6437
|
+
if (s1 !== peg$FAILED) {
|
|
6438
|
+
s2 = peg$currPos;
|
|
6439
|
+
peg$silentFails++;
|
|
6440
|
+
s3 = input.charAt(peg$currPos);
|
|
6441
|
+
if (peg$r18.test(s3)) {
|
|
6442
|
+
peg$currPos++;
|
|
6443
|
+
} else {
|
|
6444
|
+
s3 = peg$FAILED;
|
|
6445
|
+
if (peg$silentFails === 0) { peg$fail(peg$e103); }
|
|
6446
|
+
}
|
|
6447
|
+
peg$silentFails--;
|
|
6448
|
+
if (s3 !== peg$FAILED) {
|
|
6449
|
+
peg$currPos = s2;
|
|
6450
|
+
s2 = undefined;
|
|
6451
|
+
} else {
|
|
6452
|
+
s2 = peg$FAILED;
|
|
6453
|
+
}
|
|
6454
|
+
if (s2 !== peg$FAILED) {
|
|
6455
|
+
s1 = [s1, s2];
|
|
6456
|
+
s0 = s1;
|
|
6457
|
+
} else {
|
|
6458
|
+
peg$currPos = s0;
|
|
6459
|
+
s0 = peg$FAILED;
|
|
6460
|
+
}
|
|
6461
|
+
} else {
|
|
6462
|
+
peg$currPos = s0;
|
|
6402
6463
|
s0 = peg$FAILED;
|
|
6403
|
-
if (peg$silentFails === 0) { peg$fail(peg$e103); }
|
|
6404
6464
|
}
|
|
6405
6465
|
}
|
|
6406
6466
|
}
|
|
@@ -6454,25 +6514,25 @@ function peg$parse(input, options) {
|
|
|
6454
6514
|
peg$currPos += 2;
|
|
6455
6515
|
} else {
|
|
6456
6516
|
s1 = peg$FAILED;
|
|
6457
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6517
|
+
if (peg$silentFails === 0) { peg$fail(peg$e105); }
|
|
6458
6518
|
}
|
|
6459
6519
|
if (s1 !== peg$FAILED) {
|
|
6460
6520
|
s2 = [];
|
|
6461
6521
|
s3 = input.charAt(peg$currPos);
|
|
6462
|
-
if (peg$
|
|
6522
|
+
if (peg$r19.test(s3)) {
|
|
6463
6523
|
peg$currPos++;
|
|
6464
6524
|
} else {
|
|
6465
6525
|
s3 = peg$FAILED;
|
|
6466
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6526
|
+
if (peg$silentFails === 0) { peg$fail(peg$e106); }
|
|
6467
6527
|
}
|
|
6468
6528
|
while (s3 !== peg$FAILED) {
|
|
6469
6529
|
s2.push(s3);
|
|
6470
6530
|
s3 = input.charAt(peg$currPos);
|
|
6471
|
-
if (peg$
|
|
6531
|
+
if (peg$r19.test(s3)) {
|
|
6472
6532
|
peg$currPos++;
|
|
6473
6533
|
} else {
|
|
6474
6534
|
s3 = peg$FAILED;
|
|
6475
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6535
|
+
if (peg$silentFails === 0) { peg$fail(peg$e106); }
|
|
6476
6536
|
}
|
|
6477
6537
|
}
|
|
6478
6538
|
peg$savedPos = s0;
|
|
@@ -6559,7 +6619,7 @@ function peg$parse(input, options) {
|
|
|
6559
6619
|
peg$currPos += 2;
|
|
6560
6620
|
} else {
|
|
6561
6621
|
s0 = peg$FAILED;
|
|
6562
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6622
|
+
if (peg$silentFails === 0) { peg$fail(peg$e107); }
|
|
6563
6623
|
}
|
|
6564
6624
|
if (s0 === peg$FAILED) {
|
|
6565
6625
|
if (input.substr(peg$currPos, 3) === peg$c65) {
|
|
@@ -6567,7 +6627,7 @@ function peg$parse(input, options) {
|
|
|
6567
6627
|
peg$currPos += 3;
|
|
6568
6628
|
} else {
|
|
6569
6629
|
s0 = peg$FAILED;
|
|
6570
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6630
|
+
if (peg$silentFails === 0) { peg$fail(peg$e108); }
|
|
6571
6631
|
}
|
|
6572
6632
|
if (s0 === peg$FAILED) {
|
|
6573
6633
|
if (input.substr(peg$currPos, 2) === peg$c66) {
|
|
@@ -6575,7 +6635,7 @@ function peg$parse(input, options) {
|
|
|
6575
6635
|
peg$currPos += 2;
|
|
6576
6636
|
} else {
|
|
6577
6637
|
s0 = peg$FAILED;
|
|
6578
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6638
|
+
if (peg$silentFails === 0) { peg$fail(peg$e109); }
|
|
6579
6639
|
}
|
|
6580
6640
|
}
|
|
6581
6641
|
}
|
|
@@ -6645,7 +6705,7 @@ function peg$parse(input, options) {
|
|
|
6645
6705
|
peg$silentFails--;
|
|
6646
6706
|
if (s0 === peg$FAILED) {
|
|
6647
6707
|
s1 = peg$FAILED;
|
|
6648
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6708
|
+
if (peg$silentFails === 0) { peg$fail(peg$e110); }
|
|
6649
6709
|
}
|
|
6650
6710
|
|
|
6651
6711
|
return s0;
|
|
@@ -6659,7 +6719,7 @@ function peg$parse(input, options) {
|
|
|
6659
6719
|
peg$currPos++;
|
|
6660
6720
|
} else {
|
|
6661
6721
|
s0 = peg$FAILED;
|
|
6662
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6722
|
+
if (peg$silentFails === 0) { peg$fail(peg$e111); }
|
|
6663
6723
|
}
|
|
6664
6724
|
if (s0 === peg$FAILED) {
|
|
6665
6725
|
if (input.substr(peg$currPos, 2) === peg$c68) {
|
|
@@ -6667,7 +6727,7 @@ function peg$parse(input, options) {
|
|
|
6667
6727
|
peg$currPos += 2;
|
|
6668
6728
|
} else {
|
|
6669
6729
|
s0 = peg$FAILED;
|
|
6670
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6730
|
+
if (peg$silentFails === 0) { peg$fail(peg$e112); }
|
|
6671
6731
|
}
|
|
6672
6732
|
}
|
|
6673
6733
|
|
|
@@ -6688,20 +6748,20 @@ function peg$parse(input, options) {
|
|
|
6688
6748
|
if (s1 !== peg$FAILED) {
|
|
6689
6749
|
s2 = [];
|
|
6690
6750
|
s3 = input.charAt(peg$currPos);
|
|
6691
|
-
if (peg$
|
|
6751
|
+
if (peg$r19.test(s3)) {
|
|
6692
6752
|
peg$currPos++;
|
|
6693
6753
|
} else {
|
|
6694
6754
|
s3 = peg$FAILED;
|
|
6695
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6755
|
+
if (peg$silentFails === 0) { peg$fail(peg$e106); }
|
|
6696
6756
|
}
|
|
6697
6757
|
while (s3 !== peg$FAILED) {
|
|
6698
6758
|
s2.push(s3);
|
|
6699
6759
|
s3 = input.charAt(peg$currPos);
|
|
6700
|
-
if (peg$
|
|
6760
|
+
if (peg$r19.test(s3)) {
|
|
6701
6761
|
peg$currPos++;
|
|
6702
6762
|
} else {
|
|
6703
6763
|
s3 = peg$FAILED;
|
|
6704
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6764
|
+
if (peg$silentFails === 0) { peg$fail(peg$e106); }
|
|
6705
6765
|
}
|
|
6706
6766
|
}
|
|
6707
6767
|
peg$savedPos = s0;
|
|
@@ -6748,7 +6808,7 @@ function peg$parse(input, options) {
|
|
|
6748
6808
|
peg$silentFails--;
|
|
6749
6809
|
if (s0 === peg$FAILED) {
|
|
6750
6810
|
s1 = peg$FAILED;
|
|
6751
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6811
|
+
if (peg$silentFails === 0) { peg$fail(peg$e113); }
|
|
6752
6812
|
}
|
|
6753
6813
|
|
|
6754
6814
|
return s0;
|
|
@@ -6921,7 +6981,7 @@ function peg$parse(input, options) {
|
|
|
6921
6981
|
peg$silentFails--;
|
|
6922
6982
|
if (s0 === peg$FAILED) {
|
|
6923
6983
|
s1 = peg$FAILED;
|
|
6924
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
6984
|
+
if (peg$silentFails === 0) { peg$fail(peg$e114); }
|
|
6925
6985
|
}
|
|
6926
6986
|
|
|
6927
6987
|
return s0;
|
|
@@ -6975,7 +7035,7 @@ function peg$parse(input, options) {
|
|
|
6975
7035
|
peg$currPos += 2;
|
|
6976
7036
|
} else {
|
|
6977
7037
|
s2 = peg$FAILED;
|
|
6978
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7038
|
+
if (peg$silentFails === 0) { peg$fail(peg$e115); }
|
|
6979
7039
|
}
|
|
6980
7040
|
peg$silentFails--;
|
|
6981
7041
|
if (s2 === peg$FAILED) {
|
|
@@ -7056,7 +7116,7 @@ function peg$parse(input, options) {
|
|
|
7056
7116
|
peg$silentFails--;
|
|
7057
7117
|
if (s0 === peg$FAILED) {
|
|
7058
7118
|
s1 = peg$FAILED;
|
|
7059
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7119
|
+
if (peg$silentFails === 0) { peg$fail(peg$e116); }
|
|
7060
7120
|
}
|
|
7061
7121
|
|
|
7062
7122
|
return s0;
|
|
@@ -7115,7 +7175,7 @@ function peg$parse(input, options) {
|
|
|
7115
7175
|
peg$silentFails--;
|
|
7116
7176
|
if (s0 === peg$FAILED) {
|
|
7117
7177
|
s1 = peg$FAILED;
|
|
7118
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7178
|
+
if (peg$silentFails === 0) { peg$fail(peg$e117); }
|
|
7119
7179
|
}
|
|
7120
7180
|
|
|
7121
7181
|
return s0;
|
|
@@ -7140,7 +7200,7 @@ function peg$parse(input, options) {
|
|
|
7140
7200
|
peg$currPos += 2;
|
|
7141
7201
|
} else {
|
|
7142
7202
|
s2 = peg$FAILED;
|
|
7143
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7203
|
+
if (peg$silentFails === 0) { peg$fail(peg$e115); }
|
|
7144
7204
|
}
|
|
7145
7205
|
}
|
|
7146
7206
|
peg$silentFails--;
|
|
@@ -7193,7 +7253,7 @@ function peg$parse(input, options) {
|
|
|
7193
7253
|
peg$currPos += 2;
|
|
7194
7254
|
} else {
|
|
7195
7255
|
s1 = peg$FAILED;
|
|
7196
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7256
|
+
if (peg$silentFails === 0) { peg$fail(peg$e115); }
|
|
7197
7257
|
}
|
|
7198
7258
|
if (s1 !== peg$FAILED) {
|
|
7199
7259
|
s2 = peg$parseexpectExpression();
|
|
@@ -7223,7 +7283,7 @@ function peg$parse(input, options) {
|
|
|
7223
7283
|
peg$silentFails--;
|
|
7224
7284
|
if (s0 === peg$FAILED) {
|
|
7225
7285
|
s1 = peg$FAILED;
|
|
7226
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7286
|
+
if (peg$silentFails === 0) { peg$fail(peg$e118); }
|
|
7227
7287
|
}
|
|
7228
7288
|
|
|
7229
7289
|
return s0;
|
|
@@ -7276,11 +7336,11 @@ function peg$parse(input, options) {
|
|
|
7276
7336
|
let s0, s1, s2, s3;
|
|
7277
7337
|
|
|
7278
7338
|
s0 = input.charAt(peg$currPos);
|
|
7279
|
-
if (peg$
|
|
7339
|
+
if (peg$r20.test(s0)) {
|
|
7280
7340
|
peg$currPos++;
|
|
7281
7341
|
} else {
|
|
7282
7342
|
s0 = peg$FAILED;
|
|
7283
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7343
|
+
if (peg$silentFails === 0) { peg$fail(peg$e119); }
|
|
7284
7344
|
}
|
|
7285
7345
|
if (s0 === peg$FAILED) {
|
|
7286
7346
|
s0 = peg$currPos;
|
|
@@ -7289,17 +7349,17 @@ function peg$parse(input, options) {
|
|
|
7289
7349
|
peg$currPos++;
|
|
7290
7350
|
} else {
|
|
7291
7351
|
s1 = peg$FAILED;
|
|
7292
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7352
|
+
if (peg$silentFails === 0) { peg$fail(peg$e120); }
|
|
7293
7353
|
}
|
|
7294
7354
|
if (s1 !== peg$FAILED) {
|
|
7295
7355
|
s2 = peg$currPos;
|
|
7296
7356
|
peg$silentFails++;
|
|
7297
7357
|
s3 = input.charAt(peg$currPos);
|
|
7298
|
-
if (peg$
|
|
7358
|
+
if (peg$r21.test(s3)) {
|
|
7299
7359
|
peg$currPos++;
|
|
7300
7360
|
} else {
|
|
7301
7361
|
s3 = peg$FAILED;
|
|
7302
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7362
|
+
if (peg$silentFails === 0) { peg$fail(peg$e121); }
|
|
7303
7363
|
}
|
|
7304
7364
|
peg$silentFails--;
|
|
7305
7365
|
if (s3 === peg$FAILED) {
|
|
@@ -7327,7 +7387,7 @@ function peg$parse(input, options) {
|
|
|
7327
7387
|
peg$currPos += 5;
|
|
7328
7388
|
} else {
|
|
7329
7389
|
s1 = peg$FAILED;
|
|
7330
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7390
|
+
if (peg$silentFails === 0) { peg$fail(peg$e122); }
|
|
7331
7391
|
}
|
|
7332
7392
|
if (s1 !== peg$FAILED) {
|
|
7333
7393
|
s2 = peg$currPos;
|
|
@@ -7357,7 +7417,7 @@ function peg$parse(input, options) {
|
|
|
7357
7417
|
peg$currPos += 6;
|
|
7358
7418
|
} else {
|
|
7359
7419
|
s1 = peg$FAILED;
|
|
7360
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7420
|
+
if (peg$silentFails === 0) { peg$fail(peg$e123); }
|
|
7361
7421
|
}
|
|
7362
7422
|
if (s1 !== peg$FAILED) {
|
|
7363
7423
|
s2 = peg$currPos;
|
|
@@ -7387,7 +7447,7 @@ function peg$parse(input, options) {
|
|
|
7387
7447
|
peg$currPos += 4;
|
|
7388
7448
|
} else {
|
|
7389
7449
|
s1 = peg$FAILED;
|
|
7390
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7450
|
+
if (peg$silentFails === 0) { peg$fail(peg$e124); }
|
|
7391
7451
|
}
|
|
7392
7452
|
if (s1 !== peg$FAILED) {
|
|
7393
7453
|
s2 = peg$currPos;
|
|
@@ -7563,11 +7623,11 @@ function peg$parse(input, options) {
|
|
|
7563
7623
|
|
|
7564
7624
|
s0 = peg$currPos;
|
|
7565
7625
|
s1 = input.charAt(peg$currPos);
|
|
7566
|
-
if (peg$
|
|
7626
|
+
if (peg$r22.test(s1)) {
|
|
7567
7627
|
peg$currPos++;
|
|
7568
7628
|
} else {
|
|
7569
7629
|
s1 = peg$FAILED;
|
|
7570
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7630
|
+
if (peg$silentFails === 0) { peg$fail(peg$e125); }
|
|
7571
7631
|
}
|
|
7572
7632
|
if (s1 !== peg$FAILED) {
|
|
7573
7633
|
s2 = peg$currPos;
|
|
@@ -7630,7 +7690,7 @@ function peg$parse(input, options) {
|
|
|
7630
7690
|
peg$silentFails--;
|
|
7631
7691
|
if (s0 === peg$FAILED) {
|
|
7632
7692
|
s1 = peg$FAILED;
|
|
7633
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7693
|
+
if (peg$silentFails === 0) { peg$fail(peg$e126); }
|
|
7634
7694
|
}
|
|
7635
7695
|
|
|
7636
7696
|
return s0;
|
|
@@ -7641,37 +7701,37 @@ function peg$parse(input, options) {
|
|
|
7641
7701
|
|
|
7642
7702
|
s0 = peg$currPos;
|
|
7643
7703
|
s1 = input.charAt(peg$currPos);
|
|
7644
|
-
if (peg$
|
|
7704
|
+
if (peg$r23.test(s1)) {
|
|
7645
7705
|
peg$currPos++;
|
|
7646
7706
|
} else {
|
|
7647
7707
|
s1 = peg$FAILED;
|
|
7648
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7708
|
+
if (peg$silentFails === 0) { peg$fail(peg$e127); }
|
|
7649
7709
|
}
|
|
7650
7710
|
if (s1 !== peg$FAILED) {
|
|
7651
7711
|
s2 = [];
|
|
7652
7712
|
s3 = input.charAt(peg$currPos);
|
|
7653
|
-
if (peg$
|
|
7713
|
+
if (peg$r24.test(s3)) {
|
|
7654
7714
|
peg$currPos++;
|
|
7655
7715
|
} else {
|
|
7656
7716
|
s3 = peg$FAILED;
|
|
7657
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7717
|
+
if (peg$silentFails === 0) { peg$fail(peg$e128); }
|
|
7658
7718
|
}
|
|
7659
7719
|
while (s3 !== peg$FAILED) {
|
|
7660
7720
|
s2.push(s3);
|
|
7661
7721
|
s3 = input.charAt(peg$currPos);
|
|
7662
|
-
if (peg$
|
|
7722
|
+
if (peg$r24.test(s3)) {
|
|
7663
7723
|
peg$currPos++;
|
|
7664
7724
|
} else {
|
|
7665
7725
|
s3 = peg$FAILED;
|
|
7666
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7726
|
+
if (peg$silentFails === 0) { peg$fail(peg$e128); }
|
|
7667
7727
|
}
|
|
7668
7728
|
}
|
|
7669
7729
|
s3 = input.charAt(peg$currPos);
|
|
7670
|
-
if (peg$
|
|
7730
|
+
if (peg$r25.test(s3)) {
|
|
7671
7731
|
peg$currPos++;
|
|
7672
7732
|
} else {
|
|
7673
7733
|
s3 = peg$FAILED;
|
|
7674
|
-
if (peg$silentFails === 0) { peg$fail(peg$
|
|
7734
|
+
if (peg$silentFails === 0) { peg$fail(peg$e129); }
|
|
7675
7735
|
}
|
|
7676
7736
|
if (s3 !== peg$FAILED) {
|
|
7677
7737
|
peg$savedPos = s0;
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
|
|
19
19
|
// Compile the source code as an Origami program
|
|
20
20
|
const compiler = options.compiler ?? compile.program;
|
|
21
|
-
const globals = options.globals ?? (await projectGlobals());
|
|
21
|
+
const globals = options.globals ?? (await projectGlobals(parent));
|
|
22
22
|
const fn = compiler(source, {
|
|
23
23
|
globals,
|
|
24
24
|
mode: "program",
|
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
const source = getSource(packed, options);
|
|
17
17
|
|
|
18
18
|
// Compile the source code as an Origami template document
|
|
19
|
-
const globals = options.globals ?? (await projectGlobals());
|
|
19
|
+
const globals = options.globals ?? (await projectGlobals(parent));
|
|
20
20
|
const defineFn = compile.templateDocument(source, {
|
|
21
21
|
front: options.front,
|
|
22
22
|
globals,
|
|
@@ -80,7 +80,7 @@ export default {
|
|
|
80
80
|
const { body, frontText, isOrigami } = parsed;
|
|
81
81
|
let frontData;
|
|
82
82
|
if (isOrigami) {
|
|
83
|
-
const globals = await projectGlobals();
|
|
83
|
+
const globals = await projectGlobals(parent);
|
|
84
84
|
const compiled = compile.expression(frontText.trim(), {
|
|
85
85
|
globals,
|
|
86
86
|
parent,
|
|
@@ -98,7 +98,7 @@ export default {
|
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
async function oriCallTagForParent(parent, options, yaml) {
|
|
101
|
-
const globals = await projectGlobals();
|
|
101
|
+
const globals = await projectGlobals(parent);
|
|
102
102
|
return {
|
|
103
103
|
collection: "seq",
|
|
104
104
|
|
|
@@ -162,7 +162,7 @@ async function oriCallTagForParent(parent, options, yaml) {
|
|
|
162
162
|
// Define the !ori tag for YAML parsing. This will run in the context of the
|
|
163
163
|
// supplied parent.
|
|
164
164
|
async function oriTagForParent(parent, options, yaml) {
|
|
165
|
-
const globals = await projectGlobals();
|
|
165
|
+
const globals = await projectGlobals(parent);
|
|
166
166
|
return {
|
|
167
167
|
resolve(text) {
|
|
168
168
|
hasOriTags = true;
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
import { Tree } from "@weborigami/async-tree";
|
|
2
2
|
import protocolGlobals from "../protocols/protocolGlobals.js";
|
|
3
3
|
import * as protocols from "../protocols/protocols.js";
|
|
4
|
-
import builtins from "./builtins.js";
|
|
5
4
|
import jsGlobals from "./jsGlobals.js";
|
|
6
5
|
|
|
6
|
+
let globals;
|
|
7
|
+
|
|
7
8
|
export default async function coreGlobals() {
|
|
9
|
+
if (globals) {
|
|
10
|
+
return globals;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Dynamic import to avoid circular dependency
|
|
8
14
|
const handlerGlobals = await import("../handlers/handlers.js");
|
|
9
|
-
|
|
15
|
+
|
|
16
|
+
let origamiBuiltins;
|
|
17
|
+
if (!origamiBuiltins) {
|
|
18
|
+
// This dynamic import is for a different reason. We want to load the
|
|
19
|
+
// Origami builtins if they're available, but not fail if they're not. This
|
|
20
|
+
// lets someone use the language package without installing the origami
|
|
21
|
+
// package. This arrangement is unorthodox but expedient.
|
|
22
|
+
try {
|
|
23
|
+
origamiBuiltins = await import("@weborigami/origami");
|
|
24
|
+
} catch {
|
|
25
|
+
origamiBuiltins = {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
globals = {
|
|
10
30
|
...jsGlobals,
|
|
11
31
|
Tree,
|
|
12
32
|
Protocol: protocols,
|
|
13
33
|
...protocolGlobals,
|
|
14
34
|
...handlerGlobals,
|
|
15
|
-
...
|
|
35
|
+
...origamiBuiltins,
|
|
16
36
|
};
|
|
37
|
+
|
|
38
|
+
return globals;
|
|
17
39
|
}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { toString, Tree } from "@weborigami/async-tree";
|
|
2
2
|
import ori_handler from "../handlers/ori_handler.js";
|
|
3
3
|
import coreGlobals from "./coreGlobals.js";
|
|
4
|
-
import projectRootFromPath from "./projectRootFromPath.js";
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Given a container, return the Origami configuration for the associated
|
|
7
|
+
* project root. This will be the unpacked config.ori file if it exists, or an
|
|
8
|
+
* empty object otherwise.
|
|
9
|
+
*
|
|
10
|
+
* @typedef {import("@weborigami/async-tree").SyncOrAsyncMap} SyncOrAsyncMap
|
|
11
|
+
* @param {SyncOrAsyncMap} parent
|
|
12
|
+
*/
|
|
13
|
+
export default async function config(parent) {
|
|
14
|
+
const projectRoot = await Tree.root(parent);
|
|
7
15
|
|
|
8
|
-
export default async function config(dir = process.cwd()) {
|
|
9
|
-
const root = await projectRootFromPath(dir);
|
|
10
|
-
|
|
11
|
-
const rootPath = root.path;
|
|
12
|
-
const cached = mapPathToConfig.get(rootPath);
|
|
13
|
-
if (cached) {
|
|
14
|
-
return cached;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Use a plain FileMap to avoid loading extension handlers
|
|
18
|
-
const rootFileMap = new FileMap(rootPath);
|
|
19
|
-
const configBuffer = await rootFileMap.get("config.ori");
|
|
20
16
|
let configObject = {};
|
|
17
|
+
const configBuffer = await projectRoot.get("config.ori");
|
|
21
18
|
if (configBuffer) {
|
|
22
19
|
const configText = toString(configBuffer);
|
|
23
20
|
if (configText) {
|
|
@@ -26,11 +23,10 @@ export default async function config(dir = process.cwd()) {
|
|
|
26
23
|
// Evaluate the config file to obtain the configuration object
|
|
27
24
|
configObject = await ori_handler.unpack(configText, {
|
|
28
25
|
globals,
|
|
29
|
-
parent:
|
|
26
|
+
parent: projectRoot,
|
|
30
27
|
});
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
mapPathToConfig.set(rootPath, configObject);
|
|
35
31
|
return configObject;
|
|
36
32
|
}
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
import { Tree } from "@weborigami/async-tree";
|
|
2
|
+
import assignPropertyDescriptors from "../runtime/assignPropertyDescriptors.js";
|
|
1
3
|
import coreGlobals from "./coreGlobals.js";
|
|
2
4
|
import projectConfig from "./projectConfig.js";
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Return the complete set of globals available to code running in the given
|
|
8
|
+
* container. This will be the core globals plus any configuration specified in
|
|
9
|
+
* the project's config.ori file.
|
|
10
|
+
*
|
|
11
|
+
* This destructively caches a `globals` property on the root of the given
|
|
12
|
+
* container.
|
|
13
|
+
*
|
|
14
|
+
* @typedef {import("@weborigami/async-tree").SyncOrAsyncMap} SyncOrAsyncMap
|
|
15
|
+
* @param {SyncOrAsyncMap|null} parent
|
|
16
|
+
*/
|
|
17
|
+
export default async function projectGlobals(parent) {
|
|
18
|
+
if (!parent) {
|
|
19
|
+
return coreGlobals();
|
|
20
|
+
}
|
|
5
21
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (!globals) {
|
|
22
|
+
const projectRoot = await Tree.root(parent);
|
|
23
|
+
if (!projectRoot.globals) {
|
|
9
24
|
// Start with core globals
|
|
10
|
-
globals = await coreGlobals();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
const globals = await coreGlobals();
|
|
26
|
+
|
|
27
|
+
if (parent) {
|
|
28
|
+
// Get config for the given container and add it to the globals. During
|
|
29
|
+
// this read, we want to only rely on core globals to avoid circularities,
|
|
30
|
+
// so we temporarily set globals to coreGlobals.
|
|
31
|
+
projectRoot.globals = globals;
|
|
32
|
+
const config = await projectConfig(parent);
|
|
33
|
+
|
|
34
|
+
// Merge config into globals; don't invoke property getters.
|
|
35
|
+
assignPropertyDescriptors(globals, config);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Cache globals on project root
|
|
39
|
+
projectRoot.globals = globals;
|
|
16
40
|
}
|
|
17
41
|
|
|
18
|
-
return globals;
|
|
42
|
+
return projectRoot.globals;
|
|
19
43
|
}
|
|
@@ -4,6 +4,6 @@ import { Tree } from "@weborigami/async-tree";
|
|
|
4
4
|
* Return an OrigamiFileMap object for the current code context.
|
|
5
5
|
*/
|
|
6
6
|
export default async function projectRoot(state) {
|
|
7
|
-
return Tree.root(state.
|
|
7
|
+
return Tree.root(state.parent);
|
|
8
8
|
}
|
|
9
9
|
projectRoot.needsState = true;
|
|
@@ -5,54 +5,55 @@ import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
|
5
5
|
const configFileName = "config.ori";
|
|
6
6
|
const packageFileName = "package.json";
|
|
7
7
|
|
|
8
|
-
const mapPathToRoot = new Map();
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
|
-
* Return an OrigamiFileMap object for the
|
|
12
|
-
*
|
|
13
|
-
* This searches the current directory and its ancestors for an Origami file
|
|
14
|
-
* called `config.ori`. If an Origami configuration file is found, the
|
|
15
|
-
* containing folder is considered to be the project root.
|
|
9
|
+
* Return an OrigamiFileMap object for the given folder.
|
|
16
10
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
11
|
+
* This searches the given folder and its ancestors for an Origami file called
|
|
12
|
+
* `config.ori`. If an Origami configuration file is found, the containing
|
|
13
|
+
* folder is considered to be the project root.
|
|
19
14
|
*
|
|
15
|
+
* Otherwise this looks for a package.json file to determine the project root.
|
|
16
|
+
* If none is found, the given folder itself is used as the project root.
|
|
20
17
|
*
|
|
21
|
-
* @param {string}
|
|
18
|
+
* @param {string} dirname
|
|
22
19
|
*/
|
|
23
|
-
export default async function projectRootFromPath(dirname
|
|
24
|
-
const cached = mapPathToRoot.get(dirname);
|
|
25
|
-
if (cached) {
|
|
26
|
-
return cached;
|
|
27
|
-
}
|
|
28
|
-
|
|
20
|
+
export default async function projectRootFromPath(dirname) {
|
|
29
21
|
let root;
|
|
30
22
|
let value;
|
|
31
23
|
// Use a plain FileMap to avoid loading extension handlers
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
let currentFolder = new FileMap(dirname);
|
|
25
|
+
while (currentFolder) {
|
|
26
|
+
// Try looking for config file
|
|
27
|
+
value = await currentFolder.get(configFileName);
|
|
28
|
+
if (value) {
|
|
29
|
+
// Found config file
|
|
30
|
+
root = new OrigamiFileMap(currentFolder.path);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
|
|
39
34
|
// Try looking for package.json
|
|
40
|
-
value = await
|
|
35
|
+
value = await currentFolder.get(packageFileName);
|
|
41
36
|
if (value) {
|
|
42
37
|
// Found package.json
|
|
43
|
-
root = new OrigamiFileMap(
|
|
38
|
+
root = new OrigamiFileMap(currentFolder.path);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Move up a folder and try again
|
|
43
|
+
const parentPath = path.dirname(currentFolder.path);
|
|
44
|
+
if (parentPath !== currentFolder.path) {
|
|
45
|
+
currentFolder = new FileMap(parentPath);
|
|
44
46
|
} else {
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
root = await projectRootFromPath(parentPath);
|
|
49
|
-
} else {
|
|
50
|
-
// At filesystem root, use current working directory
|
|
51
|
-
root = new OrigamiFileMap(process.cwd());
|
|
52
|
-
}
|
|
47
|
+
// At filesystem root; not found
|
|
48
|
+
root = null;
|
|
49
|
+
break;
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
if (!root) {
|
|
54
|
+
// Default to using the provided folder as the project root
|
|
55
|
+
root = new OrigamiFileMap(dirname);
|
|
56
|
+
}
|
|
57
|
+
|
|
57
58
|
return root;
|
|
58
59
|
}
|
|
@@ -3,10 +3,12 @@ import handleExtension from "../runtime/handleExtension.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Fetch the resource at the given href.
|
|
5
5
|
*
|
|
6
|
+
* @typedef {import("@weborigami/async-tree").SyncOrAsyncMap} SyncOrAsyncMap
|
|
6
7
|
*
|
|
7
8
|
* @param {string} href
|
|
9
|
+
* @param {SyncOrAsyncMap} parent
|
|
8
10
|
*/
|
|
9
|
-
export default async function fetchAndHandleExtension(href) {
|
|
11
|
+
export default async function fetchAndHandleExtension(href, parent) {
|
|
10
12
|
const response = await fetch(href);
|
|
11
13
|
if (!response.ok) {
|
|
12
14
|
return undefined;
|
|
@@ -22,7 +24,7 @@ export default async function fetchAndHandleExtension(href) {
|
|
|
22
24
|
const url = new URL(href);
|
|
23
25
|
const filename = url.pathname.split("/").pop();
|
|
24
26
|
if (filename) {
|
|
25
|
-
buffer = await handleExtension(buffer, filename);
|
|
27
|
+
buffer = await handleExtension(buffer, filename, parent);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
return buffer;
|
package/src/protocols/files.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import process from "node:process";
|
|
4
3
|
import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
*
|
|
8
|
-
* @param {
|
|
7
|
+
* @param {any[]} args
|
|
9
8
|
*/
|
|
10
|
-
export default async function files(...
|
|
9
|
+
export default async function files(...args) {
|
|
10
|
+
const state = args.pop(); // Remaining args are the path
|
|
11
|
+
|
|
11
12
|
// If path begins with `~`, treat it relative to the home directory.
|
|
12
|
-
// Otherwise, treat it relative to the current
|
|
13
|
-
let relativePath =
|
|
13
|
+
// Otherwise, treat it relative to the current container.
|
|
14
|
+
let relativePath = args.join(path.sep);
|
|
14
15
|
let basePath;
|
|
15
16
|
if (relativePath.startsWith("~")) {
|
|
16
17
|
basePath = os.homedir();
|
|
17
18
|
relativePath = relativePath.slice(2);
|
|
18
19
|
} else {
|
|
19
|
-
basePath =
|
|
20
|
+
basePath = state.parent.path;
|
|
20
21
|
}
|
|
21
22
|
const resolved = path.resolve(basePath, relativePath);
|
|
22
23
|
|
|
23
24
|
const result = new OrigamiFileMap(resolved);
|
|
24
25
|
return result;
|
|
25
26
|
}
|
|
27
|
+
files.needsState = true;
|
package/src/protocols/http.js
CHANGED
|
@@ -6,9 +6,11 @@ import fetchAndHandleExtension from "./fetchAndHandleExtension.js";
|
|
|
6
6
|
*
|
|
7
7
|
*
|
|
8
8
|
* @param {string} host
|
|
9
|
-
* @param {...
|
|
9
|
+
* @param {...any} keys
|
|
10
10
|
*/
|
|
11
11
|
export default async function http(host, ...keys) {
|
|
12
|
+
const state = keys.pop();
|
|
12
13
|
const href = constructHref("http:", host, ...keys);
|
|
13
|
-
return fetchAndHandleExtension(href);
|
|
14
|
+
return fetchAndHandleExtension(href, state.parent);
|
|
14
15
|
}
|
|
16
|
+
http.needsState = true;
|
package/src/protocols/https.js
CHANGED
|
@@ -6,9 +6,11 @@ import fetchAndHandleExtension from "./fetchAndHandleExtension.js";
|
|
|
6
6
|
*
|
|
7
7
|
*
|
|
8
8
|
* @param {string} host
|
|
9
|
-
* @param {...
|
|
9
|
+
* @param {...any} keys
|
|
10
10
|
*/
|
|
11
11
|
export default async function https(host, ...keys) {
|
|
12
|
+
const state = keys.pop();
|
|
12
13
|
const href = constructHref("https:", host, ...keys);
|
|
13
|
-
return fetchAndHandleExtension(href);
|
|
14
|
+
return fetchAndHandleExtension(href, state.parent);
|
|
14
15
|
}
|
|
16
|
+
https.needsState = true;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import * as fs from "node:fs
|
|
2
|
-
import path from "node:path";
|
|
1
|
+
import * as fs from "node:fs";
|
|
3
2
|
import Watcher from "watcher";
|
|
4
3
|
import TreeEvent from "./TreeEvent.js";
|
|
5
4
|
|
|
@@ -15,10 +14,10 @@ export default function WatchFilesMixin(Base) {
|
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
onChange(
|
|
17
|
+
onChange(filePath) {
|
|
19
18
|
// Reset cached values.
|
|
20
19
|
this.subfoldersMap = new Map();
|
|
21
|
-
this.dispatchEvent(new TreeEvent("change", {
|
|
20
|
+
this.dispatchEvent(new TreeEvent("change", { filePath }));
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
async unwatch() {
|
|
@@ -38,7 +37,7 @@ export default function WatchFilesMixin(Base) {
|
|
|
38
37
|
this.watching = true;
|
|
39
38
|
|
|
40
39
|
// Ensure the directory exists.
|
|
41
|
-
|
|
40
|
+
fs.mkdirSync(this.dirname, { recursive: true });
|
|
42
41
|
|
|
43
42
|
this.watcher = new Watcher(this.dirname, {
|
|
44
43
|
ignoreInitial: true,
|
|
@@ -46,8 +45,7 @@ export default function WatchFilesMixin(Base) {
|
|
|
46
45
|
recursive: true,
|
|
47
46
|
});
|
|
48
47
|
this.watcher.on("all", (event, filePath) => {
|
|
49
|
-
|
|
50
|
-
this.onChange(key);
|
|
48
|
+
this.onChange(filePath);
|
|
51
49
|
});
|
|
52
50
|
|
|
53
51
|
// Add to the list of FileTree instances watching this directory.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is an analogue of Object.assign that destructively copies properties to
|
|
3
|
+
* a target object -- but avoids invoking property getters. Instead, it copies
|
|
4
|
+
* property descriptors over to the target object.
|
|
5
|
+
*
|
|
6
|
+
* @param {any} target
|
|
7
|
+
* @param {...any} sources
|
|
8
|
+
*/
|
|
9
|
+
export default function assignPropertyDescriptors(target, ...sources) {
|
|
10
|
+
for (const source of sources) {
|
|
11
|
+
const descriptors = Object.getOwnPropertyDescriptors(source);
|
|
12
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
13
|
+
if (descriptor.value !== undefined) {
|
|
14
|
+
// Simple value, copy it
|
|
15
|
+
target[key] = descriptor.value;
|
|
16
|
+
} else {
|
|
17
|
+
// Getter and/or setter, copy the descriptor
|
|
18
|
+
Object.defineProperty(target, key, descriptor);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return target;
|
|
23
|
+
}
|
package/src/runtime/evaluate.js
CHANGED
|
@@ -24,7 +24,7 @@ export default async function evaluate(code, state = {}) {
|
|
|
24
24
|
} else {
|
|
25
25
|
// Evaluate each instruction in the code.
|
|
26
26
|
evaluated = await Promise.all(
|
|
27
|
-
code.map((instruction) => evaluate(instruction, state))
|
|
27
|
+
code.map((instruction) => evaluate(instruction, state)),
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -34,7 +34,7 @@ export default async function evaluate(code, state = {}) {
|
|
|
34
34
|
if (!fn) {
|
|
35
35
|
// The code wants to invoke something that's couldn't be found in scope.
|
|
36
36
|
const error = ReferenceError(
|
|
37
|
-
`${codeFragment(code[0].location)} is not defined
|
|
37
|
+
`${codeFragment(code[0].location)} is not defined`,
|
|
38
38
|
);
|
|
39
39
|
/** @type {any} */ (error).location = code[0].location;
|
|
40
40
|
throw error;
|
|
@@ -48,9 +48,9 @@ export default async function evaluate(code, state = {}) {
|
|
|
48
48
|
if (fn.needsState) {
|
|
49
49
|
// The function is an op that wants the runtime state
|
|
50
50
|
args.push(state);
|
|
51
|
-
} else if (fn.containerAsTarget && state.
|
|
51
|
+
} else if (fn.containerAsTarget && state.parent) {
|
|
52
52
|
// The function wants the code's container as the `this` target
|
|
53
|
-
fn = fn.bind(state.
|
|
53
|
+
fn = fn.bind(state.parent);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Execute the function or traverse the tree.
|
|
@@ -10,9 +10,7 @@ import { evaluate } from "./internal.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export function createExpressionFunction(code, parent) {
|
|
12
12
|
async function fn() {
|
|
13
|
-
return evaluate(code, {
|
|
14
|
-
container: parent,
|
|
15
|
-
});
|
|
13
|
+
return evaluate(code, { parent });
|
|
16
14
|
}
|
|
17
15
|
fn.code = code;
|
|
18
16
|
fn.toString = () => code.location.source.text;
|
|
@@ -138,6 +138,9 @@ function defineProperty(object, propertyInfo, state, map) {
|
|
|
138
138
|
* Return a normalized version of the property key for use in the keys() method.
|
|
139
139
|
* Among other things, this adds trailing slashes to keys that correspond to
|
|
140
140
|
* maplike values.
|
|
141
|
+
*
|
|
142
|
+
* @param {any} propertyInfo
|
|
143
|
+
* @param {object|null} [object]
|
|
141
144
|
*/
|
|
142
145
|
export function normalizeKey(propertyInfo, object = null) {
|
|
143
146
|
const { key, value, valueType } = propertyInfo;
|
|
@@ -7,9 +7,7 @@ import {
|
|
|
7
7
|
setParent,
|
|
8
8
|
trailingSlash,
|
|
9
9
|
} from "@weborigami/async-tree";
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
let projectGlobals;
|
|
10
|
+
import projectGlobals from "../project/projectGlobals.js";
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* If the given value is packed (e.g., buffer) and the key is a string-like path
|
|
@@ -18,9 +16,9 @@ let projectGlobals;
|
|
|
18
16
|
*
|
|
19
17
|
* @param {any} value
|
|
20
18
|
* @param {any} key
|
|
21
|
-
* @param {import("@weborigami/async-tree").SyncOrAsyncMap} [parent]
|
|
19
|
+
* @param {import("@weborigami/async-tree").SyncOrAsyncMap|null} [parent]
|
|
22
20
|
*/
|
|
23
|
-
export default async function handleExtension(value, key, parent) {
|
|
21
|
+
export default async function handleExtension(value, key, parent = null) {
|
|
24
22
|
if (isPacked(value) && isStringlike(key) && value.unpack === undefined) {
|
|
25
23
|
const hasSlash = trailingSlash.has(key);
|
|
26
24
|
if (hasSlash) {
|
|
@@ -33,7 +31,7 @@ export default async function handleExtension(value, key, parent) {
|
|
|
33
31
|
: extension.extname(key);
|
|
34
32
|
if (extname) {
|
|
35
33
|
const handlerName = `${extname.slice(1)}_handler`;
|
|
36
|
-
const handlers = await
|
|
34
|
+
const handlers = await projectGlobals(parent);
|
|
37
35
|
let handler = await handlers[handlerName];
|
|
38
36
|
if (handler) {
|
|
39
37
|
if (isUnpackable(handler)) {
|
|
@@ -66,19 +64,3 @@ export default async function handleExtension(value, key, parent) {
|
|
|
66
64
|
}
|
|
67
65
|
return value;
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
async function getHandlers(parent) {
|
|
71
|
-
// Walk up the parent chain to find first `handlers` property
|
|
72
|
-
let current = parent;
|
|
73
|
-
|
|
74
|
-
while (current) {
|
|
75
|
-
if (current.handlers) {
|
|
76
|
-
return current.handlers;
|
|
77
|
-
}
|
|
78
|
-
current = current.parent;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Fall back to project globals
|
|
82
|
-
projectGlobals ??= await globals();
|
|
83
|
-
return projectGlobals;
|
|
84
|
-
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isPlainObject, isUnpackable, Tree } from "@weborigami/async-tree";
|
|
2
|
+
import assignPropertyDescriptors from "./assignPropertyDescriptors.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Create a tree that's the result of merging the given trees.
|
|
@@ -21,26 +22,14 @@ export default async function mergeTrees(...trees) {
|
|
|
21
22
|
// Unpack any packed objects.
|
|
22
23
|
const unpacked = await Promise.all(
|
|
23
24
|
filtered.map((obj) =>
|
|
24
|
-
isUnpackable(obj) ? /** @type {any} */ (obj).unpack() : obj
|
|
25
|
-
)
|
|
25
|
+
isUnpackable(obj) ? /** @type {any} */ (obj).unpack() : obj,
|
|
26
|
+
),
|
|
26
27
|
);
|
|
27
28
|
|
|
28
29
|
// If all trees are plain objects, return a plain object.
|
|
29
30
|
if (unpacked.every((tree) => isPlainObject(tree) && !Tree.isMap(tree))) {
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const result = {};
|
|
33
|
-
for (const obj of unpacked) {
|
|
34
|
-
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
35
|
-
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
36
|
-
if (descriptor.value !== undefined) {
|
|
37
|
-
result[key] = descriptor.value;
|
|
38
|
-
} else {
|
|
39
|
-
Object.defineProperty(result, key, descriptor);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return result;
|
|
31
|
+
// Use our Object.assign variation that avoids invoking property getters.
|
|
32
|
+
return assignPropertyDescriptors({}, ...unpacked);
|
|
44
33
|
}
|
|
45
34
|
|
|
46
35
|
// Merge the trees.
|
|
@@ -1,28 +1,26 @@
|
|
|
1
|
+
import { FileMap } from "@weborigami/async-tree";
|
|
1
2
|
import assert from "node:assert";
|
|
2
3
|
import { describe, test } from "node:test";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
4
|
import projectConfig from "../../src/project/projectConfig.js";
|
|
5
5
|
|
|
6
6
|
describe("projectConfig", () => {
|
|
7
|
-
test("
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const config = await projectConfig(subfolderPath);
|
|
7
|
+
test("loads Origami configuration file if present", async () => {
|
|
8
|
+
// The folder that represents the project root
|
|
9
|
+
const projectFiles = new FileMap(
|
|
10
|
+
new URL("fixtures/withConfig/", import.meta.url),
|
|
11
|
+
);
|
|
12
|
+
const subfolder = await projectFiles.get("subfolder");
|
|
13
|
+
const config = await projectConfig(subfolder);
|
|
15
14
|
assert.equal(config.message, "Hello");
|
|
16
15
|
});
|
|
17
16
|
|
|
18
17
|
test("defaults to an empty object", async () => {
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const config = await projectConfig(subfolderPath);
|
|
18
|
+
// The folder that represents the project root
|
|
19
|
+
const projectFiles = new FileMap(
|
|
20
|
+
new URL("fixtures/withPackageJson/", import.meta.url),
|
|
21
|
+
);
|
|
22
|
+
const subfolder = await projectFiles.get("subfolder");
|
|
23
|
+
const config = await projectConfig(subfolder);
|
|
26
24
|
assert.deepEqual(config, {});
|
|
27
25
|
});
|
|
28
26
|
});
|
|
@@ -33,8 +33,8 @@ describe("projectRootFromPath", () => {
|
|
|
33
33
|
assert.equal(resultPath, fileURLToPath(projectUrl));
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
test("defaults to
|
|
36
|
+
test("defaults to supplied directory", async () => {
|
|
37
37
|
const root = await projectRootFromPath("/");
|
|
38
|
-
assert.equal(root.path,
|
|
38
|
+
assert.equal(root.path, "/");
|
|
39
39
|
});
|
|
40
40
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
|
+
import process from "node:process";
|
|
2
3
|
import { describe, test } from "node:test";
|
|
3
4
|
import projectRootFromPath from "../../src/project/projectRootFromPath.js";
|
|
4
5
|
import packageProtocol from "../../src/protocols/package.js";
|
|
@@ -6,10 +7,10 @@ import packageProtocol from "../../src/protocols/package.js";
|
|
|
6
7
|
describe("package: protocol", () => {
|
|
7
8
|
test("returns a package's main export(s)", async () => {
|
|
8
9
|
// Reproduce the type of evaluation context object the runtime would create
|
|
9
|
-
const projectRoot = await projectRootFromPath();
|
|
10
|
-
const
|
|
10
|
+
const projectRoot = await projectRootFromPath(process.cwd());
|
|
11
|
+
const state = { parent: projectRoot };
|
|
11
12
|
|
|
12
|
-
const result = await packageProtocol("@weborigami", "async-tree",
|
|
13
|
+
const result = await packageProtocol("@weborigami", "async-tree", state);
|
|
13
14
|
const { toString } = result;
|
|
14
15
|
assert.equal(toString(123), "123");
|
|
15
16
|
});
|
|
@@ -32,10 +32,10 @@ describe("evaluate", () => {
|
|
|
32
32
|
return this;
|
|
33
33
|
};
|
|
34
34
|
fn.containerAsTarget = true;
|
|
35
|
-
const
|
|
36
|
-
const state = {
|
|
35
|
+
const parent = new SyncMap();
|
|
36
|
+
const state = { parent };
|
|
37
37
|
const code = createCode([fn]);
|
|
38
38
|
const result = await evaluate(code, state);
|
|
39
|
-
assert.equal(result,
|
|
39
|
+
assert.equal(result, parent);
|
|
40
40
|
});
|
|
41
41
|
});
|