Skip to content

Commit 5331218

Browse files
committed
Adds support for multiple TypeScript sub-projects within a working directory
1 parent 158bc87 commit 5331218

File tree

7 files changed

+170
-161
lines changed

7 files changed

+170
-161
lines changed

Moduless.code-workspace

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"type": "node",
3030
"request": "launch",
3131
"program": "${workspaceRoot}/build/moduless.js",
32-
"cwd": "${workspaceFolder}/example",
32+
"cwd": "${workspaceFolder}/example/",
3333
"smartStep": true,
3434
"sourceMaps": true
3535
},
@@ -41,7 +41,7 @@
4141
"args": [
4242
"set", "./coverage/CoverExample.ts:4"
4343
],
44-
"cwd": "${workspaceFolder}/example",
44+
"cwd": "${workspaceFolder}/example/",
4545
"smartStep": true,
4646
"sourceMaps": true
4747
},
@@ -50,15 +50,15 @@
5050
"type": "node",
5151
"request": "launch",
5252
"program": "${workspaceRoot}/build/moduless.js",
53-
"cwd": "${workspaceFolder}/example",
53+
"cwd": "${workspaceFolder}/example/",
5454
"smartStep": true,
5555
"sourceMaps": true
5656
},
5757
{
5858
"name": "Debug 'run active' in Electron",
5959
"type": "node",
6060
"request": "launch",
61-
"cwd": "${workspaceFolder}/example",
61+
"cwd": "${workspaceFolder}/example/",
6262
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
6363
"program": "${workspaceRoot}/build/moduless.js",
6464
"smartStep": true,
@@ -73,15 +73,15 @@
7373
"all",
7474
"Cover.cover"
7575
],
76-
"cwd": "${workspaceFolder}/example",
76+
"cwd": "${workspaceFolder}/example/",
7777
"smartStep": true,
7878
"sourceMaps": true
7979
},
8080
{
8181
"name": "Debug 'run all' in Electron",
8282
"type": "node",
8383
"request": "launch",
84-
"cwd": "${workspaceFolder}/example",
84+
"cwd": "${workspaceFolder}/example/",
8585
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
8686
"program": "${workspaceRoot}/build/moduless.js",
8787
"args": [
@@ -94,7 +94,7 @@
9494
"name": "Debug 'run from expression' in Electron",
9595
"type": "node",
9696
"request": "launch",
97-
"cwd": "${workspaceFolder}/example",
97+
"cwd": "${workspaceFolder}/example/",
9898
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
9999
"program": "${workspaceRoot}/build/moduless.js",
100100
"args": [

core/EnvPaths.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Moduless
1212
/**
1313
* Directory for data files.
1414
*/
15-
readonly config: string;
15+
readonly targets: string;
1616

1717
/**
1818
* Directory for non-essential data files.
@@ -42,7 +42,7 @@ namespace Moduless
4242
const library = path.join(homedir, "Library");
4343
return {
4444
data: path.join(library, "Application Support", name),
45-
config: path.join(library, "Preferences", name),
45+
targets: path.join(library, "Preferences", name),
4646
cache: path.join(library, "Caches", name),
4747
log: path.join(library, "Logs", name),
4848
temp: path.join(tmpdir, name)
@@ -57,7 +57,7 @@ namespace Moduless
5757
return {
5858
// Data/config/cache/log are invented by me as Windows isn"t opinionated about this
5959
data: path.join(localAppData, name, "Data"),
60-
config: path.join(appData, name, "Config"),
60+
targets: path.join(appData, name, "Config"),
6161
cache: path.join(localAppData, name, "Cache"),
6262
log: path.join(localAppData, name, "Log"),
6363
temp: path.join(tmpdir, name)
@@ -70,7 +70,7 @@ namespace Moduless
7070
const username = path.basename(homedir);
7171
return {
7272
data: path.join(env.XDG_DATA_HOME || path.join(homedir, ".local", "share"), name),
73-
config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, ".config"), name),
73+
targets: path.join(env.XDG_CONFIG_HOME || path.join(homedir, ".config"), name),
7474
cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, ".cache"), name),
7575
// https://wiki.debian.org/XDGBaseDirectorySpecification#state
7676
log: path.join(env.XDG_STATE_HOME || path.join(homedir, ".local", "state"), name),

core/Run.ts

Lines changed: 32 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,79 +13,54 @@ namespace Moduless
1313
/** */
1414
type CoverFn = () => CoverReturn | Promise<CoverReturn>;
1515

16-
/** */
17-
export interface IRunInfo
18-
{
19-
cwd: string;
20-
namespacePath: string[];
21-
functionPrefix?: string;
22-
functionName?: string;
23-
}
24-
2516
/**
26-
*
17+
* An interface that stores information about the running
18+
* of a single cover function.
2719
*/
28-
export namespace IRunInfo
20+
export interface IRunMeta
2921
{
30-
/**
31-
* Creates an IRunInfo namespace, parsed from
32-
* the specified namespace path, and function prefix.
33-
*/
34-
export function parsePrefix(qualifiedName: string): IRunInfo
35-
{
36-
const parts = qualifiedName.split(".");
37-
return {
38-
cwd: process.cwd(),
39-
namespacePath: parts.slice(0, -1),
40-
functionPrefix: parts.at(-1) || ""
41-
};
42-
}
22+
functionNamespace: string[];
23+
functionName: string;
24+
projectPath: string;
4325

4426
/**
45-
* Creates an IRunInfo namespace, parsed from
46-
* the specified namespace path, and function name.
27+
* Whether the "name" property refers to a prefix (true),
28+
* or whether it's a fully qualified name (false).
4729
*/
48-
export function parseNamed(qualified: string)
49-
{
50-
const parts = qualified.split(".");
51-
return {
52-
cwd: process.cwd(),
53-
namespacePath: parts.slice(0, -1),
54-
functionName: parts.at(-1) || ""
55-
};
56-
}
30+
prefix?: boolean;
5731
}
5832

5933
/**
6034
*
6135
*/
62-
export async function run(info: IRunInfo)
36+
export async function run(runInfo: IRunMeta)
6337
{
6438
// Wait 1600ms to give the debugger a chance to connect.
65-
// This can be a problem with larger projects.
66-
await new Promise(r => setTimeout(r, 1600));
39+
// This can be a problem with larger projects when
40+
if (Moduless.inElectronMain || Moduless.inElectronRender)
41+
await new Promise(r => setTimeout(r, 1600));
6742

6843
if (Moduless.inElectronRender)
6944
{
7045
// Eliminate Electron's console generated garbage
7146
console.clear();
7247
}
7348

74-
if (!info.functionName)
49+
if (runInfo.prefix)
7550
{
7651
Util.log(
77-
`Running cover functions in ${info.namespacePath.join(".")} ` +
78-
`starting with ${info.functionPrefix}.`);
52+
`Running cover functions in ${runInfo.functionNamespace.join(".")} ` +
53+
`starting with ${runInfo.functionName}.`);
7954
}
8055

8156
let hasRunOneFunction = false;
8257

83-
const coverResult = await runCovers(info);
58+
const coverResult = await runCovers(runInfo);
8459
if (coverResult)
8560
{
8661
hasRunOneFunction = true;
8762

88-
if (info.functionName)
63+
if (runInfo.functionName)
8964
return;
9065
}
9166

@@ -98,10 +73,9 @@ namespace Moduless
9873
* only be found by traversing the TypeScript project structure.
9974
* Returns null in the case when no functions were discovered.
10075
*/
101-
function tryLoadCoversFromDependencies(cwd = process.cwd())
76+
function tryLoadCoversFromDependencies(projectPath: string)
10277
{
103-
//const coverNamespaces: Namespace[] = [];
104-
const graph = new ProjectGraph(cwd);
78+
const graph = new ProjectGraph(projectPath);
10579
const scriptFilePaths: string[] = [];
10680

10781
for (const project of graph.eachProject())
@@ -138,20 +112,18 @@ namespace Moduless
138112
* Runs the cover functions with the specified name, from the specified
139113
* namespace. Intended for use with Node.js.
140114
*/
141-
async function runCovers(info: IRunInfo)
115+
async function runCovers(target: IRunMeta)
142116
{
143-
const exports = [
144-
...tryLoadCoversFromDependencies(info.cwd),
145-
globalThis,
146-
];
117+
const dependencies = tryLoadCoversFromDependencies(target.projectPath);
118+
const exports = [...dependencies, globalThis];
147119

148120
const resolvedNamespace = (() =>
149121
{
150122
nextExport: for (const exp of exports)
151123
{
152124
let current: any = exp;
153125

154-
for (const identifier of info.namespacePath)
126+
for (const identifier of target.functionNamespace)
155127
{
156128
if (!(identifier in current))
157129
continue nextExport;
@@ -165,27 +137,27 @@ namespace Moduless
165137
return current as Record<string, any>;
166138
}
167139

140+
const ns = target.functionNamespace.join(".");
168141
throw new Error(
169-
"Could not resolve: " + info.namespacePath +
170-
". Not found or not an object.");
142+
`Could not resolve: ${ns}\nNot found or not an object.`);
171143
})();
172144

173145
const covers = (() =>
174146
{
175147
const out: [string, CoverFn][] = [];
176148

177-
if (info.functionName)
149+
if (target.functionName)
178150
{
179-
const fn = resolvedNamespace[info.functionName];
151+
const fn = resolvedNamespace[target.functionName];
180152
if (typeof fn !== "function")
181-
throw new Error(info.functionName + " is not a function.");
153+
throw new Error(target.functionName + " is not a function.");
182154

183-
out.push([info.functionName, fn]);
155+
out.push([target.functionName, fn]);
184156
}
185-
else if (info.functionPrefix)
157+
else if (target.prefix)
186158
for (const [functionName, maybeFunction] of Object.entries(resolvedNamespace))
187159
if (typeof maybeFunction === "function")
188-
if (functionName.startsWith(info.functionPrefix))
160+
if (functionName.startsWith(target.functionName))
189161
out.push([functionName, maybeFunction]);
190162

191163
return out;

0 commit comments

Comments
 (0)