@weborigami/language 0.6.4 → 0.6.6
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/main.js +4 -0
- package/package.json +2 -2
- package/src/compiler/optimize.js +17 -11
- package/src/compiler/origami.pegjs +192 -58
- package/src/compiler/parse.js +2182 -1172
- package/src/compiler/parserHelpers.js +172 -10
- package/src/project/projectConfig.js +2 -2
- package/src/project/projectGlobals.js +2 -2
- package/src/project/projectRoot.js +5 -54
- package/src/project/projectRootFromPath.js +58 -0
- package/src/protocols/fetchAndHandleExtension.js +5 -0
- package/src/protocols/package.js +26 -39
- package/src/runtime/expressionObject.js +162 -150
- package/src/runtime/handleExtension.js +18 -2
- package/src/runtime/ops.js +30 -9
- package/test/compiler/compile.test.js +39 -0
- package/test/compiler/optimize.test.js +2 -1
- package/test/compiler/parse.test.js +355 -112
- package/test/project/{projectRoot.test.js → projectRootFromPath.test.js} +5 -5
- package/test/protocols/package.test.js +6 -1
- package/test/runtime/expressionObject.test.js +25 -10
- package/test/runtime/ops.test.js +32 -4
|
@@ -16,8 +16,13 @@ const YAML = YAMLModule.default ?? YAMLModule.YAML;
|
|
|
16
16
|
|
|
17
17
|
// Markers in compiled output, will get optimized away
|
|
18
18
|
export const markers = {
|
|
19
|
-
global: Symbol("global"), // Global reference
|
|
20
19
|
external: Symbol("external"), // External reference
|
|
20
|
+
global: Symbol("global"), // Global reference
|
|
21
|
+
paramArray: Symbol("paramArray"), // Parameter array destructuring
|
|
22
|
+
paramInitializer: Symbol("paramInitializer"), // Parameter default value
|
|
23
|
+
paramName: Symbol("paramName"), // Parameter name
|
|
24
|
+
paramObject: Symbol("paramObject"), // Parameter object destructuring
|
|
25
|
+
paramRest: Symbol("paramRest"), // Rest operator in parameters
|
|
21
26
|
property: Symbol("property"), // Property access
|
|
22
27
|
reference: Symbol("reference"), // Reference to local, scope, or global
|
|
23
28
|
spread: Symbol("spread"), // Spread operator
|
|
@@ -69,6 +74,21 @@ export function applyMacro(code, name, macro) {
|
|
|
69
74
|
return annotate(applied, code.location);
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
function checkDuplicateParamNames(flat) {
|
|
78
|
+
const names = new Set();
|
|
79
|
+
for (const binding of flat) {
|
|
80
|
+
const paramName = binding[0];
|
|
81
|
+
if (names.has(paramName)) {
|
|
82
|
+
const error = new SyntaxError(`Duplicate parameter name "${paramName}"`);
|
|
83
|
+
/** @type {any} */ (error).location = /** @type {any} */ (
|
|
84
|
+
binding
|
|
85
|
+
).location;
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
names.add(paramName);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
/**
|
|
73
93
|
* Create an array
|
|
74
94
|
*
|
|
@@ -236,10 +256,8 @@ export function makeDeferredArguments(args) {
|
|
|
236
256
|
if (arg instanceof Array && arg[0] === ops.literal) {
|
|
237
257
|
return arg;
|
|
238
258
|
}
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
const fn = [ops.lambda, lambdaParameters, arg];
|
|
242
|
-
return annotate(fn, arg.location);
|
|
259
|
+
const params = annotate([], arg.location);
|
|
260
|
+
return makeLambda(params, arg, arg.location);
|
|
243
261
|
});
|
|
244
262
|
}
|
|
245
263
|
|
|
@@ -257,6 +275,40 @@ export function makeDocument(front, body, location) {
|
|
|
257
275
|
return annotate([ops.object, ...entries], location);
|
|
258
276
|
}
|
|
259
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Create a lambda function with the given parameters.
|
|
280
|
+
*
|
|
281
|
+
* @param {AnnotatedCode} params
|
|
282
|
+
* @param {AnnotatedCode} body
|
|
283
|
+
* @param {CodeLocation} location
|
|
284
|
+
*/
|
|
285
|
+
export function makeLambda(params, body, location) {
|
|
286
|
+
// Create a reference that at runtime resolves to parameters array. All
|
|
287
|
+
// parameter references will use this as their basis.
|
|
288
|
+
const reference = annotate([ops.params, 0], location);
|
|
289
|
+
|
|
290
|
+
// Shared state for parameter processing
|
|
291
|
+
const state = { tempVariableCount: 0 };
|
|
292
|
+
|
|
293
|
+
const bindings = makeParamArray(params, reference, state);
|
|
294
|
+
const annotatedBindings = annotate(bindings, params.location);
|
|
295
|
+
|
|
296
|
+
// Calculate function "length" (number of expected arguments). The length
|
|
297
|
+
// can't be easily calculated at runtime because default values and rest
|
|
298
|
+
// parameters affect it.
|
|
299
|
+
let length = 0;
|
|
300
|
+
for (const param of params) {
|
|
301
|
+
const [op] = param;
|
|
302
|
+
if (op === markers.paramInitializer || op === markers.paramRest) {
|
|
303
|
+
// Default value or rest parameter: stop counting
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
length++;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return annotate([ops.lambda, length, annotatedBindings, body], location);
|
|
310
|
+
}
|
|
311
|
+
|
|
260
312
|
/**
|
|
261
313
|
* From the given spreads within an object spread, return the merge.
|
|
262
314
|
*
|
|
@@ -413,19 +465,129 @@ function makeOptionalCall(target, chain, location) {
|
|
|
413
465
|
location
|
|
414
466
|
);
|
|
415
467
|
|
|
416
|
-
// Create the call to be made if the target is not null/undefined
|
|
417
|
-
const
|
|
468
|
+
// Create the call body to be made if the target is not null/undefined
|
|
469
|
+
const body = makeCallChain(optionalTraverse, chain, location);
|
|
418
470
|
|
|
419
471
|
// Create a function that takes __optional__ and makes the call
|
|
420
|
-
const
|
|
421
|
-
const
|
|
422
|
-
const lambda =
|
|
472
|
+
const optionalParam = annotate([markers.paramName, optionalKey], location);
|
|
473
|
+
const params = annotate([optionalParam], location);
|
|
474
|
+
const lambda = makeLambda(params, body, location);
|
|
423
475
|
|
|
424
476
|
// Create the call to ops.optional
|
|
425
477
|
const optionalCall = annotate([ops.optional, target, lambda], location);
|
|
426
478
|
return optionalCall;
|
|
427
479
|
}
|
|
428
480
|
|
|
481
|
+
// Return bindings for the given parameter
|
|
482
|
+
function makeParam(parameter, reference, state) {
|
|
483
|
+
const [marker, ...args] = parameter;
|
|
484
|
+
switch (marker) {
|
|
485
|
+
case markers.paramArray:
|
|
486
|
+
return makeParamArray(args, reference, state);
|
|
487
|
+
|
|
488
|
+
case markers.paramInitializer:
|
|
489
|
+
return makeParamInitializer(parameter, reference, state);
|
|
490
|
+
|
|
491
|
+
case markers.paramName:
|
|
492
|
+
return makeParamName(parameter, reference, state);
|
|
493
|
+
|
|
494
|
+
case markers.paramObject:
|
|
495
|
+
return makeParamObject(args, reference, state);
|
|
496
|
+
|
|
497
|
+
default:
|
|
498
|
+
throw new Error(`Unknown parameter type: ${parameter[0]}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Return bindings for the array destructuring parameter
|
|
503
|
+
function makeParamArray(entries, reference, state) {
|
|
504
|
+
const bindings = entries.map((entry, index) => {
|
|
505
|
+
if (entry === undefined) {
|
|
506
|
+
return []; // Skip missing entry
|
|
507
|
+
} else if (entry[0] === markers.paramRest) {
|
|
508
|
+
// Rest parameter
|
|
509
|
+
const sliceFunction = annotate([reference, "slice"], entry.location);
|
|
510
|
+
const sliceCall = annotate([sliceFunction, index], entry.location);
|
|
511
|
+
return makeParam(entry[1], sliceCall, state);
|
|
512
|
+
}
|
|
513
|
+
// Other type of parameter
|
|
514
|
+
const indexReference = annotate([reference, index], entry.location);
|
|
515
|
+
return makeParam(entry, indexReference, state);
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const flat = bindings.flat();
|
|
519
|
+
checkDuplicateParamNames(flat);
|
|
520
|
+
return flat;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Return binding for a parameter with a default value
|
|
524
|
+
function makeParamInitializer(parameter, reference, state) {
|
|
525
|
+
const [baseParam, defaultValue] = parameter.slice(1);
|
|
526
|
+
|
|
527
|
+
if (defaultValue[0] === ops.literal) {
|
|
528
|
+
// Literal default value can be inlined
|
|
529
|
+
const defaultReference = annotate(
|
|
530
|
+
[ops.defaultValue, reference, defaultValue],
|
|
531
|
+
parameter.location
|
|
532
|
+
);
|
|
533
|
+
return makeParam(baseParam, defaultReference, state);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Need to introduce a temporary variable so that the default value, if it's
|
|
537
|
+
// an expression, is only evaluated once.
|
|
538
|
+
const deferred = makeDeferredArguments([defaultValue])[0];
|
|
539
|
+
const defaultReference = annotate(
|
|
540
|
+
[ops.defaultValue, reference, deferred],
|
|
541
|
+
parameter.location
|
|
542
|
+
);
|
|
543
|
+
const tempVariableName = `__temp${state.tempVariableCount++}__`;
|
|
544
|
+
const tempBinding = annotate(
|
|
545
|
+
[tempVariableName, defaultReference],
|
|
546
|
+
parameter.location
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
const selfReference = annotate([ops.inherited, 0], parameter.location);
|
|
550
|
+
const tempReference = annotate(
|
|
551
|
+
[selfReference, tempVariableName],
|
|
552
|
+
parameter.location
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
const paramBindings = makeParam(baseParam, tempReference, state);
|
|
556
|
+
return [tempBinding, ...paramBindings];
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Return binding for a single parameter name
|
|
560
|
+
function makeParamName(parameter, reference, state) {
|
|
561
|
+
const paramName = parameter[1];
|
|
562
|
+
// Return as an array with one entry
|
|
563
|
+
const bindings = [annotate([paramName, reference], parameter.location)];
|
|
564
|
+
return bindings;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Return bindings for an object destructuring parameter
|
|
568
|
+
function makeParamObject(entries, reference, state) {
|
|
569
|
+
const keys = [];
|
|
570
|
+
const bindings = entries.map((entry) => {
|
|
571
|
+
if (entry[0] === markers.paramRest) {
|
|
572
|
+
// Rest parameter; exclude keys we've seen so far
|
|
573
|
+
const annotatedKeys = annotate([ops.array, ...keys], entry.location);
|
|
574
|
+
const objectRest = annotate(
|
|
575
|
+
[ops.objectRest, reference, annotatedKeys],
|
|
576
|
+
entry.location
|
|
577
|
+
);
|
|
578
|
+
return makeParam(entry[1], objectRest, state);
|
|
579
|
+
}
|
|
580
|
+
const [key, binding] = entry;
|
|
581
|
+
keys.push(key);
|
|
582
|
+
const propertyValue = annotate([reference, key], entry.location);
|
|
583
|
+
return makeParam(binding, propertyValue, state);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const flat = bindings.flat();
|
|
587
|
+
checkDuplicateParamNames(flat);
|
|
588
|
+
return flat;
|
|
589
|
+
}
|
|
590
|
+
|
|
429
591
|
/**
|
|
430
592
|
* Handle a path with one or more segments separated by slashes.
|
|
431
593
|
*
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { FileMap, toString } from "@weborigami/async-tree";
|
|
2
2
|
import ori_handler from "../handlers/ori_handler.js";
|
|
3
3
|
import coreGlobals from "./coreGlobals.js";
|
|
4
|
-
import
|
|
4
|
+
import projectRootFromPath from "./projectRootFromPath.js";
|
|
5
5
|
|
|
6
6
|
const mapPathToConfig = new Map();
|
|
7
7
|
|
|
8
8
|
export default async function config(dir = process.cwd()) {
|
|
9
|
-
const root = await
|
|
9
|
+
const root = await projectRootFromPath(dir);
|
|
10
10
|
|
|
11
11
|
const rootPath = root.path;
|
|
12
12
|
const cached = mapPathToConfig.get(rootPath);
|
|
@@ -4,14 +4,14 @@ import projectConfig from "./projectConfig.js";
|
|
|
4
4
|
let globals;
|
|
5
5
|
|
|
6
6
|
// Core globals plus project config
|
|
7
|
-
export default async function projectGlobals() {
|
|
7
|
+
export default async function projectGlobals(dir = process.cwd()) {
|
|
8
8
|
if (!globals) {
|
|
9
9
|
// Start with core globals
|
|
10
10
|
globals = await coreGlobals();
|
|
11
11
|
// Now get config. The config.ori file may require access to globals,
|
|
12
12
|
// which will obtain the core globals set above. Once we've got the
|
|
13
13
|
// config, we add it to the globals.
|
|
14
|
-
const config = await projectConfig();
|
|
14
|
+
const config = await projectConfig(dir);
|
|
15
15
|
Object.assign(globals, config);
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -1,58 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
4
|
-
|
|
5
|
-
const configFileName = "config.ori";
|
|
6
|
-
const packageFileName = "package.json";
|
|
7
|
-
|
|
8
|
-
const mapPathToRoot = new Map();
|
|
1
|
+
import { Tree } from "@weborigami/async-tree";
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
|
-
* Return an OrigamiFileMap object for the current
|
|
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.
|
|
16
|
-
*
|
|
17
|
-
* Otherwise, this looks for a package.json file to determine the project root.
|
|
18
|
-
* If no package.json is found, the current folder is used as the project root.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param {string} [dirname]
|
|
4
|
+
* Return an OrigamiFileMap object for the current code context.
|
|
22
5
|
*/
|
|
23
|
-
export default async function projectRoot(
|
|
24
|
-
|
|
25
|
-
if (cached) {
|
|
26
|
-
return cached;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
let root;
|
|
30
|
-
let value;
|
|
31
|
-
// Use a plain FileMap to avoid loading extension handlers
|
|
32
|
-
const currentTree = new FileMap(dirname);
|
|
33
|
-
// Try looking for config file
|
|
34
|
-
value = await currentTree.get(configFileName);
|
|
35
|
-
if (value) {
|
|
36
|
-
// Found config file
|
|
37
|
-
root = new OrigamiFileMap(currentTree.path);
|
|
38
|
-
} else {
|
|
39
|
-
// Try looking for package.json
|
|
40
|
-
value = await currentTree.get(packageFileName);
|
|
41
|
-
if (value) {
|
|
42
|
-
// Found package.json
|
|
43
|
-
root = new OrigamiFileMap(currentTree.path);
|
|
44
|
-
} else {
|
|
45
|
-
// Move up a folder and try again
|
|
46
|
-
const parentPath = path.dirname(dirname);
|
|
47
|
-
if (parentPath !== dirname) {
|
|
48
|
-
root = await projectRoot(parentPath);
|
|
49
|
-
} else {
|
|
50
|
-
// At filesystem root, use current working directory
|
|
51
|
-
root = new OrigamiFileMap(process.cwd());
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
mapPathToRoot.set(dirname, root);
|
|
57
|
-
return root;
|
|
6
|
+
export default async function projectRoot(state) {
|
|
7
|
+
return Tree.root(state.container);
|
|
58
8
|
}
|
|
9
|
+
projectRoot.needsState = true;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { FileMap } from "@weborigami/async-tree";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import OrigamiFileMap from "../runtime/OrigamiFileMap.js";
|
|
4
|
+
|
|
5
|
+
const configFileName = "config.ori";
|
|
6
|
+
const packageFileName = "package.json";
|
|
7
|
+
|
|
8
|
+
const mapPathToRoot = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Return an OrigamiFileMap object for the current project root.
|
|
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.
|
|
16
|
+
*
|
|
17
|
+
* Otherwise, this looks for a package.json file to determine the project root.
|
|
18
|
+
* If no package.json is found, the current folder is used as the project root.
|
|
19
|
+
*
|
|
20
|
+
*
|
|
21
|
+
* @param {string} [dirname]
|
|
22
|
+
*/
|
|
23
|
+
export default async function projectRootFromPath(dirname = process.cwd()) {
|
|
24
|
+
const cached = mapPathToRoot.get(dirname);
|
|
25
|
+
if (cached) {
|
|
26
|
+
return cached;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let root;
|
|
30
|
+
let value;
|
|
31
|
+
// Use a plain FileMap to avoid loading extension handlers
|
|
32
|
+
const currentTree = new FileMap(dirname);
|
|
33
|
+
// Try looking for config file
|
|
34
|
+
value = await currentTree.get(configFileName);
|
|
35
|
+
if (value) {
|
|
36
|
+
// Found config file
|
|
37
|
+
root = new OrigamiFileMap(currentTree.path);
|
|
38
|
+
} else {
|
|
39
|
+
// Try looking for package.json
|
|
40
|
+
value = await currentTree.get(packageFileName);
|
|
41
|
+
if (value) {
|
|
42
|
+
// Found package.json
|
|
43
|
+
root = new OrigamiFileMap(currentTree.path);
|
|
44
|
+
} else {
|
|
45
|
+
// Move up a folder and try again
|
|
46
|
+
const parentPath = path.dirname(dirname);
|
|
47
|
+
if (parentPath !== dirname) {
|
|
48
|
+
root = await projectRootFromPath(parentPath);
|
|
49
|
+
} else {
|
|
50
|
+
// At filesystem root, use current working directory
|
|
51
|
+
root = new OrigamiFileMap(process.cwd());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
mapPathToRoot.set(dirname, root);
|
|
57
|
+
return root;
|
|
58
|
+
}
|
|
@@ -13,6 +13,11 @@ export default async function fetchAndHandleExtension(href) {
|
|
|
13
13
|
}
|
|
14
14
|
let buffer = await response.arrayBuffer();
|
|
15
15
|
|
|
16
|
+
const mediaType = response.headers.get("Content-Type");
|
|
17
|
+
if (mediaType) {
|
|
18
|
+
/** @type {any} */ (buffer).mediaType = mediaType;
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
// Attach any loader defined for the file type.
|
|
17
22
|
const url = new URL(href);
|
|
18
23
|
const filename = url.pathname.split("/").pop();
|
package/src/protocols/package.js
CHANGED
|
@@ -2,66 +2,53 @@ import { Tree, keysFromPath } from "@weborigami/async-tree";
|
|
|
2
2
|
import projectRoot from "../project/projectRoot.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* The package: protocol handler
|
|
6
|
+
*
|
|
7
|
+
* @param {any[]} args
|
|
6
8
|
*/
|
|
7
|
-
export default async function
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
getPackage(parent, organization, name, keys);
|
|
19
|
-
}
|
|
20
|
-
name = keys.shift();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return getPackage(parent, organization, name, keys);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function getPackage(parent, organization, name, keys) {
|
|
27
|
-
const packagePath = ["node_modules"];
|
|
28
|
-
if (organization) {
|
|
29
|
-
packagePath.push(organization);
|
|
9
|
+
export default async function packageProtocol(...args) {
|
|
10
|
+
const state = args.pop(); // Remaining args are the path
|
|
11
|
+
const root = await projectRoot(state);
|
|
12
|
+
|
|
13
|
+
// Identify the path to the package root
|
|
14
|
+
const packageRootPath = ["node_modules"];
|
|
15
|
+
const name = args.shift();
|
|
16
|
+
packageRootPath.push(name);
|
|
17
|
+
if (name.startsWith("@")) {
|
|
18
|
+
// First key is an npm organization, add next key as name
|
|
19
|
+
packageRootPath.push(args.shift());
|
|
30
20
|
}
|
|
31
|
-
packagePath.push(name);
|
|
32
|
-
|
|
33
|
-
const parentScope = await Tree.scope(parent);
|
|
34
|
-
const packageRoot = await Tree.traverse(
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
parentScope,
|
|
37
|
-
...packagePath
|
|
38
|
-
);
|
|
39
21
|
|
|
22
|
+
// Get the package root (top level folder of the package)
|
|
23
|
+
const packageRoot = await Tree.traverse(root, ...packageRootPath);
|
|
40
24
|
if (!packageRoot) {
|
|
41
|
-
throw new Error(`Can't find ${
|
|
25
|
+
throw new Error(`Can't find ${packageRootPath.join("/")}`);
|
|
42
26
|
}
|
|
43
27
|
|
|
28
|
+
// Identify the main entry point
|
|
44
29
|
const mainPath = await Tree.traverse(packageRoot, "package.json", "main");
|
|
45
30
|
if (!mainPath) {
|
|
46
31
|
throw new Error(
|
|
47
|
-
|
|
32
|
+
`${packageRootPath.join(
|
|
48
33
|
"/"
|
|
49
34
|
)} doesn't contain a package.json with a "main" entry.`
|
|
50
35
|
);
|
|
51
36
|
}
|
|
52
37
|
|
|
38
|
+
// Identify the folder containing the main entry point
|
|
53
39
|
const mainKeys = keysFromPath(mainPath);
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const mainContainer = await Tree.traverse(packageRoot, ...mainContainerKeys);
|
|
40
|
+
const mainFileName = mainKeys.pop();
|
|
41
|
+
const mainContainer = await Tree.traverse(packageRoot, ...mainKeys);
|
|
57
42
|
const packageExports = await mainContainer.import(mainFileName);
|
|
58
43
|
|
|
59
44
|
let result =
|
|
60
45
|
"default" in packageExports ? packageExports.default : packageExports;
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
// If there are remaining args, traverse into the package exports
|
|
48
|
+
if (args.length > 0) {
|
|
49
|
+
result = await Tree.traverse(result, ...args);
|
|
64
50
|
}
|
|
65
51
|
|
|
66
52
|
return result;
|
|
67
53
|
}
|
|
54
|
+
packageProtocol.needsState = true;
|