From fb7dd558fb06a822a4911f5c00b1853204a971cf Mon Sep 17 00:00:00 2001 From: JD Huntington Date: Thu, 14 Mar 2019 08:45:00 -0700 Subject: [PATCH] feat(config): specify package.json location (#823) (#1013) * feat(config): specify package.json location (#823) * fix(docs): package.json config option (#823) Document the package.json config option. --- docs/user/config/index.md | 2 + docs/user/config/packageJson.md | 69 +++++++++++++++++++ src/__helpers__/fakers.ts | 1 + .../__snapshots__/config-set.spec.ts.snap | 4 ++ src/config/config-set.spec.ts | 34 ++++++++- src/config/config-set.ts | 52 +++++++++++--- src/types.ts | 18 +++++ 7 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 docs/user/config/packageJson.md diff --git a/docs/user/config/index.md b/docs/user/config/index.md index 283b46c579..7d7eda3bd8 100644 --- a/docs/user/config/index.md +++ b/docs/user/config/index.md @@ -193,6 +193,7 @@ All options have default values which should fit most of the projects. Click on | [**`diagnostics`**][diagnostics] | [Diagnostics related configuration.][diagnostics] | `boolean`\|`object` | `true` | | [**`babelConfig`**][babelConfig] | [Babel(Jest) related configuration.][babelConfig] | `boolean`\|`object` | _disabled_ | | [**`stringifyContentPathRegex`**][stringifyContentPathRegex] | [Files which will become modules returning self content.][stringifyContentPathRegex] | `string`\|`RegExp` | _disabled_ | +| [**`packageJson`**][packageJson] | [Package metadata.][packageJson] | `string`\|`object`\|`boolean` | _auto_ | ### Upgrading @@ -222,3 +223,4 @@ npx ts-jest config:migrate package.json [diagnostics]: diagnostics [babelConfig]: babelConfig [stringifyContentPathRegex]: stringifyContentPathRegex +[packageJson]: packageJson diff --git a/docs/user/config/packageJson.md b/docs/user/config/packageJson.md new file mode 100644 index 0000000000..6d2343010a --- /dev/null +++ b/docs/user/config/packageJson.md @@ -0,0 +1,69 @@ +--- +title: packageJson Config option +--- + +The `packageJson` option specifies the `package.json` file to use. An inline object may also be specified instead of a file path. + +By default, the `package.json` file at the root of the project will be used. If it cannot be found, an empty project definition will be used instead. + +### Examples + +#### Path to a `packageJson` file + +The path should be relative to the current working directory where you start Jest from. You can also use `` in the path to start from the project root dir. + +
+ +```js +// jest.config.js +module.exports = { + // [...] + globals: { + 'ts-jest': { + packageJson: 'package.json' + } + } +}; +``` + +
+ +```js +// OR from a non-trivial path +// jest.config.js +module.exports = { + // [...] + globals: { + 'ts-jest': { + packageJson: '/../../shared/package.json' + } + } +}; +``` + +
+ +#### Inline package metadata + +
+ +```js +// jest.config.js +module.exports = { + // [...] + globals: { + 'ts-jest': { + packageJson: { + "name": "my-project", + "version": "1.0.0", + "dependencies": { + // [...] + } + } + } + } +}; +``` + +
+ diff --git a/src/__helpers__/fakers.ts b/src/__helpers__/fakers.ts index 0ba769f57b..0628f2d540 100644 --- a/src/__helpers__/fakers.ts +++ b/src/__helpers__/fakers.ts @@ -60,6 +60,7 @@ export function tsJestConfig(options?: Partial): TsJestConfig { transformers: [], babelConfig: undefined, tsConfig: undefined, + packageJson: undefined, stringifyContentPathRegex: undefined, diagnostics: { ignoreCodes: [], pretty: false, throws: true }, ...options, diff --git a/src/config/__snapshots__/config-set.spec.ts.snap b/src/config/__snapshots__/config-set.spec.ts.snap index d17c707470..27c682189a 100644 --- a/src/config/__snapshots__/config-set.spec.ts.snap +++ b/src/config/__snapshots__/config-set.spec.ts.snap @@ -32,6 +32,10 @@ Object { "throws": true, }, "isolatedModules": false, + "packageJson": Object { + "kind": "file", + "value": undefined, + }, "stringifyContentPathRegex": undefined, "transformers": Array [], "tsConfig": Object { diff --git a/src/config/config-set.spec.ts b/src/config/config-set.spec.ts index 6cf028711c..745eff5a60 100644 --- a/src/config/config-set.spec.ts +++ b/src/config/config-set.spec.ts @@ -103,6 +103,34 @@ describe('tsJest', () => { }) }) // tsconfig + describe('packageJson', () => { + it('should be correct for default value', () => { + const EXPECTED = { + kind: 'file', + value: undefined, + } + expect(get().packageJson).toEqual(EXPECTED) + }) + + it('should be correct for given file', () => { + const FILE = 'bar/tsconfig.foo.json' + const EXPECTED = { + kind: 'file', + value: defaultResolve(FILE), + } + expect(get({ packageJson: FILE }).packageJson).toEqual(EXPECTED) + }) + + it('should be correct for inline config', () => { + const CONFIG = { foo: 'bar' } + const EXPECTED = { + kind: 'inline', + value: CONFIG, + } + expect(get({ packageJson: CONFIG as any }).packageJson).toEqual(EXPECTED) + }) + }) // packageJson + describe('babelConfig', () => { it('should be correct for default value', () => { expect(get().babelConfig).toBeUndefined() @@ -532,7 +560,7 @@ describe('cacheKey', () => { cs.jsonValue.value = val // digest is mocked in src/__mocks__/index.ts expect(cs.cacheKey).toMatchInlineSnapshot( - '"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"isolatedModules\\":false,\\"transformers\\":[]},\\"tsconfig\\":{\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"outDir\\":\\"$$ts-jest$$\\",\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1}}"', + '"{\\"digest\\":\\"a0d51ca854194df8191d0e65c0ca4730f510f332\\",\\"jest\\":{\\"__backported\\":true,\\"globals\\":{}},\\"projectDepVersions\\":{\\"dev\\":\\"1.2.5\\",\\"opt\\":\\"1.2.3\\",\\"peer\\":\\"1.2.4\\",\\"std\\":\\"1.2.6\\"},\\"transformers\\":[\\"hoisting-jest-mock@1\\"],\\"tsJest\\":{\\"compiler\\":\\"typescript\\",\\"diagnostics\\":{\\"ignoreCodes\\":[6059,18002,18003],\\"pretty\\":true,\\"throws\\":true},\\"isolatedModules\\":false,\\"packageJson\\":{\\"kind\\":\\"file\\"},\\"transformers\\":[]},\\"tsconfig\\":{\\"declaration\\":false,\\"inlineSourceMap\\":false,\\"inlineSources\\":true,\\"module\\":1,\\"noEmit\\":false,\\"outDir\\":\\"$$ts-jest$$\\",\\"removeComments\\":false,\\"sourceMap\\":true,\\"target\\":1}}"', ) }) }) // cacheKey @@ -579,6 +607,10 @@ Object { "throws": true, }, "isolatedModules": false, + "packageJson": Object { + "kind": "file", + "value": undefined, + }, "stringifyContentPathRegex": undefined, "transformers": Array [], "tsConfig": undefined, diff --git a/src/config/config-set.ts b/src/config/config-set.ts index 16fa0fb5f1..2cb2cb3482 100644 --- a/src/config/config-set.ts +++ b/src/config/config-set.ts @@ -114,18 +114,38 @@ const toDiagnosticCodeList = (items: any, into: number[] = []): number[] => { export class ConfigSet { @Memoize() get projectPackageJson(): Record { + const { + tsJest: { packageJson }, + } = this + + if (packageJson && packageJson.kind === 'inline') { + return packageJson.value + } + + if (packageJson && packageJson.kind === 'file' && packageJson.value) { + const path = this.resolvePath(packageJson.value) + if (existsSync(path)) { + return require(path) + } + this.logger.warn(Errors.UnableToFindProjectRoot) + return {} + } + const tsJestRoot = resolve(__dirname, '..', '..') let pkgPath = resolve(tsJestRoot, '..', '..', 'package.json') - let exists = existsSync(pkgPath) - if (!exists) { - if (realpathSync(this.rootDir) === realpathSync(tsJestRoot)) { - pkgPath = resolve(tsJestRoot, 'package.json') - exists = true - } else { - this.logger.warn(Errors.UnableToFindProjectRoot) + if (existsSync(pkgPath)) { + return require(pkgPath) + } + + if (realpathSync(this.rootDir) === realpathSync(tsJestRoot)) { + pkgPath = resolve(tsJestRoot, 'package.json') + if (existsSync(pkgPath)) { + return require(pkgPath) } } - return exists ? require(pkgPath) : {} + + this.logger.warn(Errors.UnableToFindProjectRoot) + return {} } @Memoize() @@ -183,6 +203,21 @@ export class ConfigSet { } } + // packageJson + const { packageJson: packageJsonOpt } = options + let packageJson: TsJestConfig['packageJson'] + if (typeof packageJsonOpt === 'string' || packageJsonOpt == null || packageJsonOpt === true) { + packageJson = { + kind: 'file', + value: typeof packageJsonOpt === 'string' ? this.resolvePath(packageJsonOpt) : undefined, + } + } else if (typeof packageJsonOpt === 'object') { + packageJson = { + kind: 'inline', + value: packageJsonOpt, + } + } + // transformers const transformers = (options.astTransformers || []).map(mod => this.resolvePath(mod, { nodeResolve: true })) @@ -234,6 +269,7 @@ export class ConfigSet { // parsed options const res: TsJestConfig = { tsConfig, + packageJson, babelConfig, diagnostics, isolatedModules: !!options.isolatedModules, diff --git a/src/types.ts b/src/types.ts index 779b4b03e5..0e75172481 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,6 +21,14 @@ export interface TsJestGlobalOptions { */ tsConfig?: boolean | string | CompilerOptions + /** + * packageJson. It can be: + * - `true` (or `undefined`, it's the default): use default package.json file + * - `path/to/package.json`: path to a specific package.json file ( can be used) + * - `{...}`: contents of a package.json + */ + packageJson?: boolean | string | object + /** * Whether to compile files as isolated modules (disables some features and type-checking, default to `false`): */ @@ -93,10 +101,20 @@ interface TsJestConfig$babelConfig$inline { value: BabelConfig } type TsJestConfig$babelConfig = TsJestConfig$babelConfig$file | TsJestConfig$babelConfig$inline | undefined +interface TsJestConfig$packageJson$file { + kind: 'file' + value: string | undefined +} +interface TsJestConfig$packageJson$inline { + kind: 'inline' + value: any +} +type TsJestConfig$packageJson = TsJestConfig$packageJson$file | TsJestConfig$packageJson$inline | undefined type TsJestConfig$stringifyContentPathRegex = string | undefined export interface TsJestConfig { tsConfig: TsJestConfig$tsConfig + packageJson: TsJestConfig$packageJson isolatedModules: boolean compiler: string diagnostics: TsJestConfig$diagnostics