Skip to content

Commit 462ef8c

Browse files
renovate[bot]Codex-
authored andcommitted
feat!: Upgrade to Jiti 2
1 parent 8e46d2c commit 462ef8c

11 files changed

+321
-148
lines changed

.github/workflows/build.yml

+9
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ jobs:
4242
- name: Import with both CJS and ESM
4343
if: ${{ always() }}
4444
run: node smoke-tests/smoke-test.js
45+
- name: Import synchronously with CJS
46+
if: ${{ always() }}
47+
run: node smoke-tests/smoke-test-cjs-sync.cjs
48+
- name: Import synchronously with ESM
49+
if: ${{ always() }}
50+
run: node smoke-tests/smoke-test-esm-sync.mjs
51+
- name: Import synchronously with both CJS and ESM
52+
if: ${{ always() }}
53+
run: node smoke-tests/smoke-test-sync.js
4554
- name: lint
4655
if: ${{ always() }}
4756
run: pnpm lint

README.md

+17-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## Usage
1010

11-
Simply add `TypeScriptLoader` to the list of loaders for the `.ts` file type:
11+
Simply add `TypeScriptLoader` to the list of loaders for the `.ts` file type, and `await` loading:
1212

1313
```ts
1414
import { cosmiconfig } from "cosmiconfig";
@@ -34,7 +34,7 @@ const explorer = cosmiconfig("test", {
3434
},
3535
});
3636

37-
const cfg = explorer.load("./");
37+
const cfg = await explorer.load("./");
3838
```
3939

4040
Or more simply if you only support loading of a TypeScript based configuration file:
@@ -50,15 +50,23 @@ const explorer = cosmiconfig("test", {
5050
},
5151
});
5252

53-
const cfg = explorer.load("./amazing.config.ts");
53+
const cfg = await explorer.load("./amazing.config.ts");
5454
```
5555

56-
## `@endemolshinegroup/cosmiconfig-typescript-loader`
56+
### Synchronously loading
5757

58-
This package serves as a drop in replacement for `@endemolshinegroup/cosmiconfig-typescript-loader`. At the time of publishing this, `endemolshinegroup` is not maintaining the original package. I can only assume this is to do with the fact that Endemol Shine Group [was purchased and absorbed by another business](https://en.wikipedia.org/wiki/Endemol_Shine_Group#Sale_to_Banijay). This discontinuation of development efforts towards the original package left any open issues and pull requests unresolved.
58+
With the release of Jiti 2, the synchronous loader has now been deprecated. It can still be used by using the `TypeScriptLoaderSync` export:
5959

60-
This new package resolves the following original issues:
60+
```ts
61+
import { cosmiconfig } from "cosmiconfig";
62+
import { TypeScriptLoaderSync } from "cosmiconfig-typescript-loader";
6163

