-
Notifications
You must be signed in to change notification settings - Fork 57
feat: support typescript config #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
GabrielAnca
merged 10 commits into
intercom:master
from
G-Rath:support-typescript-config
Dec 15, 2022
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
1209802
feat: support `getContentfulEnvironment.ts`
G-Rath 3f90868
fix: loosen types of load environment
G-Rath c818b96
fix: add `ts-node` as an optional peer dependency
G-Rath de949fd
refactor: move exported types and functions to top of file
G-Rath 29124a6
chore: add todo comment
G-Rath 1b4b230
chore: bump `ts-node` to v10.6.0 or higher
G-Rath 7808d3a
test: add extra case + deduplicate
G-Rath 1faf4ec
docs: update readme with typescript config
G-Rath 1f80bf7
Fix typo
GabrielAnca e72ecce
Merge branch 'master' into support-typescript-config
GabrielAnca File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import * as path from "path" | ||
import * as fs from "fs" | ||
import { ContentfulCollection, ContentTypeCollection, LocaleCollection } from "contentful" | ||
|
||
// todo: switch to contentful-management interfaces here | ||
export interface ContentfulEnvironment { | ||
getContentTypes(options: { limit: number }): Promise<ContentfulCollection<unknown>> | ||
getLocales(): Promise<ContentfulCollection<unknown>> | ||
} | ||
|
||
export type EnvironmentGetter = () => Promise<ContentfulEnvironment> | ||
|
||
export async function loadEnvironment() { | ||
try { | ||
const getEnvironment = getEnvironmentGetter() | ||
const environment = await getEnvironment() | ||
|
||
return { | ||
contentTypes: (await environment.getContentTypes({ limit: 1000 })) as ContentTypeCollection, | ||
locales: (await environment.getLocales()) as LocaleCollection, | ||
} | ||
} finally { | ||
if (registerer) { | ||
registerer.enabled(false) | ||
} | ||
} | ||
} | ||
|
||
/* istanbul ignore next */ | ||
const interopRequireDefault = (obj: any): { default: any } => | ||
obj && obj.__esModule ? obj : { default: obj } | ||
|
||
type Registerer = { enabled(value: boolean): void } | ||
|
||
let registerer: Registerer | null = null | ||
|
||
function enableTSNodeRegisterer() { | ||
if (registerer) { | ||
registerer.enabled(true) | ||
|
||
return | ||
} | ||
|
||
try { | ||
registerer = require("ts-node").register() as Registerer | ||
GabrielAnca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
registerer.enabled(true) | ||
} catch (e) { | ||
if (e.code === "MODULE_NOT_FOUND") { | ||
throw new Error( | ||
`'ts-node' is required for TypeScript configuration files. Make sure it is installed\nError: ${e.message}`, | ||
) | ||
} | ||
|
||
throw e | ||
} | ||
} | ||
|
||
function determineEnvironmentPath() { | ||
const pathWithoutExtension = path.resolve(process.cwd(), "./getContentfulEnvironment") | ||
|
||
if (fs.existsSync(`${pathWithoutExtension}.ts`)) { | ||
return `${pathWithoutExtension}.ts` | ||
} | ||
|
||
return `${pathWithoutExtension}.js` | ||
} | ||
|
||
function getEnvironmentGetter(): EnvironmentGetter { | ||
const getEnvironmentPath = determineEnvironmentPath() | ||
|
||
if (getEnvironmentPath.endsWith(".ts")) { | ||
enableTSNodeRegisterer() | ||
|
||
return interopRequireDefault(require(getEnvironmentPath)).default | ||
} | ||
|
||
return require(getEnvironmentPath) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import * as fs from "fs" | ||
import { loadEnvironment } from "../src/loadEnvironment" | ||
|
||
const contentfulEnvironment = () => ({ | ||
getContentTypes: () => [], | ||
getLocales: () => [], | ||
}) | ||
|
||
const getContentfulEnvironmentFileFactory = jest.fn((_type: string) => contentfulEnvironment) | ||
|
||
jest.mock( | ||
require("path").resolve(process.cwd(), "./getContentfulEnvironment.js"), | ||
() => getContentfulEnvironmentFileFactory("js"), | ||
{ virtual: true }, | ||
) | ||
|
||
jest.mock( | ||
require("path").resolve(process.cwd(), "./getContentfulEnvironment.ts"), | ||
() => getContentfulEnvironmentFileFactory("ts"), | ||
{ virtual: true }, | ||
) | ||
|
||
const tsNodeRegistererEnabled = jest.fn() | ||
const tsNodeRegister = jest.fn() | ||
|
||
jest.mock("ts-node", () => ({ register: tsNodeRegister })) | ||
|
||
describe("loadEnvironment", () => { | ||
beforeEach(() => { | ||
jest.resetAllMocks() | ||
jest.restoreAllMocks() | ||
jest.resetModules() | ||
|
||
getContentfulEnvironmentFileFactory.mockReturnValue(contentfulEnvironment) | ||
tsNodeRegister.mockReturnValue({ enabled: tsNodeRegistererEnabled }) | ||
}) | ||
|
||
describe("when getContentfulEnvironment.ts exists", () => { | ||
G-Rath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
beforeEach(() => { | ||
jest.spyOn(fs, "existsSync").mockReturnValue(true) | ||
}) | ||
|
||
describe("when ts-node is not found", () => { | ||
beforeEach(() => { | ||
// technically this is throwing after the `require` call, | ||
// but it still tests the same code path so is fine | ||
tsNodeRegister.mockImplementation(() => { | ||
throw new (class extends Error { | ||
public code: string | ||
|
||
constructor(message?: string) { | ||
super(message) | ||
this.code = "MODULE_NOT_FOUND" | ||
} | ||
})() | ||
}) | ||
}) | ||
|
||
it("throws a nice error", async () => { | ||
await expect(loadEnvironment()).rejects.toThrow( | ||
"'ts-node' is required for TypeScript configuration files", | ||
) | ||
}) | ||
}) | ||
|
||
describe("when there is another error", () => { | ||
beforeEach(() => { | ||
tsNodeRegister.mockImplementation(() => { | ||
throw new Error("something else went wrong!") | ||
}) | ||
}) | ||
|
||
it("re-throws", async () => { | ||
await expect(loadEnvironment()).rejects.toThrow("something else went wrong!") | ||
}) | ||
}) | ||
|
||
describe("when called multiple times", () => { | ||
it("re-uses the registerer", async () => { | ||
await loadEnvironment() | ||
await loadEnvironment() | ||
|
||
expect(tsNodeRegister).toHaveBeenCalledTimes(1) | ||
}) | ||
}) | ||
|
||
it("requires the typescript config", async () => { | ||
await loadEnvironment() | ||
|
||
expect(getContentfulEnvironmentFileFactory).toHaveBeenCalledWith("ts") | ||
expect(getContentfulEnvironmentFileFactory).not.toHaveBeenCalledWith("js") | ||
}) | ||
|
||
it("disables the registerer afterwards", async () => { | ||
await loadEnvironment() | ||
|
||
expect(tsNodeRegistererEnabled).toHaveBeenCalledWith(false) | ||
}) | ||
}) | ||
|
||
it("requires the javascript config", async () => { | ||
jest.spyOn(fs, "existsSync").mockReturnValue(false) | ||
|
||
await loadEnvironment() | ||
|
||
expect(getContentfulEnvironmentFileFactory).toHaveBeenCalledWith("js") | ||
expect(getContentfulEnvironmentFileFactory).not.toHaveBeenCalledWith("ts") | ||
}) | ||
}) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.