• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmcelhaney / counterfact / 5941942840

22 Aug 2023 05:13PM UTC coverage: 87.442% (+0.1%) from 87.318%
5941942840

Pull #377

github

pmcelhaney
is the promise really just not resolving?
Pull Request #377: run CI on Windows as well as Linux

432 of 460 branches covered (93.91%)

Branch coverage included in aggregate %.

214 of 214 new or added lines in 13 files covered. (100.0%)

2005 of 2327 relevant lines covered (86.16%)

21.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.47
/src/server/module-loader.js
1
import fs from "node:fs/promises";
1✔
2
import { existsSync } from "node:fs";
1✔
3
import nodePath from "node:path";
1✔
4
import { once } from "node:events";
1✔
5

1✔
6
import chokidar from "chokidar";
1✔
7

1✔
8
import { ContextRegistry } from "./context-registry.js";
1✔
9
import { CHOKIDAR_OPTIONS } from "./constants.js";
1✔
10

1✔
11
function log(...strings) {
50✔
12
  process.stdout.write(`[module-loader] ${strings.join("\t")}\n`);
50✔
13
}
50✔
14

1✔
15
export class ModuleLoader extends EventTarget {
1✔
16
  basePath;
1✔
17

8✔
18
  registry;
8✔
19

8✔
20
  watcher;
8✔
21

8✔
22
  contextRegistry;
1✔
23

1✔
24
  constructor(basePath, registry, contextRegistry = new ContextRegistry()) {
1✔
25
    super();
8✔
26
    this.basePath = basePath;
8✔
27
    this.registry = registry;
8✔
28
    this.contextRegistry = contextRegistry;
8✔
29
  }
8✔
30

1✔
31
  async watch() {
1✔
32
    log("watching", this.basePath);
6✔
33
    this.watcher = chokidar
6✔
34
      .watch(`${this.basePath}/**/*.{js,mjs,ts,mts}`, CHOKIDAR_OPTIONS)
6✔
35
      .on("all", (eventName, pathNameOriginal) => {
6✔
36
        const pathName = pathNameOriginal.replaceAll("\\", "/");
9✔
37

9✔
38
        log("chokidar", eventName, pathName);
9✔
39

9✔
40
        if (!["add", "change", "unlink"].includes(eventName)) {
9!
41
          return;
×
42
        }
×
43

9✔
44
        const parts = nodePath.parse(pathName.replace(this.basePath, ""));
9✔
45
        const url = nodePath
9✔
46
          .normalize(`/${nodePath.join(parts.dir, parts.name)}`)
9✔
47
          .replaceAll("\\", "/");
9✔
48

9✔
49
        if (eventName === "unlink") {
9✔
50
          this.registry.remove(url);
1✔
51
          this.dispatchEvent(new Event("remove"), pathName);
1✔
52
        }
1✔
53

9✔
54
        // eslint-disable-next-line  import/no-dynamic-require, no-unsanitized/method
9✔
55
        import(`${pathName}?cacheBust=${Date.now()}`)
9✔
56
          // eslint-disable-next-line promise/prefer-await-to-then
9✔
57
          .then((endpoint) => {
9✔
58
            this.dispatchEvent(new Event(eventName), pathName);
9✔
59

9✔
60
            if (pathName.includes("$.context")) {
9!
61
              this.contextRegistry.update(parts.dir, endpoint.default);
×
62

×
63
              return "context";
×
64
            }
×
65

9✔
66
            this.registry.add(url, endpoint);
9✔
67

9✔
68
            return "path";
9✔
69
          })
9✔
70
          // eslint-disable-next-line promise/prefer-await-to-then
9✔
71
          .catch((error) => {
9✔
72
            process.stdout.write(`\nError loading ${pathName}:\n${error}\n`);
×
73
          });
×
74
      });
9✔
75

6✔
76
    log("waiting for ready event", this.basePath);
6✔
77
    await once(this.watcher, "ready");
6✔
78
    log("received ready event", this.basePath);
6✔
79
  }
6✔
80

1✔
81
  async stopWatching() {
1✔
82
    log("stopping the watcher...", this.basePath);
6✔
83
    await this.watcher?.close();
6✔
84
    log("stopped the watcher", this.basePath);
6✔
85
  }
6✔
86

1✔
87
  async load(directory = "") {
1✔
88
    if (
12✔
89
      !existsSync(nodePath.join(this.basePath, directory).replaceAll("\\", "/"))
12✔
90
    ) {
12!
91
      log("Directory does not exist", this.basePath, directory);
×
92

×
93
      throw new Error(`Directory does not exist ${this.basePath}`);
×
94
    }
×
95

12✔
96
    const files = await fs.readdir(
12✔
97
      nodePath.join(this.basePath, directory).replaceAll("\\", "/"),
12✔
98
      {
12✔
99
        withFileTypes: true,
12✔
100
      }
12✔
101
    );
12✔
102

12✔
103
    // eslint-disable-next-line max-statements
12✔
104
    const imports = files.flatMap(async (file) => {
12✔
105
      const extension = file.name.split(".").at(-1);
16✔
106

16✔
107
      if (file.isDirectory()) {
16✔
108
        await this.load(
4✔
109
          nodePath.join(directory, file.name).replaceAll("\\", "/")
4✔
110
        );
4✔
111

4✔
112
        return;
4✔
113
      }
4✔
114

12✔
115
      if (!["js", "mjs", "ts", "mts"].includes(extension)) {
16✔
116
        return;
1✔
117
      }
1✔
118

11✔
119
      const fullPath = nodePath
11✔
120
        .join(this.basePath, directory, file.name)
11✔
121
        .replaceAll("\\", "/");
11✔
122

11✔
123
      try {
11✔
124
        // eslint-disable-next-line  import/no-dynamic-require, no-unsanitized/method
11✔
125
        const endpoint = await import(fullPath);
11✔
126

11✔
127
        if (file.name.includes("$.context")) {
16✔
128
          log("adding context to registry", directory, endpoint.default);
9✔
129
          this.contextRegistry.add(`/${directory}`, endpoint.default);
9✔
130
        } else {
9✔
131
          log(
9✔
132
            "adding module to registry",
9✔
133
            directory,
9✔
134
            file.name,
9✔
135
            endpoint.default
9✔
136
          );
9✔
137
          this.registry.add(
9✔
138
            `/${nodePath
9✔
139
              .join(directory, nodePath.parse(file.name).name)
9✔
140
              .replaceAll("\\", "/")}`,
9✔
141
            endpoint
9✔
142
          );
9✔
143
        }
9✔
144
      } catch (error) {
16!
145
        log("Error loading", fullPath, error);
×
146
      }
×
147
    });
16✔
148

12✔
149
    await Promise.all(imports);
12✔
150
  }
12✔
151
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc