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

pmcelhaney / counterfact / 6030589989

30 Aug 2023 10:12PM UTC coverage: 83.297% (-0.3%) from 83.567%
6030589989

push

github

web-flow
Merge pull request #540 from pmcelhaney/ci-fixes

390 of 424 branches covered (0.0%)

Branch coverage included in aggregate %.

1924 of 2354 relevant lines covered (81.73%)

9.6 hits per line

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

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

1✔
7
import chokidar from "chokidar";
1✔
8
import createDebug from "debug";
1✔
9

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

1✔
13
const debug = createDebug("counterfact:typescript-generator:module-loader");
1✔
14

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

1✔
18
  registry;
1✔
19

1✔
20
  watcher;
1✔
21

1✔
22
  contextRegistry;
1✔
23

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

1✔
31
  async watch() {
1✔
32
    this.watcher = chokidar
6✔
33
      .watch(`${this.basePath}/**/*.{js,mjs,ts,mts}`, CHOKIDAR_OPTIONS)
6✔
34

6✔
35
      // eslint-disable-next-line max-statements
6✔
36
      .on("all", (eventName, pathNameOriginal) => {
6✔
37
        const pathName = pathNameOriginal.replaceAll("\\", "/");
9✔
38

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

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

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

1✔
52
          return;
1✔
53
        }
1✔
54

8✔
55
        const fileUrl = `${pathToFileURL(pathName)}?cacheBust=${Date.now()}`;
8✔
56

8✔
57
        debug("importing module: %s", fileUrl);
8✔
58

8✔
59
        // eslint-disable-next-line  import/no-dynamic-require, no-unsanitized/method
8✔
60
        import(fileUrl)
8✔
61
          // eslint-disable-next-line promise/prefer-await-to-then
8✔
62
          .then((endpoint) => {
8✔
63
            debug("imported module: %s", fileUrl);
8✔
64
            this.dispatchEvent(new Event(eventName), pathName);
8✔
65

8✔
66
            if (pathName.includes("$.context")) {
8!
67
              this.contextRegistry.update(parts.dir, endpoint.default);
×
68

×
69
              return "context";
×
70
            }
×
71

8✔
72
            this.registry.add(url, endpoint);
8✔
73

8✔
74
            return "path";
8✔
75
          })
8✔
76
          // eslint-disable-next-line promise/prefer-await-to-then
8✔
77
          .catch((error) => {
8✔
78
            process.stdout.write(`\nError loading ${fileUrl}:\n${error}\n`);
×
79
          });
×
80
      });
8✔
81

6✔
82
    await once(this.watcher, "ready");
6✔
83
  }
6✔
84

1✔
85
  async stopWatching() {
1✔
86
    await this.watcher?.close();
6✔
87
  }
6✔
88

1✔
89
  async load(directory = "") {
1✔
90
    if (
12✔
91
      !existsSync(nodePath.join(this.basePath, directory).replaceAll("\\", "/"))
12✔
92
    ) {
12!
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", "mts", "ts"].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
        const fileUrl = `${pathToFileURL(fullPath)}?cacheBust=${Date.now()}`;
11✔
125

11✔
126
        debug("* importing module: %s", fileUrl);
11✔
127

11✔
128
        // eslint-disable-next-line import/no-dynamic-require, no-unsanitized/method
11✔
129
        const endpoint = await import(fileUrl);
11✔
130

11✔
131
        debug("* imported module: %s", fileUrl);
11✔
132

11✔
133
        if (file.name.includes("$.context")) {
16✔
134
          this.contextRegistry.add(
9✔
135
            `/${directory.replaceAll("\\", "/")}`.replaceAll(/\/+/gu, "/"),
9✔
136
            endpoint.default,
9✔
137
          );
9✔
138
        } else {
9✔
139
          const url = `/${nodePath.join(
9✔
140
            directory,
9✔
141
            nodePath.parse(file.name).name,
9✔
142
          )}`
9✔
143
            .replaceAll("\\", "/")
9✔
144
            .replaceAll(/\/+/gu, "/");
9✔
145

9✔
146
          this.registry.add(url, endpoint);
9✔
147
        }
9✔
148
      } catch (error) {
16!
149
        process.stdout.write(["Error loading", fullPath, error].join("\n"));
×
150
      }
×
151
    });
16✔
152

12✔
153
    await Promise.all(imports);
12✔
154
  }
12✔
155
}
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

© 2026 Coveralls, Inc