62-
- [`#134`](https://github.com/EndemolShineGroup/cosmiconfig-typescript-loader/issues/134): "Doesn't work with Cosmiconfig sync API"
63-
- [`#147`](https://github.com/EndemolShineGroup/cosmiconfig-typescript-loader/issues/147): "doesn't provide typescript, requested by ts-node"
64-
- [`#155`](https://github.com/EndemolShineGroup/cosmiconfig-typescript-loader/issues/155): "Misleading TypeScriptCompileError when user's tsconfig.json "module" is set to "es2015""
64+
const moduleName = "module";
65+
const explorer = cosmiconfig("test", {
66+
loaders: {
67+
".ts": TypeScriptLoaderSync(),
68+
},
69+
});
70+
71+
const cfg = explorer.load("./amazing.config.ts");
72+
```

lib/index.spec.ts

+6-32
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
/* eslint-disable @typescript-eslint/no-deprecated */
2+
13
import path from "node:path";
24

35
import { cosmiconfig, cosmiconfigSync } from "cosmiconfig";
46

5-
import { TypeScriptLoader } from ".";
7+
import { TypeScriptLoader, TypeScriptLoaderSync } from ".";
68

79
describe("TypeScriptLoader", () => {
810
const fixturesPath = path.resolve(__dirname, "__fixtures__");
911

1012
describe("exports", () => {
1113
it("should export the loader function as a default", () => {
1214
expect(typeof TypeScriptLoader).toStrictEqual("function");
15+
expect(typeof TypeScriptLoaderSync).toStrictEqual("function");
1316
});
1417
});
1518

@@ -18,7 +21,7 @@ describe("TypeScriptLoader", () => {
1821
it("should load a valid TS file", () => {
1922
const cfg = cosmiconfigSync("test", {
2023
loaders: {
21-
".ts": TypeScriptLoader(),
24+
".ts": TypeScriptLoaderSync(),
2225
},
2326
});
2427
const loadedCfg = cfg.load(
@@ -33,7 +36,7 @@ describe("TypeScriptLoader", () => {
3336
it("should throw an error on loading an invalid TS file", () => {
3437
const cfg = cosmiconfigSync("test", {
3538
loaders: {
36-
".ts": TypeScriptLoader(),
39+
".ts": TypeScriptLoaderSync(),
3740
},
3841
});
3942

@@ -80,33 +83,4 @@ describe("TypeScriptLoader", () => {
8083
});
8184
});
8285
});
83-
84-
describe("cosmiconfigSync", () => {
85-
it("should load a valid TS file", () => {
86-
const cfg = cosmiconfigSync("test", {
87-
loaders: {
88-
".ts": TypeScriptLoader(),
89-
},
90-
});
91-
const loadedCfg = cfg.load(
92-
path.resolve(fixturesPath, "valid.fixture.ts"),
93-
);
94-
95-
expect(typeof loadedCfg!.config).toStrictEqual("object");
96-
expect(typeof loadedCfg!.config.test).toStrictEqual("object");
97-
expect(loadedCfg!.config.test.cake).toStrictEqual("a lie");
98-
});
99-
100-
it("should throw an error on loading an invalid TS file", () => {
101-
const cfg = cosmiconfigSync("test", {
102-
loaders: {
103-
".ts": TypeScriptLoader(),
104-
},
105-
});
106-
107-
expect(() =>
108-
cfg.load(path.resolve(fixturesPath, "invalid.fixture.ts")),
109-
).toThrow();
110-
});
111-
});
11286
});

lib/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { TypeScriptLoader } from "./loader.js";
1+
export { TypeScriptLoader, TypeScriptLoaderSync } from "./loader.js";
22
export type { TypeScriptCompileError } from "./typescript-compile-error.js";

lib/loader.spec.ts

+119-47
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,166 @@
11
import fs from "node:fs";
22
import path from "node:path";
33

4-
import { Loader } from "cosmiconfig";
4+
import type { LoaderResult, LoaderSync } from "cosmiconfig";
55
import * as jiti from "jiti";
66

7-
import { TypeScriptLoader } from "./loader";
7+
import { TypeScriptLoader, TypeScriptLoaderSync } from "./loader";
88
import { TypeScriptCompileError } from "./typescript-compile-error";
99

1010
// Handle jiti using `export default`
1111
jest.mock("jiti", () => {
1212
const actual = jest.requireActual("jiti");
1313
return {
1414
__esModule: true,
15-
default: jest.fn(actual),
15+
createJiti: actual.createJiti,
1616
};
1717
});
1818

1919
describe("TypeScriptLoader", () => {
2020
const fixturesPath = path.resolve(__dirname, "__fixtures__");
21-
const jitiSpy = jest.spyOn(jiti, "default");
22-
23-
let loader: Loader;
21+
let jitiCreateJitiSpy: jest.SpyInstance<typeof jiti.createJiti>;
2422

2523
function readFixtureContent(file: string): string {
2624
return fs.readFileSync(file).toString();
2725
}
2826

29-
beforeAll(() => {
30-
loader = TypeScriptLoader();
27+
beforeEach(() => {
28+
jitiCreateJitiSpy = jest.spyOn(jiti, "createJiti");
3129
});
3230

33-
it("should parse a valid TS file", () => {
34-
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
35-
loader(filePath, readFixtureContent(filePath));
31+
afterEach(() => {
32+
jest.restoreAllMocks();
3633
});
3734

38-
it("should fail on parsing an invalid TS file", () => {
39-
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
40-
expect((): unknown =>
41-
loader(filePath, readFixtureContent(filePath)),
42-
).toThrow();
43-
});
35+
describe("asynchronous", () => {
36+
let loader: (filepath: string, content: string) => Promise<LoaderResult>;
4437

45-
it("should use the same instance of jiti across multiple calls", () => {
46-
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
47-
loader(filePath, readFixtureContent(filePath));
48-
loader(filePath, readFixtureContent(filePath));
49-
expect(jitiSpy).toHaveBeenCalledTimes(1);
50-
});
38+
beforeEach(() => {
39+
loader = TypeScriptLoader();
40+
});
41+
42+
it("should parse a valid TS file", async () => {
43+
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
44+
await loader(filePath, readFixtureContent(filePath));
45+
});
5146

52-
it("should throw a TypeScriptCompileError on error", () => {
53-
try {
47+
it("should fail on parsing an invalid TS file", async () => {
5448
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
55-
loader(filePath, readFixtureContent(filePath));
56-
fail(
57-
"Error should be thrown upon failing to transpile an invalid TS file.",
58-
);
59-
} catch (error: unknown) {
60-
expect(error).toBeInstanceOf(TypeScriptCompileError);
61-
}
62-
});
49+
await expect(
50+
loader(filePath, readFixtureContent(filePath)),
51+
).rejects.toThrow();
52+
});
6353

64-
describe("jiti", () => {
65-
const unknownError = "Test Error";
54+
it("should use the same instance of jiti across multiple calls", async () => {
55+
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
56+
await loader(filePath, readFixtureContent(filePath));
57+
await loader(filePath, readFixtureContent(filePath));
58+
expect(jitiCreateJitiSpy).toHaveBeenCalledTimes(1);
59+
});
6660

67-
let stub: jest.SpyInstance;
61+
it("should throw a TypeScriptCompileError on error", async () => {
62+
try {
63+
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
64+
await loader(filePath, readFixtureContent(filePath));
65+
fail(
66+
"Error should be thrown upon failing to transpile an invalid TS file.",
67+
);
68+
} catch (error: unknown) {
69+
expect(error).toBeInstanceOf(TypeScriptCompileError);
70+
}
71+
});
72+
73+
describe("jiti", () => {
74+
const unknownError = "Test Error";
75+
76+
beforeEach(() => {
77+
jitiCreateJitiSpy.mockImplementation((() => ({
78+
import: () => {
79+
// eslint-disable-next-line @typescript-eslint/only-throw-error
80+
throw unknownError;
81+
},
82+
})) as never);
83+
84+
loader = TypeScriptLoader();
85+
});
86+
87+
it("rethrows an error if it is not an instance of Error", async () => {
88+
try {
89+
await loader("filePath", "readFixtureContent(filePath)");
90+
fail(
91+
"Error should be thrown upon failing to transpile an invalid TS file.",
92+
);
93+
} catch (error: unknown) {
94+
expect(error).not.toBeInstanceOf(TypeScriptCompileError);
95+
expect(error).toStrictEqual(unknownError);
96+
}
97+
});
98+
});
99+
});
100+
101+
describe("synchronous", () => {
102+
let loader: LoaderSync;
68103

69104
beforeEach(() => {
70-
stub = jest.spyOn(jiti, "default").mockImplementation((() => () => {
71-
// eslint-disable-next-line @typescript-eslint/only-throw-error
72-
throw unknownError;
73-
}) as never);
105+
// eslint-disable-next-line @typescript-eslint/no-deprecated
106+
loader = TypeScriptLoaderSync();
107+
});
74108

75-
loader = TypeScriptLoader();
109+
it("should parse a valid TS file", () => {
110+
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
111+
loader(filePath, readFixtureContent(filePath));
112+
});
113+
114+
it("should fail on parsing an invalid TS file", () => {
115+
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
116+
expect((): unknown =>
117+
loader(filePath, readFixtureContent(filePath)),
118+
).toThrow();
76119
});
77120

78-
afterEach(() => {
79-
stub.mockRestore();
121+
it("should use the same instance of jiti across multiple calls", () => {
122+
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
123+
loader(filePath, readFixtureContent(filePath));
124+
loader(filePath, readFixtureContent(filePath));
125+
expect(jitiCreateJitiSpy).toHaveBeenCalledTimes(1);
80126
});
81127

82-
it("rethrows an error if it is not an instance of Error", () => {
128+
it("should throw a TypeScriptCompileError on error", () => {
83129
try {
84-
loader("filePath", "readFixtureContent(filePath)");
130+
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
131+
loader(filePath, readFixtureContent(filePath));
85132
fail(
86133
"Error should be thrown upon failing to transpile an invalid TS file.",
87134
);
88135
} catch (error: unknown) {
89-
expect(error).not.toBeInstanceOf(TypeScriptCompileError);
90-
expect(error).toStrictEqual(unknownError);
136+
expect(error).toBeInstanceOf(TypeScriptCompileError);
91137
}
92138
});
139+
140+
describe("jiti", () => {
141+
const unknownError = "Test Error";
142+
143+
beforeEach(() => {
144+
jitiCreateJitiSpy.mockImplementation((() => () => {
145+
// eslint-disable-next-line @typescript-eslint/only-throw-error
146+
throw unknownError;
147+
}) as never);
148+
149+
// eslint-disable-next-line @typescript-eslint/no-deprecated
150+
loader = TypeScriptLoaderSync();
151+
});
152+
153+
it("rethrows an error if it is not an instance of Error", () => {
154+
try {
155+
loader("filePath", "readFixtureContent(filePath)");
156+
fail(
157+
"Error should be thrown upon failing to transpile an invalid TS file.",
158+
);
159+
} catch (error: unknown) {
160+
expect(error).not.toBeInstanceOf(TypeScriptCompileError);
161+
expect(error).toStrictEqual(unknownError);
162+
}
163+
});
164+
});
93165
});
94166
});

0 commit comments

Comments
 (0)