Skip to content

Commit de60629

Browse files
committed
fix: api rewrite 🫠 😂
1 parent ef02cef commit de60629

File tree

6 files changed

+83
-130
lines changed

6 files changed

+83
-130
lines changed

src/__tests__/utils.test.ts

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,23 @@
11
import * as fs from "node:fs";
2-
import { ImportMap } from "@jspm/import-map";
3-
import { constructImportMap } from "src/utils";
2+
import * as path from "node:path";
3+
import { ensureDirSync } from 'src/utils';
44

55
jest.mock("node:fs");
6-
7-
jest.mock("node:path", () => {
8-
const actual = jest.requireActual("node:path");
9-
return {
10-
...actual,
11-
dirname: jest.fn((str) => str),
12-
join: jest.fn((str, str2) => `${str}${str2}`),
13-
};
14-
});
15-
16-
jest.mock("node-fetch", () =>
17-
jest.fn().mockResolvedValue({
18-
ok: true,
19-
text: jest.fn().mockResolvedValue("module code"),
20-
})
21-
);
22-
23-
jest.mock("@jspm/import-map", () => {
24-
const ImportMap = jest.fn();
25-
return { ImportMap };
26-
});
27-
28-
test("constructImportMap minimal", () => {
29-
const result = constructImportMap();
30-
expect(result).toBeInstanceOf(ImportMap);
31-
});
32-
33-
test("constructImportMap should return null if path does not exist", () => {
34-
jest.spyOn(fs, "readFileSync").mockReturnValue(Error("invalid/path") as unknown as string);
35-
const result = constructImportMap("invalid/path");
36-
expect(result).toEqual({});
37-
});
38-
39-
test("constructImportMap should return ImportMap instance if path exists", () => {
40-
const path = `${process.cwd()}/src/__fixtures__/fake.json`;
41-
constructImportMap(path);
42-
expect(ImportMap).toHaveBeenCalled();
6+
jest.mock("node:path");
7+
8+
test("ensureDirSync has dir", () => {
9+
const dir = "/path/to/dir";
10+
const existsSyncMock = jest.spyOn(fs, 'existsSync').mockReturnValue(true);
11+
ensureDirSync(dir);
12+
expect(existsSyncMock).toBeCalledWith(dir);
13+
expect(fs.mkdirSync).not.toBeCalled();
4314
});
4415

45-
test("constructImportMap should use cwd if no path provided", () => {
46-
constructImportMap();
47-
expect(ImportMap).toHaveBeenCalledWith({
48-
rootUrl: `file://${process.cwd()}/src/utils.ts`,
49-
map: {},
50-
});
16+
test("ensureDirSync has no dir", () => {
17+
const dir = "/path/to/dir";
18+
const existsSyncMock = jest.spyOn(fs, 'existsSync').mockReturnValue(false);
19+
const mkdirSyncMock = jest.spyOn(fs, 'mkdirSync')
20+
ensureDirSync(dir);
21+
expect(existsSyncMock).toBeCalledWith(dir);
22+
expect(mkdirSyncMock).toBeCalledWith(dir);
5123
});

src/config.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { existsSync, readFileSync } from "node:fs";
12
import { join } from "node:path";
23
import { fileURLToPath } from "node:url";
4+
import { ImportMap } from "@jspm/import-map";
35
/**
46
* ******************************************************
57
* CONFIG
@@ -9,7 +11,10 @@ import { fileURLToPath } from "node:url";
911
*
1012
* ******************************************************
1113
*/
12-
export const root = fileURLToPath(`file://${process.cwd()}`);
14+
export const rootUrl = import.meta.url;
15+
export const root = fileURLToPath(new URL(".", rootUrl));
1316
export const cacheMap = new Map();
1417
export const nodeImportMapPath = join(root, "node.importmap");
1518
export const cache = join(root, ".cache");
19+
export const map = existsSync(nodeImportMapPath) ? JSON.parse(readFileSync(nodeImportMapPath, { encoding: "utf8" })) : {};
20+
export const importMap = new ImportMap({ rootUrl, map })

src/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export const NO_CACHE_MAP_DEFINED =
22
"No parentURL provided. No cachePath was defined. Couldn't get cachePath from cacheMap.";
33
export const ALL_CACHE_MAP_REQUIREMENTS_MUST_BE_DEFINED = "All cacheMap requirements must be defined.";
4-
54
export const IS_DEBUGGING = Boolean(process.env.DEBUG) || false;

src/loader.ts

Lines changed: 12 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
import { join } from "node:path";
2-
import { parseUrlPkg } from "@jspm/generator";
3-
import { cache, cacheMap, nodeImportMapPath } from "./config";
4-
import { constructImportMap } from "./utils";
5-
import { parseNodeModuleCachePath } from "./parser";
6-
import { IS_DEBUGGING } from "./constants";
7-
import { logger } from "./logger";
8-
import { Context, NextResolve } from "./types";
1+
import { cacheMap, nodeImportMapPath } from "src/config";
2+
import { isNodeOrFileProtocol, resolveNodeModuleCachePath, resolveModulePath, resolveParsedModulePath } from 'src/utils';
3+
import { Context, NextResolve } from "src/types";
94

105
/**
116
* ******************************************************
127
* LOADER
138
* ------------------------------------------------------
14-
* @description generates a node.importmap
159
* @summary loads node modules via an *assumed root working directory with a cache and node.importmap*
1610
* @notes
1711
* The node loader api is being redesigned.
@@ -24,58 +18,22 @@ import { Context, NextResolve } from "./types";
2418
* ******************************************************
2519
*/
2620

27-
const log = logger({ file: "loader" });
28-
log.setLogger(IS_DEBUGGING);
29-
3021
/**
3122
* resolve
32-
* @description a convenience function to resolve the modules, this function is called by the loader automatically
23+
* @description resolves modules, this function is called by the loader automatically
3324
* @param {string} specifier
3425
* @param {object} context
3526
* @param {callback} nextResolve
3627
* @returns {function} nextResolve
3728
*/
38-
3929
export const resolve = async (specifier: string, { parentURL }: Context, nextResolve: NextResolve) => {
4030
if (!parentURL || !nodeImportMapPath) return nextResolve(specifier);
41-
42-
const importmap = constructImportMap(nodeImportMapPath);
43-
log.debug("resolve:importmap:", { importmap });
44-
const cacheMapPath = cacheMap.get(parentURL) || parentURL;
45-
log.debug("resolve:cacheMapPath:", { cacheMapPath });
46-
47-
// construct module path
48-
const modulePath = importmap.resolve(specifier, cacheMapPath);
49-
log.debug("resolve:modulePath:", { modulePath });
50-
51-
// resolve URL
52-
const { protocol = "" } = new URL(modulePath);
53-
const isNode = protocol === "node:";
54-
const isFile = protocol === "file:";
55-
log.debug("resolve:protocol:", { isNode, isFile });
56-
if (isNode || isFile) return nextResolve(specifier);
57-
58-
// get node module information
59-
try {
60-
const moduleMetadata = await parseUrlPkg(modulePath);
61-
// debugged to here
62-
log.debug("resolve:moduleMetaData:", { moduleMetadata });
63-
if (!moduleMetadata) return nextResolve(specifier);
64-
65-
// construct node module cache path
66-
const {
67-
pkg: { name, version },
68-
} = moduleMetadata;
69-
const moduleFile = modulePath.split("/").reverse()[0] || "";
70-
const nodeModuleCachePath = join(cache, `${name}@${version}`, moduleFile);
71-
cacheMap.set(`file://${nodeModuleCachePath}`, modulePath);
72-
const parsedNodeModuleCachePath = await parseNodeModuleCachePath(modulePath, nodeModuleCachePath);
73-
log.debug("resolve:nodeModuleCachePath:", { nodeModuleCachePath, parsedNodeModuleCachePath });
74-
75-
// resolve node module cache path
76-
return nextResolve(parsedNodeModuleCachePath);
77-
} catch (err) {
78-
log.error(`resolve: ${err}`);
79-
return nextResolve(specifier);
80-
}
31+
const modulePath = resolveModulePath(specifier, cacheMap.get(parentURL) || parentURL);
32+
if (isNodeOrFileProtocol(modulePath)) return nextResolve(specifier);
33+
const nodeModuleCachePath = await resolveNodeModuleCachePath(modulePath);
34+
if (!nodeModuleCachePath) return nextResolve(specifier);
35+
cacheMap.set(`file://${nodeModuleCachePath}`, modulePath);
36+
const parsedNodeModuleCachePath = await resolveParsedModulePath(modulePath, nodeModuleCachePath);
37+
if (!parsedNodeModuleCachePath) return nextResolve(specifier);
38+
return nextResolve(parsedNodeModuleCachePath);
8139
};

src/logger.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,5 @@ export const logger = ({ file, isLogging = false }: LoggerOptions) => ({
1010
if (args) console.error(`jspm:[${file}]: ${msg}`, ...args);
1111
else console.error(`jspm:[${file}]: ${msg}`);
1212
},
13-
info: (msg: string, ...args: unknown[]) => {
14-
if (!isLogging) return;
15-
if (args) console.info(`jspm:[${file}]: ${msg}`, ...args);
16-
else console.info(`jspm:[${file}]: ${msg}`);
17-
},
1813
setLogger: (isLogging = false) => logger({ file, isLogging }),
1914
});

src/utils.ts

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import { existsSync, mkdirSync, readFileSync } from "node:fs";
2-
import { dirname } from "node:path";
3-
import { ImportMap } from "@jspm/import-map";
1+
import { existsSync, mkdirSync } from "node:fs";
2+
import { dirname, join } from "node:path";
3+
import { parseUrlPkg } from "@jspm/generator";
4+
import { parseNodeModuleCachePath } from "src/parser";
5+
import { cache, importMap } from 'src/config';
6+
import { IS_DEBUGGING } from "src/constants";
7+
import { logger } from "src/logger";
48

59
/**
610
* ******************************************************
@@ -13,31 +17,51 @@ import { ImportMap } from "@jspm/import-map";
1317
* ******************************************************
1418
*/
1519

16-
/**
17-
* ensureDirSync
18-
* @description a function to ensure the dis exists
19-
* @param dirPath
20-
*/
20+
const log = logger({ file: "loader" });
21+
log.setLogger(IS_DEBUGGING);
22+
2123
export const ensureDirSync = (dirPath: string) => {
2224
if (existsSync(dirPath)) return;
2325
const parentDir = dirname(dirPath);
2426
if (parentDir !== dirPath) ensureDirSync(parentDir);
2527
mkdirSync(dirPath);
2628
};
2729

28-
/**
29-
* constructImportMap
30-
* @description a convenience function to construct an import map
31-
* @param {string} path
32-
* @param {string} rootUrl
33-
* @returns {ImportMap|null}
34-
*/
35-
export const constructImportMap = (path = "", rootUrl = import.meta.url) => {
36-
const pathExists = existsSync(path);
37-
const json = readFileSync(path, { encoding: "utf8" });
38-
const map = pathExists && json ? JSON.parse(json) : {};
39-
return new ImportMap({
40-
rootUrl,
41-
map,
42-
});
43-
};
30+
export const isNodeOrFileProtocol = (modulePath: string) => {
31+
const { protocol = "" } = new URL(modulePath);
32+
const isNode = protocol === "node:";
33+
const isFile = protocol === "file:";
34+
return isNode || isFile;
35+
}
36+
37+
export const resolveModulePath = (specifier: string, cacheMapPath: string) => {
38+
const modulePath = importMap.resolve(specifier, cacheMapPath);
39+
log.debug("resolveModulePath:", { modulePath });
40+
return modulePath;
41+
}
42+
43+
export const resolveNodeModuleCachePath = async (modulePath: string) => {
44+
try {
45+
const moduleMetadata = await parseUrlPkg(modulePath);
46+
const name = moduleMetadata?.pkg?.name;
47+
const version = moduleMetadata?.pkg?.version;
48+
const moduleFile = modulePath.split("/").reverse()[0] || "";
49+
const nodeModuleCachePath = join(cache, `${name}@${version}`, moduleFile);
50+
log.debug("resolveNodeModuleCachePath:", { name, version, nodeModuleCachePath });
51+
return nodeModuleCachePath;
52+
} catch (err) {
53+
log.error("resolveNodeModuleCachePath:", err);
54+
return
55+
}
56+
}
57+
58+
export const resolveParsedModulePath = async (modulePath: string, nodeModuleCachePath: string) => {
59+
try {
60+
const parsedNodeModuleCachePath = await parseNodeModuleCachePath(modulePath, nodeModuleCachePath);
61+
log.debug("resolveParsedModulePath:", { nodeModuleCachePath, parsedNodeModuleCachePath });
62+
return parsedNodeModuleCachePath;
63+
} catch (err) {
64+
log.error("resolveParsedModulePath:", err);
65+
return
66+
}
67+
}

0 commit comments

Comments
 (0)