feat(boc): Complete Business Operations Center v1.0

- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics)
- Rust analytics service with parallel report generation
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables, full migrations
- Redis cache, sessions, pub/sub
- Kafka event streaming with Zookeeper
- WebSocket hub for real-time updates
- Automation engine with cron jobs, workflows, event triggers
- JWT authentication, multi-tenant from start
- Docker Compose with all services
- Nginx reverse proxy with rate limiting
- Integration tests passing
- Feature gap analysis against Fortnox/Odoo/Visma

Refs: BOC-001
This commit is contained in:
Bernt
2026-07-12 12:41:35 +00:00
parent 4789a7fb48
commit 58ca4e68db
26666 changed files with 575891 additions and 2074516 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Meta Platforms, Inc. and affiliates.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+129
View File
@@ -0,0 +1,129 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
function _path() {
const data = require('path');
_path = function () {
return data;
};
return data;
}
function _ciInfo() {
const data = require('ci-info');
_ciInfo = function () {
return data;
};
return data;
}
function _jestRegexUtil() {
const data = require('jest-regex-util');
_jestRegexUtil = function () {
return data;
};
return data;
}
var _constants = require('./constants');
var _getCacheDirectory = _interopRequireDefault(require('./getCacheDirectory'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const NODE_MODULES_REGEXP = (0, _jestRegexUtil().replacePathSepForRegex)(
_constants.NODE_MODULES
);
const defaultOptions = {
automock: false,
bail: 0,
cache: true,
cacheDirectory: (0, _getCacheDirectory.default)(),
changedFilesWithAncestor: false,
ci: _ciInfo().isCI,
clearMocks: false,
collectCoverage: false,
coveragePathIgnorePatterns: [NODE_MODULES_REGEXP],
coverageProvider: 'babel',
coverageReporters: ['json', 'text', 'lcov', 'clover'],
detectLeaks: false,
detectOpenHandles: false,
errorOnDeprecated: false,
expand: false,
extensionsToTreatAsEsm: [],
fakeTimers: {
enableGlobally: false
},
forceCoverageMatch: [],
globals: {},
haste: {
computeSha1: false,
enableSymlinks: false,
forceNodeFilesystemAPI: true,
throwOnModuleCollision: false
},
injectGlobals: true,
listTests: false,
maxConcurrency: 5,
maxWorkers: '50%',
moduleDirectories: ['node_modules'],
moduleFileExtensions: [
'js',
'mjs',
'cjs',
'jsx',
'ts',
'tsx',
'json',
'node'
],
moduleNameMapper: {},
modulePathIgnorePatterns: [],
noStackTrace: false,
notify: false,
notifyMode: 'failure-change',
openHandlesTimeout: 1000,
passWithNoTests: false,
prettierPath: 'prettier',
resetMocks: false,
resetModules: false,
restoreMocks: false,
roots: ['<rootDir>'],
runTestsByPath: false,
runner: 'jest-runner',
setupFiles: [],
setupFilesAfterEnv: [],
skipFilter: false,
slowTestThreshold: 5,
snapshotFormat: {
escapeString: false,
printBasicPrototype: false
},
snapshotSerializers: [],
testEnvironment: 'jest-environment-node',
testEnvironmentOptions: {},
testFailureExitCode: 1,
testLocationInResults: false,
testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[tj]s?(x)'],
testPathIgnorePatterns: [NODE_MODULES_REGEXP],
testRegex: [],
testRunner: 'jest-circus/runner',
testSequencer: '@jest/test-sequencer',
transformIgnorePatterns: [
NODE_MODULES_REGEXP,
`\\.pnp\\.[^\\${_path().sep}]+$`
],
useStderr: false,
watch: false,
watchPathIgnorePatterns: [],
watchman: true,
workerThreads: false
};
var _default = defaultOptions;
exports.default = _default;
+85
View File
@@ -0,0 +1,85 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const deprecatedOptions = {
browser: () =>
` Option ${_chalk().default.bold(
'"browser"'
)} has been deprecated. Please install "browser-resolve" and use the "resolver" option in Jest configuration as shown in the documentation: https://jestjs.io/docs/configuration#resolver-string`,
collectCoverageOnlyFrom: _options => ` Option ${_chalk().default.bold(
'"collectCoverageOnlyFrom"'
)} was replaced by ${_chalk().default.bold('"collectCoverageFrom"')}.
Please update your configuration.`,
extraGlobals: _options => ` Option ${_chalk().default.bold(
'"extraGlobals"'
)} was replaced by ${_chalk().default.bold('"sandboxInjectedGlobals"')}.
Please update your configuration.`,
moduleLoader: _options => ` Option ${_chalk().default.bold(
'"moduleLoader"'
)} was replaced by ${_chalk().default.bold('"runtime"')}.
Please update your configuration.`,
preprocessorIgnorePatterns: _options => ` Option ${_chalk().default.bold(
'"preprocessorIgnorePatterns"'
)} was replaced by ${_chalk().default.bold(
'"transformIgnorePatterns"'
)}, which support multiple preprocessors.
Please update your configuration.`,
scriptPreprocessor: _options => ` Option ${_chalk().default.bold(
'"scriptPreprocessor"'
)} was replaced by ${_chalk().default.bold(
'"transform"'
)}, which support multiple preprocessors.
Please update your configuration.`,
setupTestFrameworkScriptFile: _options => ` Option ${_chalk().default.bold(
'"setupTestFrameworkScriptFile"'
)} was replaced by configuration ${_chalk().default.bold(
'"setupFilesAfterEnv"'
)}, which supports multiple paths.
Please update your configuration.`,
testPathDirs: _options => ` Option ${_chalk().default.bold(
'"testPathDirs"'
)} was replaced by ${_chalk().default.bold('"roots"')}.
Please update your configuration.
`,
testURL: _options => ` Option ${_chalk().default.bold(
'"testURL"'
)} was replaced by passing the URL via ${_chalk().default.bold(
'"testEnvironmentOptions.url"'
)}.
Please update your configuration.`,
timers: _options => ` Option ${_chalk().default.bold(
'"timers"'
)} was replaced by ${_chalk().default.bold('"fakeTimers"')}.
Please update your configuration.`
};
var _default = deprecatedOptions;
exports.default = _default;
@@ -0,0 +1,104 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const descriptions = {
automock: 'All imported modules in your tests should be mocked automatically',
bail: 'Stop running tests after `n` failures',
cacheDirectory:
'The directory where Jest should store its cached dependency information',
clearMocks:
'Automatically clear mock calls, instances, contexts and results before every test',
collectCoverage:
'Indicates whether the coverage information should be collected while executing the test',
collectCoverageFrom:
'An array of glob patterns indicating a set of files for which coverage information should be collected',
coverageDirectory:
'The directory where Jest should output its coverage files',
coveragePathIgnorePatterns:
'An array of regexp pattern strings used to skip coverage collection',
coverageProvider:
'Indicates which provider should be used to instrument code for coverage',
coverageReporters:
'A list of reporter names that Jest uses when writing coverage reports',
coverageThreshold:
'An object that configures minimum threshold enforcement for coverage results',
dependencyExtractor: 'A path to a custom dependency extractor',
errorOnDeprecated:
'Make calling deprecated APIs throw helpful error messages',
fakeTimers: 'The default configuration for fake timers',
forceCoverageMatch:
'Force coverage collection from ignored files using an array of glob patterns',
globalSetup:
'A path to a module which exports an async function that is triggered once before all test suites',
globalTeardown:
'A path to a module which exports an async function that is triggered once after all test suites',
globals:
'A set of global variables that need to be available in all test environments',
maxWorkers:
'The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.',
moduleDirectories:
"An array of directory names to be searched recursively up from the requiring module's location",
moduleFileExtensions: 'An array of file extensions your modules use',
moduleNameMapper:
'A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module',
modulePathIgnorePatterns:
"An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader",
notify: 'Activates notifications for test results',
notifyMode:
'An enum that specifies notification mode. Requires { notify: true }',
preset: "A preset that is used as a base for Jest's configuration",
projects: 'Run tests from one or more projects',
reporters: 'Use this configuration option to add custom reporters to Jest',
resetMocks: 'Automatically reset mock state before every test',
resetModules: 'Reset the module registry before running each individual test',
resolver: 'A path to a custom resolver',
restoreMocks:
'Automatically restore mock state and implementation before every test',
rootDir:
'The root directory that Jest should scan for tests and modules within',
roots:
'A list of paths to directories that Jest should use to search for files in',
runner:
"Allows you to use a custom runner instead of Jest's default test runner",
setupFiles:
'The paths to modules that run some code to configure or set up the testing environment before each test',
setupFilesAfterEnv:
'A list of paths to modules that run some code to configure or set up the testing framework before each test',
slowTestThreshold:
'The number of seconds after which a test is considered as slow and reported as such in the results.',
snapshotSerializers:
'A list of paths to snapshot serializer modules Jest should use for snapshot testing',
testEnvironment: 'The test environment that will be used for testing',
testEnvironmentOptions: 'Options that will be passed to the testEnvironment',
testLocationInResults: 'Adds a location field to test results',
testMatch: 'The glob patterns Jest uses to detect test files',
testPathIgnorePatterns:
'An array of regexp pattern strings that are matched against all test paths, matched tests are skipped',
testRegex:
'The regexp pattern or array of patterns that Jest uses to detect test files',
testResultsProcessor:
'This option allows the use of a custom results processor',
testRunner: 'This option allows use of a custom test runner',
transform: 'A map from regular expressions to paths to transformers',
transformIgnorePatterns:
'An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation',
unmockedModulePathPatterns:
'An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them',
verbose:
'Indicates whether each individual test should be reported during the run',
watchPathIgnorePatterns:
'An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode',
watchman: 'Whether to use watchman for file crawling'
};
var _default = descriptions;
exports.default = _default;
@@ -0,0 +1,122 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.createArrayReporterError = createArrayReporterError;
exports.createReporterError = createReporterError;
exports.validateReporters = validateReporters;
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function _jestGetType() {
const data = require('jest-get-type');
_jestGetType = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
var _utils = require('./utils');
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const validReporterTypes = ['array', 'string'];
const ERROR = `${_utils.BULLET}Reporter Validation Error`;
/**
* Reporter Validation Error is thrown if the given arguments
* within the reporter are not valid.
*
* This is a highly specific reporter error and in the future will be
* merged with jest-validate. Till then, we can make use of it. It works
* and that's what counts most at this time.
*/
function createReporterError(reporterIndex, reporterValue) {
const errorMessage =
` Reporter at index ${reporterIndex} must be of type:\n` +
` ${_chalk().default.bold.green(validReporterTypes.join(' or '))}\n` +
' but instead received:\n' +
` ${_chalk().default.bold.red(
(0, _jestGetType().getType)(reporterValue)
)}`;
return new (_jestValidate().ValidationError)(
ERROR,
errorMessage,
_utils.DOCUMENTATION_NOTE
);
}
function createArrayReporterError(
arrayReporter,
reporterIndex,
valueIndex,
value,
expectedType,
valueName
) {
const errorMessage =
` Unexpected value for ${valueName} ` +
`at index ${valueIndex} of reporter at index ${reporterIndex}\n` +
' Expected:\n' +
` ${_chalk().default.bold.red(expectedType)}\n` +
' Got:\n' +
` ${_chalk().default.bold.green((0, _jestGetType().getType)(value))}\n` +
' Reporter configuration:\n' +
` ${_chalk().default.bold.green(
JSON.stringify(arrayReporter, null, 2).split('\n').join('\n ')
)}`;
return new (_jestValidate().ValidationError)(
ERROR,
errorMessage,
_utils.DOCUMENTATION_NOTE
);
}
function validateReporters(reporterConfig) {
return reporterConfig.every((reporter, index) => {
if (Array.isArray(reporter)) {
validateArrayReporter(reporter, index);
} else if (typeof reporter !== 'string') {
throw createReporterError(index, reporter);
}
return true;
});
}
function validateArrayReporter(arrayReporter, reporterIndex) {
const [path, options] = arrayReporter;
if (typeof path !== 'string') {
throw createArrayReporterError(
arrayReporter,
reporterIndex,
0,
path,
'string',
'Path'
);
} else if (typeof options !== 'object') {
throw createArrayReporterError(
arrayReporter,
reporterIndex,
1,
options,
'object',
'Reporter Configuration'
);
}
}
+342
View File
@@ -0,0 +1,342 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.initialProjectOptions = exports.initialOptions = void 0;
function _jestRegexUtil() {
const data = require('jest-regex-util');
_jestRegexUtil = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
function _prettyFormat() {
const data = require('pretty-format');
_prettyFormat = function () {
return data;
};
return data;
}
var _constants = require('./constants');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const NODE_MODULES_REGEXP = (0, _jestRegexUtil().replacePathSepForRegex)(
_constants.NODE_MODULES
);
const initialOptions = {
automock: false,
bail: (0, _jestValidate().multipleValidOptions)(false, 0),
cache: true,
cacheDirectory: '/tmp/user/jest',
changedFilesWithAncestor: false,
changedSince: 'master',
ci: false,
clearMocks: false,
collectCoverage: true,
collectCoverageFrom: ['src', '!public'],
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [NODE_MODULES_REGEXP],
coverageProvider: 'v8',
coverageReporters: ['json', 'text', 'lcov', 'clover'],
coverageThreshold: {
global: {
branches: 50,
functions: 100,
lines: 100,
statements: 100
}
},
dependencyExtractor: '<rootDir>/dependencyExtractor.js',
detectLeaks: false,
detectOpenHandles: false,
displayName: (0, _jestValidate().multipleValidOptions)('test-config', {
color: 'blue',
name: 'test-config'
}),
errorOnDeprecated: false,
expand: false,
extensionsToTreatAsEsm: [],
fakeTimers: {
advanceTimers: (0, _jestValidate().multipleValidOptions)(40, true),
doNotFake: [
'Date',
'hrtime',
'nextTick',
'performance',
'queueMicrotask',
'requestAnimationFrame',
'cancelAnimationFrame',
'requestIdleCallback',
'cancelIdleCallback',
'setImmediate',
'clearImmediate',
'setInterval',
'clearInterval',
'setTimeout',
'clearTimeout'
],
enableGlobally: true,
legacyFakeTimers: false,
now: 1483228800000,
timerLimit: 1000
},
filter: '<rootDir>/filter.js',
forceCoverageMatch: ['**/*.t.js'],
forceExit: false,
globalSetup: 'setup.js',
globalTeardown: 'teardown.js',
globals: {
__DEV__: true
},
haste: {
computeSha1: true,
defaultPlatform: 'ios',
enableSymlinks: false,
forceNodeFilesystemAPI: true,
hasteImplModulePath: '<rootDir>/haste_impl.js',
hasteMapModulePath: '',
platforms: ['ios', 'android'],
retainAllFiles: false,
throwOnModuleCollision: false
},
id: 'string',
injectGlobals: true,
json: false,
lastCommit: false,
listTests: false,
logHeapUsage: true,
maxConcurrency: 5,
maxWorkers: '50%',
moduleDirectories: ['node_modules'],
moduleFileExtensions: [
'js',
'mjs',
'cjs',
'json',
'jsx',
'ts',
'tsx',
'node'
],
moduleNameMapper: {
'^React$': '<rootDir>/node_modules/react'
},
modulePathIgnorePatterns: ['<rootDir>/build/'],
modulePaths: ['/shared/vendor/modules'],
noStackTrace: false,
notify: false,
notifyMode: 'failure-change',
onlyChanged: false,
onlyFailures: false,
openHandlesTimeout: 1000,
passWithNoTests: false,
preset: 'react-native',
prettierPath: '<rootDir>/node_modules/prettier',
projects: ['project-a', 'project-b/'],
randomize: false,
reporters: [
'default',
'custom-reporter-1',
[
'custom-reporter-2',
{
configValue: true
}
]
],
resetMocks: false,
resetModules: false,
resolver: '<rootDir>/resolver.js',
restoreMocks: false,
rootDir: '/',
roots: ['<rootDir>'],
runTestsByPath: false,
runner: 'jest-runner',
runtime: '<rootDir>',
sandboxInjectedGlobals: [],
setupFiles: ['<rootDir>/setup.js'],
setupFilesAfterEnv: ['<rootDir>/testSetupFile.js'],
showSeed: false,
silent: true,
skipFilter: false,
skipNodeResolution: false,
slowTestThreshold: 5,
snapshotFormat: _prettyFormat().DEFAULT_OPTIONS,
snapshotResolver: '<rootDir>/snapshotResolver.js',
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-node',
testEnvironmentOptions: {
url: 'http://localhost',
userAgent: 'Agent/007'
},
testFailureExitCode: 1,
testLocationInResults: false,
testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
testNamePattern: 'test signature',
testPathIgnorePatterns: [NODE_MODULES_REGEXP],
testRegex: (0, _jestValidate().multipleValidOptions)(
'(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
['/__tests__/\\.test\\.[jt]sx?$', '/__tests__/\\.spec\\.[jt]sx?$']
),
testResultsProcessor: 'processor-node-module',
testRunner: 'circus',
testSequencer: '@jest/test-sequencer',
testTimeout: 5000,
transform: {
'\\.js$': '<rootDir>/preprocessor.js'
},
transformIgnorePatterns: [NODE_MODULES_REGEXP],
unmockedModulePathPatterns: ['mock'],
updateSnapshot: true,
useStderr: false,
verbose: false,
watch: false,
watchAll: false,
watchPathIgnorePatterns: ['<rootDir>/e2e/'],
watchPlugins: [
'path/to/yourWatchPlugin',
[
'jest-watch-typeahead/filename',
{
key: 'k',
prompt: 'do something with my custom prompt'
}
]
],
watchman: true,
workerIdleMemoryLimit: (0, _jestValidate().multipleValidOptions)(0.2, '50%'),
workerThreads: true
};
exports.initialOptions = initialOptions;
const initialProjectOptions = {
automock: false,
cache: true,
cacheDirectory: '/tmp/user/jest',
clearMocks: false,
collectCoverageFrom: ['src', '!public'],
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [NODE_MODULES_REGEXP],
dependencyExtractor: '<rootDir>/dependencyExtractor.js',
detectLeaks: false,
detectOpenHandles: false,
displayName: (0, _jestValidate().multipleValidOptions)('test-config', {
color: 'blue',
name: 'test-config'
}),
errorOnDeprecated: false,
extensionsToTreatAsEsm: [],
fakeTimers: {
advanceTimers: (0, _jestValidate().multipleValidOptions)(40, true),
doNotFake: [
'Date',
'hrtime',
'nextTick',
'performance',
'queueMicrotask',
'requestAnimationFrame',
'cancelAnimationFrame',
'requestIdleCallback',
'cancelIdleCallback',
'setImmediate',
'clearImmediate',
'setInterval',
'clearInterval',
'setTimeout',
'clearTimeout'
],
enableGlobally: true,
legacyFakeTimers: false,
now: 1483228800000,
timerLimit: 1000
},
filter: '<rootDir>/filter.js',
forceCoverageMatch: ['**/*.t.js'],
globalSetup: 'setup.js',
globalTeardown: 'teardown.js',
globals: {
__DEV__: true
},
haste: {
computeSha1: true,
defaultPlatform: 'ios',
enableSymlinks: false,
forceNodeFilesystemAPI: true,
hasteImplModulePath: '<rootDir>/haste_impl.js',
hasteMapModulePath: '',
platforms: ['ios', 'android'],
retainAllFiles: false,
throwOnModuleCollision: false
},
id: 'string',
injectGlobals: true,
moduleDirectories: ['node_modules'],
moduleFileExtensions: [
'js',
'mjs',
'cjs',
'json',
'jsx',
'ts',
'tsx',
'node'
],
moduleNameMapper: {
'^React$': '<rootDir>/node_modules/react'
},
modulePathIgnorePatterns: ['<rootDir>/build/'],
modulePaths: ['/shared/vendor/modules'],
openHandlesTimeout: 1000,
preset: 'react-native',
prettierPath: '<rootDir>/node_modules/prettier',
resetMocks: false,
resetModules: false,
resolver: '<rootDir>/resolver.js',
restoreMocks: false,
rootDir: '/',
roots: ['<rootDir>'],
runner: 'jest-runner',
runtime: '<rootDir>',
sandboxInjectedGlobals: [],
setupFiles: ['<rootDir>/setup.js'],
setupFilesAfterEnv: ['<rootDir>/testSetupFile.js'],
skipFilter: false,
skipNodeResolution: false,
slowTestThreshold: 5,
snapshotFormat: _prettyFormat().DEFAULT_OPTIONS,
snapshotResolver: '<rootDir>/snapshotResolver.js',
snapshotSerializers: ['my-serializer-module'],
testEnvironment: 'jest-environment-node',
testEnvironmentOptions: {
url: 'http://localhost',
userAgent: 'Agent/007'
},
testLocationInResults: false,
testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
testPathIgnorePatterns: [NODE_MODULES_REGEXP],
testRegex: (0, _jestValidate().multipleValidOptions)(
'(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
['/__tests__/\\.test\\.[jt]sx?$', '/__tests__/\\.spec\\.[jt]sx?$']
),
testRunner: 'circus',
transform: {
'\\.js$': '<rootDir>/preprocessor.js'
},
transformIgnorePatterns: [NODE_MODULES_REGEXP],
unmockedModulePathPatterns: ['mock'],
watchPathIgnorePatterns: ['<rootDir>/e2e/'],
workerIdleMemoryLimit: (0, _jestValidate().multipleValidOptions)(0.2, '50%')
};
exports.initialProjectOptions = initialProjectOptions;
+31
View File
@@ -0,0 +1,31 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.getDisplayNameColor = void 0;
function _crypto() {
const data = require('crypto');
_crypto = function () {
return data;
};
return data;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const colors = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
const getDisplayNameColor = seed => {
if (seed === undefined) {
return 'white';
}
const hash = (0, _crypto().createHash)('sha256');
hash.update(seed);
const num = hash.digest().readUInt32LE(0);
return colors[num % colors.length];
};
exports.getDisplayNameColor = getDisplayNameColor;
+96
View File
@@ -0,0 +1,96 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.PACKAGE_JSON =
exports.NODE_MODULES =
exports.JEST_CONFIG_EXT_TS =
exports.JEST_CONFIG_EXT_ORDER =
exports.JEST_CONFIG_EXT_MJS =
exports.JEST_CONFIG_EXT_JSON =
exports.JEST_CONFIG_EXT_JS =
exports.JEST_CONFIG_EXT_CJS =
exports.JEST_CONFIG_BASE_NAME =
exports.DEFAULT_JS_PATTERN =
void 0;
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const NODE_MODULES = `${path().sep}node_modules${path().sep}`;
exports.NODE_MODULES = NODE_MODULES;
const DEFAULT_JS_PATTERN = '\\.[jt]sx?$';
exports.DEFAULT_JS_PATTERN = DEFAULT_JS_PATTERN;
const PACKAGE_JSON = 'package.json';
exports.PACKAGE_JSON = PACKAGE_JSON;
const JEST_CONFIG_BASE_NAME = 'jest.config';
exports.JEST_CONFIG_BASE_NAME = JEST_CONFIG_BASE_NAME;
const JEST_CONFIG_EXT_CJS = '.cjs';
exports.JEST_CONFIG_EXT_CJS = JEST_CONFIG_EXT_CJS;
const JEST_CONFIG_EXT_MJS = '.mjs';
exports.JEST_CONFIG_EXT_MJS = JEST_CONFIG_EXT_MJS;
const JEST_CONFIG_EXT_JS = '.js';
exports.JEST_CONFIG_EXT_JS = JEST_CONFIG_EXT_JS;
const JEST_CONFIG_EXT_TS = '.ts';
exports.JEST_CONFIG_EXT_TS = JEST_CONFIG_EXT_TS;
const JEST_CONFIG_EXT_JSON = '.json';
exports.JEST_CONFIG_EXT_JSON = JEST_CONFIG_EXT_JSON;
const JEST_CONFIG_EXT_ORDER = Object.freeze([
JEST_CONFIG_EXT_JS,
JEST_CONFIG_EXT_TS,
JEST_CONFIG_EXT_MJS,
JEST_CONFIG_EXT_CJS,
JEST_CONFIG_EXT_JSON
]);
exports.JEST_CONFIG_EXT_ORDER = JEST_CONFIG_EXT_ORDER;
@@ -0,0 +1,91 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
function _os() {
const data = require('os');
_os = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require('jest-util');
_jestUtil = function () {
return data;
};
return data;
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const getCacheDirectory = () => {
const {getuid} = process;
const tmpdirPath = path().join(
(0, _jestUtil().tryRealpath)((0, _os().tmpdir)()),
'jest'
);
if (getuid == null) {
return tmpdirPath;
} else {
// On some platforms tmpdir() is `/tmp`, causing conflicts between different
// users and permission issues. Adding an additional subdivision by UID can
// help.
return `${tmpdirPath}_${getuid.call(process).toString(36)}`;
}
};
var _default = getCacheDirectory;
exports.default = _default;
@@ -0,0 +1,56 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = getMaxWorkers;
function _os() {
const data = require('os');
_os = function () {
return data;
};
return data;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
function getNumCpus() {
return typeof _os().availableParallelism === 'function'
? (0, _os().availableParallelism)()
: (0, _os().cpus)()?.length ?? 1;
}
function getMaxWorkers(argv, defaultOptions) {
if (argv.runInBand) {
return 1;
} else if (argv.maxWorkers) {
return parseWorkers(argv.maxWorkers);
} else if (defaultOptions && defaultOptions.maxWorkers) {
return parseWorkers(defaultOptions.maxWorkers);
} else {
// In watch mode, Jest should be unobtrusive and not use all available CPUs.
const numCpus = getNumCpus();
const isWatchModeEnabled = argv.watch || argv.watchAll;
return Math.max(
isWatchModeEnabled ? Math.floor(numCpus / 2) : numCpus - 1,
1
);
}
}
const parseWorkers = maxWorkers => {
const parsed = parseInt(maxWorkers.toString(), 10);
if (
typeof maxWorkers === 'string' &&
maxWorkers.trim().endsWith('%') &&
parsed > 0 &&
parsed <= 100
) {
const numCpus = getNumCpus();
const workers = Math.floor((parsed / 100) * numCpus);
return Math.max(workers, 1);
}
return parsed > 0 ? parsed : 1;
};
+147
View File
@@ -0,0 +1,147 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type {Config} from '@jest/types';
import type {DeprecatedOptions} from 'jest-validate';
declare type AllOptions = Config.ProjectConfig & Config.GlobalConfig;
declare namespace constants {
export {
NODE_MODULES,
DEFAULT_JS_PATTERN,
PACKAGE_JSON,
JEST_CONFIG_BASE_NAME,
JEST_CONFIG_EXT_CJS,
JEST_CONFIG_EXT_MJS,
JEST_CONFIG_EXT_JS,
JEST_CONFIG_EXT_TS,
JEST_CONFIG_EXT_JSON,
JEST_CONFIG_EXT_ORDER,
};
}
export {constants};
declare const DEFAULT_JS_PATTERN = '\\.[jt]sx?$';
export declare const defaults: Config.DefaultOptions;
export declare const deprecationEntries: DeprecatedOptions;
export declare const descriptions: {
[key in keyof Config.InitialOptions]: string;
};
export declare const isJSONString: (
text?: JSONString | string,
) => text is JSONString;
declare const JEST_CONFIG_BASE_NAME = 'jest.config';
declare const JEST_CONFIG_EXT_CJS = '.cjs';
declare const JEST_CONFIG_EXT_JS = '.js';
declare const JEST_CONFIG_EXT_JSON = '.json';
declare const JEST_CONFIG_EXT_MJS = '.mjs';
declare const JEST_CONFIG_EXT_ORDER: readonly string[];
declare const JEST_CONFIG_EXT_TS = '.ts';
declare type JSONString = string & {
readonly $$type: never;
};
declare const NODE_MODULES: string;
export declare function normalize(
initialOptions: Config.InitialOptions,
argv: Config.Argv,
configPath?: string | null,
projectIndex?: number,
isProjectOptions?: boolean,
): Promise<{
hasDeprecationWarnings: boolean;
options: AllOptions;
}>;
declare const PACKAGE_JSON = 'package.json';
declare type ReadConfig = {
configPath: string | null | undefined;
globalConfig: Config.GlobalConfig;
hasDeprecationWarnings: boolean;
projectConfig: Config.ProjectConfig;
};
export declare function readConfig(
argv: Config.Argv,
packageRootOrConfig: string | Config.InitialOptions,
skipArgvConfigOption?: boolean,
parentConfigDirname?: string | null,
projectIndex?: number,
skipMultipleConfigError?: boolean,
): Promise<ReadConfig>;
export declare function readConfigs(
argv: Config.Argv,
projectPaths: Array<string>,
): Promise<{
globalConfig: Config.GlobalConfig;
configs: Array<Config.ProjectConfig>;
hasDeprecationWarnings: boolean;
}>;
/**
* Reads the jest config, without validating them or filling it out with defaults.
* @param config The path to the file or serialized config.
* @param param1 Additional options
* @returns The raw initial config (not validated)
*/
export declare function readInitialOptions(
config?: string,
{
packageRootOrConfig,
parentConfigDirname,
readFromCwd,
skipMultipleConfigError,
}?: ReadJestConfigOptions,
): Promise<{
config: Config.InitialOptions;
configPath: string | null;
}>;
export declare interface ReadJestConfigOptions {
/**
* The package root or deserialized config (default is cwd)
*/
packageRootOrConfig?: string | Config.InitialOptions;
/**
* When the `packageRootOrConfig` contains config, this parameter should
* contain the dirname of the parent config
*/
parentConfigDirname?: null | string;
/**
* Indicates whether or not to read the specified config file from disk.
* When true, jest will read try to read config from the current working directory.
* (default is false)
*/
readFromCwd?: boolean;
/**
* Indicates whether or not to ignore the error of jest finding multiple config files.
* (default is false)
*/
skipMultipleConfigError?: boolean;
}
export declare const replaceRootDirInPath: (
rootDir: string,
filePath: string,
) => string;
export {};
+494
View File
@@ -0,0 +1,494 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.constants = void 0;
Object.defineProperty(exports, 'defaults', {
enumerable: true,
get: function () {
return _Defaults.default;
}
});
Object.defineProperty(exports, 'deprecationEntries', {
enumerable: true,
get: function () {
return _Deprecated.default;
}
});
Object.defineProperty(exports, 'descriptions', {
enumerable: true,
get: function () {
return _Descriptions.default;
}
});
Object.defineProperty(exports, 'isJSONString', {
enumerable: true,
get: function () {
return _utils.isJSONString;
}
});
Object.defineProperty(exports, 'normalize', {
enumerable: true,
get: function () {
return _normalize.default;
}
});
exports.readConfig = readConfig;
exports.readConfigs = readConfigs;
exports.readInitialOptions = readInitialOptions;
Object.defineProperty(exports, 'replaceRootDirInPath', {
enumerable: true,
get: function () {
return _utils.replaceRootDirInPath;
}
});
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require('graceful-fs'));
fs = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require('jest-util');
_jestUtil = function () {
return data;
};
return data;
}
var constants = _interopRequireWildcard(require('./constants'));
exports.constants = constants;
var _normalize = _interopRequireDefault(require('./normalize'));
var _readConfigFileAndSetRootDir = _interopRequireDefault(
require('./readConfigFileAndSetRootDir')
);
var _resolveConfigPath = _interopRequireDefault(require('./resolveConfigPath'));
var _utils = require('./utils');
var _Deprecated = _interopRequireDefault(require('./Deprecated'));
var _Defaults = _interopRequireDefault(require('./Defaults'));
var _Descriptions = _interopRequireDefault(require('./Descriptions'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
async function readConfig(
argv,
packageRootOrConfig,
// Whether it needs to look into `--config` arg passed to CLI.
// It only used to read initial config. If the initial config contains
// `project` property, we don't want to read `--config` value and rather
// read individual configs for every project.
skipArgvConfigOption,
parentConfigDirname,
projectIndex = Infinity,
skipMultipleConfigError = false
) {
const {config: initialOptions, configPath} = await readInitialOptions(
argv.config,
{
packageRootOrConfig,
parentConfigDirname,
readFromCwd: skipArgvConfigOption,
skipMultipleConfigError
}
);
const packageRoot =
typeof packageRootOrConfig === 'string'
? path().resolve(packageRootOrConfig)
: undefined;
const {options, hasDeprecationWarnings} = await (0, _normalize.default)(
initialOptions,
argv,
configPath,
projectIndex,
skipArgvConfigOption && !(packageRoot === parentConfigDirname)
);
const {globalConfig, projectConfig} = groupOptions(options);
return {
configPath,
globalConfig,
hasDeprecationWarnings,
projectConfig
};
}
const groupOptions = options => ({
globalConfig: Object.freeze({
bail: options.bail,
changedFilesWithAncestor: options.changedFilesWithAncestor,
changedSince: options.changedSince,
ci: options.ci,
collectCoverage: options.collectCoverage,
collectCoverageFrom: options.collectCoverageFrom,
coverageDirectory: options.coverageDirectory,
coverageProvider: options.coverageProvider,
coverageReporters: options.coverageReporters,
coverageThreshold: options.coverageThreshold,
detectLeaks: options.detectLeaks,
detectOpenHandles: options.detectOpenHandles,
errorOnDeprecated: options.errorOnDeprecated,
expand: options.expand,
filter: options.filter,
findRelatedTests: options.findRelatedTests,
forceExit: options.forceExit,
globalSetup: options.globalSetup,
globalTeardown: options.globalTeardown,
json: options.json,
lastCommit: options.lastCommit,
listTests: options.listTests,
logHeapUsage: options.logHeapUsage,
maxConcurrency: options.maxConcurrency,
maxWorkers: options.maxWorkers,
noSCM: undefined,
noStackTrace: options.noStackTrace,
nonFlagArgs: options.nonFlagArgs,
notify: options.notify,
notifyMode: options.notifyMode,
onlyChanged: options.onlyChanged,
onlyFailures: options.onlyFailures,
openHandlesTimeout: options.openHandlesTimeout,
outputFile: options.outputFile,
passWithNoTests: options.passWithNoTests,
projects: options.projects,
randomize: options.randomize,
replname: options.replname,
reporters: options.reporters,
rootDir: options.rootDir,
runInBand: options.runInBand,
runTestsByPath: options.runTestsByPath,
seed: options.seed,
shard: options.shard,
showSeed: options.showSeed,
silent: options.silent,
skipFilter: options.skipFilter,
snapshotFormat: options.snapshotFormat,
testFailureExitCode: options.testFailureExitCode,
testNamePattern: options.testNamePattern,
testPathPattern: options.testPathPattern,
testResultsProcessor: options.testResultsProcessor,
testSequencer: options.testSequencer,
testTimeout: options.testTimeout,
updateSnapshot: options.updateSnapshot,
useStderr: options.useStderr,
verbose: options.verbose,
watch: options.watch,
watchAll: options.watchAll,
watchPlugins: options.watchPlugins,
watchman: options.watchman,
workerIdleMemoryLimit: options.workerIdleMemoryLimit,
workerThreads: options.workerThreads
}),
projectConfig: Object.freeze({
automock: options.automock,
cache: options.cache,
cacheDirectory: options.cacheDirectory,
clearMocks: options.clearMocks,
collectCoverageFrom: options.collectCoverageFrom,
coverageDirectory: options.coverageDirectory,
coveragePathIgnorePatterns: options.coveragePathIgnorePatterns,
cwd: options.cwd,
dependencyExtractor: options.dependencyExtractor,
detectLeaks: options.detectLeaks,
detectOpenHandles: options.detectOpenHandles,
displayName: options.displayName,
errorOnDeprecated: options.errorOnDeprecated,
extensionsToTreatAsEsm: options.extensionsToTreatAsEsm,
fakeTimers: options.fakeTimers,
filter: options.filter,
forceCoverageMatch: options.forceCoverageMatch,
globalSetup: options.globalSetup,
globalTeardown: options.globalTeardown,
globals: options.globals,
haste: options.haste,
id: options.id,
injectGlobals: options.injectGlobals,
moduleDirectories: options.moduleDirectories,
moduleFileExtensions: options.moduleFileExtensions,
moduleNameMapper: options.moduleNameMapper,
modulePathIgnorePatterns: options.modulePathIgnorePatterns,
modulePaths: options.modulePaths,
openHandlesTimeout: options.openHandlesTimeout,
prettierPath: options.prettierPath,
resetMocks: options.resetMocks,
resetModules: options.resetModules,
resolver: options.resolver,
restoreMocks: options.restoreMocks,
rootDir: options.rootDir,
roots: options.roots,
runner: options.runner,
runtime: options.runtime,
sandboxInjectedGlobals: options.sandboxInjectedGlobals,
setupFiles: options.setupFiles,
setupFilesAfterEnv: options.setupFilesAfterEnv,
skipFilter: options.skipFilter,
skipNodeResolution: options.skipNodeResolution,
slowTestThreshold: options.slowTestThreshold,
snapshotFormat: options.snapshotFormat,
snapshotResolver: options.snapshotResolver,
snapshotSerializers: options.snapshotSerializers,
testEnvironment: options.testEnvironment,
testEnvironmentOptions: options.testEnvironmentOptions,
testLocationInResults: options.testLocationInResults,
testMatch: options.testMatch,
testPathIgnorePatterns: options.testPathIgnorePatterns,
testRegex: options.testRegex,
testRunner: options.testRunner,
transform: options.transform,
transformIgnorePatterns: options.transformIgnorePatterns,
unmockedModulePathPatterns: options.unmockedModulePathPatterns,
watchPathIgnorePatterns: options.watchPathIgnorePatterns
})
});
const ensureNoDuplicateConfigs = (parsedConfigs, projects) => {
if (projects.length <= 1) {
return;
}
const configPathMap = new Map();
for (const config of parsedConfigs) {
const {configPath} = config;
if (configPathMap.has(configPath)) {
const message = `Whoops! Two projects resolved to the same config path: ${_chalk().default.bold(
String(configPath)
)}:
Project 1: ${_chalk().default.bold(
projects[parsedConfigs.findIndex(x => x === config)]
)}
Project 2: ${_chalk().default.bold(
projects[parsedConfigs.findIndex(x => x === configPathMap.get(configPath))]
)}
This usually means that your ${_chalk().default.bold(
'"projects"'
)} config includes a directory that doesn't have any configuration recognizable by Jest. Please fix it.
`;
throw new Error(message);
}
if (configPath !== null) {
configPathMap.set(configPath, config);
}
}
};
/**
* Reads the jest config, without validating them or filling it out with defaults.
* @param config The path to the file or serialized config.
* @param param1 Additional options
* @returns The raw initial config (not validated)
*/
async function readInitialOptions(
config,
{
packageRootOrConfig = process.cwd(),
parentConfigDirname = null,
readFromCwd = false,
skipMultipleConfigError = false
} = {}
) {
if (typeof packageRootOrConfig !== 'string') {
if (parentConfigDirname) {
const rawOptions = packageRootOrConfig;
rawOptions.rootDir = rawOptions.rootDir
? (0, _utils.replaceRootDirInPath)(
parentConfigDirname,
rawOptions.rootDir
)
: parentConfigDirname;
return {
config: rawOptions,
configPath: null
};
} else {
throw new Error(
'Jest: Cannot use configuration as an object without a file path.'
);
}
}
if ((0, _utils.isJSONString)(config)) {
try {
// A JSON string was passed to `--config` argument and we can parse it
// and use as is.
const initialOptions = JSON.parse(config);
// NOTE: we might need to resolve this dir to an absolute path in the future
initialOptions.rootDir = initialOptions.rootDir || packageRootOrConfig;
return {
config: initialOptions,
configPath: null
};
} catch {
throw new Error(
'There was an error while parsing the `--config` argument as a JSON string.'
);
}
}
if (!readFromCwd && typeof config == 'string') {
// A string passed to `--config`, which is either a direct path to the config
// or a path to directory containing `package.json`, `jest.config.js` or `jest.config.ts`
const configPath = (0, _resolveConfigPath.default)(
config,
process.cwd(),
skipMultipleConfigError
);
return {
config: await (0, _readConfigFileAndSetRootDir.default)(configPath),
configPath
};
}
// Otherwise just try to find config in the current rootDir.
const configPath = (0, _resolveConfigPath.default)(
packageRootOrConfig,
process.cwd(),
skipMultipleConfigError
);
return {
config: await (0, _readConfigFileAndSetRootDir.default)(configPath),
configPath
};
}
// Possible scenarios:
// 1. jest --config config.json
// 2. jest --projects p1 p2
// 3. jest --projects p1 p2 --config config.json
// 4. jest --projects p1
// 5. jest
//
// If no projects are specified, process.cwd() will be used as the default
// (and only) project.
async function readConfigs(argv, projectPaths) {
let globalConfig;
let hasDeprecationWarnings;
let configs = [];
let projects = projectPaths;
let configPath;
if (projectPaths.length === 1) {
const parsedConfig = await readConfig(argv, projects[0]);
configPath = parsedConfig.configPath;
hasDeprecationWarnings = parsedConfig.hasDeprecationWarnings;
globalConfig = parsedConfig.globalConfig;
configs = [parsedConfig.projectConfig];
if (globalConfig.projects && globalConfig.projects.length) {
// Even though we had one project in CLI args, there might be more
// projects defined in the config.
// In other words, if this was a single project,
// and its config has `projects` settings, use that value instead.
projects = globalConfig.projects;
}
}
if (projects.length > 0) {
const cwd =
process.platform === 'win32'
? (0, _jestUtil().tryRealpath)(process.cwd())
: process.cwd();
const projectIsCwd = projects[0] === cwd;
const parsedConfigs = await Promise.all(
projects
.filter(root => {
// Ignore globbed files that cannot be `require`d.
if (
typeof root === 'string' &&
fs().existsSync(root) &&
!fs().lstatSync(root).isDirectory() &&
!constants.JEST_CONFIG_EXT_ORDER.some(ext => root.endsWith(ext))
) {
return false;
}
return true;
})
.map((root, projectIndex) => {
const projectIsTheOnlyProject =
projectIndex === 0 && projects.length === 1;
const skipArgvConfigOption = !(
projectIsTheOnlyProject && projectIsCwd
);
return readConfig(
argv,
root,
skipArgvConfigOption,
configPath ? path().dirname(configPath) : cwd,
projectIndex,
// we wanna skip the warning if this is the "main" project
projectIsCwd
);
})
);
ensureNoDuplicateConfigs(parsedConfigs, projects);
configs = parsedConfigs.map(({projectConfig}) => projectConfig);
if (!hasDeprecationWarnings) {
hasDeprecationWarnings = parsedConfigs.some(
({hasDeprecationWarnings}) => !!hasDeprecationWarnings
);
}
// If no config was passed initially, use the one from the first project
if (!globalConfig) {
globalConfig = parsedConfigs[0].globalConfig;
}
}
if (!globalConfig || !configs.length) {
throw new Error('jest: No configuration found for any project.');
}
return {
configs,
globalConfig,
hasDeprecationWarnings: !!hasDeprecationWarnings
};
}
+1180
View File
@@ -0,0 +1,1180 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = normalize;
function _crypto() {
const data = require('crypto');
_crypto = function () {
return data;
};
return data;
}
function _os() {
const data = require('os');
_os = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function _deepmerge() {
const data = _interopRequireDefault(require('deepmerge'));
_deepmerge = function () {
return data;
};
return data;
}
function _glob() {
const data = require('glob');
_glob = function () {
return data;
};
return data;
}
function _gracefulFs() {
const data = require('graceful-fs');
_gracefulFs = function () {
return data;
};
return data;
}
function _micromatch() {
const data = _interopRequireDefault(require('micromatch'));
_micromatch = function () {
return data;
};
return data;
}
function _jestRegexUtil() {
const data = require('jest-regex-util');
_jestRegexUtil = function () {
return data;
};
return data;
}
function _jestResolve() {
const data = _interopRequireWildcard(require('jest-resolve'));
_jestResolve = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require('jest-util');
_jestUtil = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
var _Defaults = _interopRequireDefault(require('./Defaults'));
var _Deprecated = _interopRequireDefault(require('./Deprecated'));
var _ReporterValidationErrors = require('./ReporterValidationErrors');
var _ValidConfig = require('./ValidConfig');
var _color = require('./color');
var _constants = require('./constants');
var _getMaxWorkers = _interopRequireDefault(require('./getMaxWorkers'));
var _parseShardPair = require('./parseShardPair');
var _setFromArgv = _interopRequireDefault(require('./setFromArgv'));
var _stringToBytes = _interopRequireDefault(require('./stringToBytes'));
var _utils = require('./utils');
var _validatePattern = _interopRequireDefault(require('./validatePattern'));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const ERROR = `${_utils.BULLET}Validation Error`;
const PRESET_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs'];
const PRESET_NAME = 'jest-preset';
const createConfigError = message =>
new (_jestValidate().ValidationError)(
ERROR,
message,
_utils.DOCUMENTATION_NOTE
);
function verifyDirectoryExists(path, key) {
try {
const rootStat = (0, _gracefulFs().statSync)(path);
if (!rootStat.isDirectory()) {
throw createConfigError(
` ${_chalk().default.bold(path)} in the ${_chalk().default.bold(
key
)} option is not a directory.`
);
}
} catch (err) {
if (err instanceof _jestValidate().ValidationError) {
throw err;
}
if (err.code === 'ENOENT') {
throw createConfigError(
` Directory ${_chalk().default.bold(
path
)} in the ${_chalk().default.bold(key)} option was not found.`
);
}
// Not sure in which cases `statSync` can throw, so let's just show the underlying error to the user
throw createConfigError(
` Got an error trying to find ${_chalk().default.bold(
path
)} in the ${_chalk().default.bold(key)} option.\n\n Error was: ${
err.message
}`
);
}
}
const mergeOptionWithPreset = (options, preset, optionName) => {
if (options[optionName] && preset[optionName]) {
options[optionName] = {
...options[optionName],
...preset[optionName],
...options[optionName]
};
}
};
const mergeGlobalsWithPreset = (options, preset) => {
if (options.globals && preset.globals) {
options.globals = (0, _deepmerge().default)(
preset.globals,
options.globals
);
}
};
const setupPreset = async (options, optionsPreset) => {
let preset;
const presetPath = (0, _utils.replaceRootDirInPath)(
options.rootDir,
optionsPreset
);
const presetModule = _jestResolve().default.findNodeModule(
presetPath.startsWith('.')
? presetPath
: path().join(presetPath, PRESET_NAME),
{
basedir: options.rootDir,
extensions: PRESET_EXTENSIONS
}
);
try {
if (!presetModule) {
throw new Error(`Cannot find module '${presetPath}'`);
}
// Force re-evaluation to support multiple projects
try {
delete require.cache[require.resolve(presetModule)];
} catch {}
preset = await (0, _jestUtil().requireOrImportModule)(presetModule);
} catch (error) {
if (error instanceof SyntaxError || error instanceof TypeError) {
throw createConfigError(
` Preset ${_chalk().default.bold(presetPath)} is invalid:\n\n ${
error.message
}\n ${error.stack}`
);
}
if (error.message.includes('Cannot find module')) {
if (error.message.includes(presetPath)) {
const preset = _jestResolve().default.findNodeModule(presetPath, {
basedir: options.rootDir
});
if (preset) {
throw createConfigError(
` Module ${_chalk().default.bold(
presetPath
)} should have "jest-preset.js" or "jest-preset.json" file at the root.`
);
}
throw createConfigError(
` Preset ${_chalk().default.bold(presetPath)} not found.`
);
}
throw createConfigError(
` Missing dependency in ${_chalk().default.bold(presetPath)}:\n\n ${
error.message
}\n ${error.stack}`
);
}
throw createConfigError(
` An unknown error occurred in ${_chalk().default.bold(
presetPath
)}:\n\n ${error.message}\n ${error.stack}`
);
}
if (options.setupFiles) {
options.setupFiles = (preset.setupFiles || []).concat(options.setupFiles);
}
if (options.setupFilesAfterEnv) {
options.setupFilesAfterEnv = (preset.setupFilesAfterEnv || []).concat(
options.setupFilesAfterEnv
);
}
if (options.modulePathIgnorePatterns && preset.modulePathIgnorePatterns) {
options.modulePathIgnorePatterns = preset.modulePathIgnorePatterns.concat(
options.modulePathIgnorePatterns
);
}
mergeOptionWithPreset(options, preset, 'moduleNameMapper');
mergeOptionWithPreset(options, preset, 'transform');
mergeGlobalsWithPreset(options, preset);
return {
...preset,
...options
};
};
const setupBabelJest = options => {
const transform = options.transform;
let babelJest;
if (transform) {
const customJSPattern = Object.keys(transform).find(pattern => {
const regex = new RegExp(pattern);
return regex.test('a.js') || regex.test('a.jsx');
});
const customTSPattern = Object.keys(transform).find(pattern => {
const regex = new RegExp(pattern);
return regex.test('a.ts') || regex.test('a.tsx');
});
[customJSPattern, customTSPattern].forEach(pattern => {
if (pattern) {
const customTransformer = transform[pattern];
if (Array.isArray(customTransformer)) {
if (customTransformer[0] === 'babel-jest') {
babelJest = require.resolve('babel-jest');
customTransformer[0] = babelJest;
} else if (customTransformer[0].includes('babel-jest')) {
babelJest = customTransformer[0];
}
} else {
if (customTransformer === 'babel-jest') {
babelJest = require.resolve('babel-jest');
transform[pattern] = babelJest;
} else if (customTransformer.includes('babel-jest')) {
babelJest = customTransformer;
}
}
}
});
} else {
babelJest = require.resolve('babel-jest');
options.transform = {
[_constants.DEFAULT_JS_PATTERN]: babelJest
};
}
};
const normalizeCollectCoverageFrom = (options, key) => {
const initialCollectCoverageFrom = options[key];
let value;
if (!initialCollectCoverageFrom) {
value = [];
}
if (!Array.isArray(initialCollectCoverageFrom)) {
try {
value = JSON.parse(initialCollectCoverageFrom);
} catch {}
if (options[key] && !Array.isArray(value)) {
value = [initialCollectCoverageFrom];
}
} else {
value = initialCollectCoverageFrom;
}
if (value) {
value = value.map(filePath =>
filePath.replace(/^(!?)(<rootDir>\/)(.*)/, '$1$3')
);
}
return value;
};
const normalizeUnmockedModulePathPatterns = (options, key) =>
// _replaceRootDirTags is specifically well-suited for substituting
// <rootDir> in paths (it deals with properly interpreting relative path
// separators, etc).
//
// For patterns, direct global substitution is far more ideal, so we
// special case substitutions for patterns here.
options[key].map(pattern =>
(0, _jestRegexUtil().replacePathSepForRegex)(
pattern.replace(/<rootDir>/g, options.rootDir)
)
);
const normalizeMissingOptions = (options, configPath, projectIndex) => {
if (!options.id) {
options.id = (0, _crypto().createHash)('sha1')
.update(options.rootDir)
// In case we load config from some path that has the same root dir
.update(configPath || '')
.update(String(projectIndex))
.digest('hex')
.substring(0, 32);
}
if (!options.setupFiles) {
options.setupFiles = [];
}
return options;
};
const normalizeRootDir = options => {
// Assert that there *is* a rootDir
if (!options.rootDir) {
throw createConfigError(
` Configuration option ${_chalk().default.bold(
'rootDir'
)} must be specified.`
);
}
options.rootDir = path().normalize(options.rootDir);
try {
// try to resolve windows short paths, ignoring errors (permission errors, mostly)
options.rootDir = (0, _jestUtil().tryRealpath)(options.rootDir);
} catch {
// ignored
}
verifyDirectoryExists(options.rootDir, 'rootDir');
return {
...options,
rootDir: options.rootDir
};
};
const normalizeReporters = ({reporters, rootDir}) => {
if (!reporters || !Array.isArray(reporters)) {
return undefined;
}
(0, _ReporterValidationErrors.validateReporters)(reporters);
return reporters.map(reporterConfig => {
const normalizedReporterConfig =
typeof reporterConfig === 'string'
? // if reporter config is a string, we wrap it in an array
// and pass an empty object for options argument, to normalize
// the shape.
[reporterConfig, {}]
: reporterConfig;
const reporterPath = (0, _utils.replaceRootDirInPath)(
rootDir,
normalizedReporterConfig[0]
);
if (!['default', 'github-actions', 'summary'].includes(reporterPath)) {
const reporter = _jestResolve().default.findNodeModule(reporterPath, {
basedir: rootDir
});
if (!reporter) {
throw new (_jestResolve().default.ModuleNotFoundError)(
'Could not resolve a module for a custom reporter.\n' +
` Module name: ${reporterPath}`
);
}
normalizedReporterConfig[0] = reporter;
}
return normalizedReporterConfig;
});
};
const buildTestPathPattern = argv => {
const patterns = [];
if (argv._) {
patterns.push(...argv._);
}
if (argv.testPathPattern) {
patterns.push(...argv.testPathPattern);
}
const replacePosixSep = pattern => {
// yargs coerces positional args into numbers
const patternAsString = pattern.toString();
if (path().sep === '/') {
return patternAsString;
}
return patternAsString.replace(/\//g, '\\\\');
};
const testPathPattern = patterns.map(replacePosixSep).join('|');
if ((0, _validatePattern.default)(testPathPattern)) {
return testPathPattern;
} else {
showTestPathPatternError(testPathPattern);
return '';
}
};
const showTestPathPatternError = testPathPattern => {
(0, _jestUtil().clearLine)(process.stdout);
// eslint-disable-next-line no-console
console.log(
_chalk().default.red(
` Invalid testPattern ${testPathPattern} supplied. ` +
'Running all tests instead.'
)
);
};
function validateExtensionsToTreatAsEsm(extensionsToTreatAsEsm) {
if (!extensionsToTreatAsEsm || extensionsToTreatAsEsm.length === 0) {
return;
}
function printConfig(opts) {
const string = opts.map(ext => `'${ext}'`).join(', ');
return _chalk().default.bold(`extensionsToTreatAsEsm: [${string}]`);
}
const extensionWithoutDot = extensionsToTreatAsEsm.some(
ext => !ext.startsWith('.')
);
if (extensionWithoutDot) {
throw createConfigError(` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes a string that does not start with a period (${_chalk().default.bold(
'.'
)}).
Please change your configuration to ${printConfig(
extensionsToTreatAsEsm.map(ext => (ext.startsWith('.') ? ext : `.${ext}`))
)}.`);
}
if (extensionsToTreatAsEsm.includes('.js')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.js'"
)} which is always inferred based on ${_chalk().default.bold(
'type'
)} in its nearest ${_chalk().default.bold('package.json')}.`
);
}
if (extensionsToTreatAsEsm.includes('.cjs')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.cjs'"
)} which is always treated as CommonJS.`
);
}
if (extensionsToTreatAsEsm.includes('.mjs')) {
throw createConfigError(
` Option: ${printConfig(
extensionsToTreatAsEsm
)} includes ${_chalk().default.bold(
"'.mjs'"
)} which is always treated as an ECMAScript Module.`
);
}
}
async function normalize(
initialOptions,
argv,
configPath,
projectIndex = Infinity,
isProjectOptions
) {
const {hasDeprecationWarnings} = (0, _jestValidate().validate)(
initialOptions,
{
comment: _utils.DOCUMENTATION_NOTE,
deprecatedConfig: _Deprecated.default,
exampleConfig: isProjectOptions
? _ValidConfig.initialProjectOptions
: _ValidConfig.initialOptions,
recursiveDenylist: [
// 'coverageThreshold' allows to use 'global' and glob strings on the same
// level, there's currently no way we can deal with such config
'coverageThreshold',
'globals',
'moduleNameMapper',
'testEnvironmentOptions',
'transform'
]
}
);
let options = normalizeMissingOptions(
normalizeRootDir((0, _setFromArgv.default)(initialOptions, argv)),
configPath,
projectIndex
);
if (options.preset) {
options = await setupPreset(options, options.preset);
}
if (!options.setupFilesAfterEnv) {
options.setupFilesAfterEnv = [];
}
options.testEnvironment = (0, _jestResolve().resolveTestEnvironment)({
requireResolveFunction: require.resolve,
rootDir: options.rootDir,
testEnvironment:
options.testEnvironment ||
require.resolve(_Defaults.default.testEnvironment)
});
if (!options.roots) {
options.roots = [options.rootDir];
}
if (
!options.testRunner ||
options.testRunner === 'circus' ||
options.testRunner === 'jest-circus' ||
options.testRunner === 'jest-circus/runner'
) {
options.testRunner = require.resolve('jest-circus/runner');
} else if (options.testRunner === 'jasmine2') {
try {
options.testRunner = require.resolve('jest-jasmine2');
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
throw createConfigError(
'jest-jasmine is no longer shipped by default with Jest, you need to install it explicitly or provide an absolute path to Jest'
);
}
throw error;
}
}
if (!options.coverageDirectory) {
options.coverageDirectory = path().resolve(options.rootDir, 'coverage');
}
setupBabelJest(options);
// TODO: Type this properly
const newOptions = {
..._Defaults.default
};
if (options.resolver) {
newOptions.resolver = (0, _utils.resolve)(null, {
filePath: options.resolver,
key: 'resolver',
rootDir: options.rootDir
});
}
validateExtensionsToTreatAsEsm(options.extensionsToTreatAsEsm);
if (options.watchman == null) {
options.watchman = _Defaults.default.watchman;
}
const optionKeys = Object.keys(options);
optionKeys.reduce((newOptions, key) => {
// The resolver has been resolved separately; skip it
if (key === 'resolver') {
return newOptions;
}
// This is cheating, because it claims that all keys of InitialOptions are Required.
// We only really know it's Required for oldOptions[key], not for oldOptions.someOtherKey,
// so oldOptions[key] is the only way it should be used.
const oldOptions = options;
let value;
switch (key) {
case 'setupFiles':
case 'setupFilesAfterEnv':
case 'snapshotSerializers':
{
const option = oldOptions[key];
value =
option &&
option.map(filePath =>
(0, _utils.resolve)(newOptions.resolver, {
filePath,
key,
rootDir: options.rootDir
})
);
}
break;
case 'modulePaths':
case 'roots':
{
const option = oldOptions[key];
value =
option &&
option.map(filePath =>
path().resolve(
options.rootDir,
(0, _utils.replaceRootDirInPath)(options.rootDir, filePath)
)
);
}
break;
case 'collectCoverageFrom':
value = normalizeCollectCoverageFrom(oldOptions, key);
break;
case 'cacheDirectory':
case 'coverageDirectory':
{
const option = oldOptions[key];
value =
option &&
path().resolve(
options.rootDir,
(0, _utils.replaceRootDirInPath)(options.rootDir, option)
);
}
break;
case 'dependencyExtractor':
case 'globalSetup':
case 'globalTeardown':
case 'runtime':
case 'snapshotResolver':
case 'testResultsProcessor':
case 'testRunner':
case 'filter':
{
const option = oldOptions[key];
value =
option &&
(0, _utils.resolve)(newOptions.resolver, {
filePath: option,
key,
rootDir: options.rootDir
});
}
break;
case 'runner':
{
const option = oldOptions[key];
value =
option &&
(0, _jestResolve().resolveRunner)(newOptions.resolver, {
filePath: option,
requireResolveFunction: require.resolve,
rootDir: options.rootDir
});
}
break;
case 'prettierPath':
{
// We only want this to throw if "prettierPath" is explicitly passed
// from config or CLI, and the requested path isn't found. Otherwise we
// set it to null and throw an error lazily when it is used.
const option = oldOptions[key];
value =
option &&
(0, _utils.resolve)(newOptions.resolver, {
filePath: option,
key,
optional: option === _Defaults.default[key],
rootDir: options.rootDir
});
}
break;
case 'moduleNameMapper':
const moduleNameMapper = oldOptions[key];
value =
moduleNameMapper &&
Object.keys(moduleNameMapper).map(regex => {
const item = moduleNameMapper && moduleNameMapper[regex];
return (
item && [
regex,
(0, _utils._replaceRootDirTags)(options.rootDir, item)
]
);
});
break;
case 'transform':
const transform = oldOptions[key];
value =
transform &&
Object.keys(transform).map(regex => {
const transformElement = transform[regex];
return [
regex,
(0, _utils.resolve)(newOptions.resolver, {
filePath: Array.isArray(transformElement)
? transformElement[0]
: transformElement,
key,
rootDir: options.rootDir
}),
Array.isArray(transformElement) ? transformElement[1] : {}
];
});
break;
case 'reporters':
value = normalizeReporters(oldOptions);
break;
case 'coveragePathIgnorePatterns':
case 'modulePathIgnorePatterns':
case 'testPathIgnorePatterns':
case 'transformIgnorePatterns':
case 'watchPathIgnorePatterns':
case 'unmockedModulePathPatterns':
value = normalizeUnmockedModulePathPatterns(oldOptions, key);
break;
case 'haste':
value = {
...oldOptions[key]
};
if (value.hasteImplModulePath != null) {
const resolvedHasteImpl = (0, _utils.resolve)(newOptions.resolver, {
filePath: (0, _utils.replaceRootDirInPath)(
options.rootDir,
value.hasteImplModulePath
),
key: 'haste.hasteImplModulePath',
rootDir: options.rootDir
});
value.hasteImplModulePath = resolvedHasteImpl || undefined;
}
break;
case 'projects':
value = (oldOptions[key] || [])
.map(project =>
typeof project === 'string'
? (0, _utils._replaceRootDirTags)(options.rootDir, project)
: project
)
.reduce((projects, project) => {
// Project can be specified as globs. If a glob matches any files,
// We expand it to these paths. If not, we keep the original path
// for the future resolution.
const globMatches =
typeof project === 'string' ? (0, _glob().sync)(project) : [];
return projects.concat(globMatches.length ? globMatches : project);
}, []);
break;
case 'moduleDirectories':
case 'testMatch':
{
const replacedRootDirTags = (0, _utils._replaceRootDirTags)(
(0, _utils.escapeGlobCharacters)(options.rootDir),
oldOptions[key]
);
if (replacedRootDirTags) {
value = Array.isArray(replacedRootDirTags)
? replacedRootDirTags.map(_jestUtil().replacePathSepForGlob)
: (0, _jestUtil().replacePathSepForGlob)(replacedRootDirTags);
} else {
value = replacedRootDirTags;
}
}
break;
case 'testRegex':
{
const option = oldOptions[key];
value = option
? (Array.isArray(option) ? option : [option]).map(
_jestRegexUtil().replacePathSepForRegex
)
: [];
}
break;
case 'moduleFileExtensions': {
value = oldOptions[key];
if (
Array.isArray(value) &&
// If it's the wrong type, it can throw at a later time
(options.runner === undefined ||
options.runner === _Defaults.default.runner) &&
// Only require 'js' for the default jest-runner
!value.includes('js')
) {
const errorMessage =
" moduleFileExtensions must include 'js':\n" +
' but instead received:\n' +
` ${_chalk().default.bold.red(JSON.stringify(value))}`;
// If `js` is not included, any dependency Jest itself injects into
// the environment, like jasmine or sourcemap-support, will need to
// `require` its modules with a file extension. This is not plausible
// in the long run, so it's way easier to just fail hard early.
// We might consider throwing if `json` is missing as well, as it's a
// fair assumption from modules that they can do
// `require('some-package/package') without the trailing `.json` as it
// works in Node normally.
throw createConfigError(
`${errorMessage}\n Please change your configuration to include 'js'.`
);
}
break;
}
case 'bail': {
const bail = oldOptions[key];
if (typeof bail === 'boolean') {
value = bail ? 1 : 0;
} else if (typeof bail === 'string') {
value = 1;
// If Jest is invoked as `jest --bail someTestPattern` then need to
// move the pattern from the `bail` configuration and into `argv._`
// to be processed as an extra parameter
argv._.push(bail);
} else {
value = oldOptions[key];
}
break;
}
case 'displayName': {
const displayName = oldOptions[key];
/**
* Ensuring that displayName shape is correct here so that the
* reporters can trust the shape of the data
*/
if (typeof displayName === 'object') {
const {name, color} = displayName;
if (
!name ||
!color ||
typeof name !== 'string' ||
typeof color !== 'string'
) {
const errorMessage =
` Option "${_chalk().default.bold(
'displayName'
)}" must be of type:\n\n` +
' {\n' +
' name: string;\n' +
' color: string;\n' +
' }\n';
throw createConfigError(errorMessage);
}
value = oldOptions[key];
} else {
value = {
color: (0, _color.getDisplayNameColor)(options.runner),
name: displayName
};
}
break;
}
case 'testTimeout': {
if (oldOptions[key] < 0) {
throw createConfigError(
` Option "${_chalk().default.bold(
'testTimeout'
)}" must be a natural number.`
);
}
value = oldOptions[key];
break;
}
case 'snapshotFormat': {
value = {
..._Defaults.default.snapshotFormat,
...oldOptions[key]
};
break;
}
case 'automock':
case 'cache':
case 'changedSince':
case 'changedFilesWithAncestor':
case 'clearMocks':
case 'collectCoverage':
case 'coverageProvider':
case 'coverageReporters':
case 'coverageThreshold':
case 'detectLeaks':
case 'detectOpenHandles':
case 'errorOnDeprecated':
case 'expand':
case 'extensionsToTreatAsEsm':
case 'globals':
case 'fakeTimers':
case 'findRelatedTests':
case 'forceCoverageMatch':
case 'forceExit':
case 'injectGlobals':
case 'lastCommit':
case 'listTests':
case 'logHeapUsage':
case 'maxConcurrency':
case 'id':
case 'noStackTrace':
case 'notify':
case 'notifyMode':
case 'onlyChanged':
case 'onlyFailures':
case 'openHandlesTimeout':
case 'outputFile':
case 'passWithNoTests':
case 'randomize':
case 'replname':
case 'resetMocks':
case 'resetModules':
case 'restoreMocks':
case 'rootDir':
case 'runTestsByPath':
case 'sandboxInjectedGlobals':
case 'silent':
case 'showSeed':
case 'skipFilter':
case 'skipNodeResolution':
case 'slowTestThreshold':
case 'testEnvironment':
case 'testEnvironmentOptions':
case 'testFailureExitCode':
case 'testLocationInResults':
case 'testNamePattern':
case 'useStderr':
case 'verbose':
case 'watch':
case 'watchAll':
case 'watchman':
case 'workerThreads':
value = oldOptions[key];
break;
case 'workerIdleMemoryLimit':
value = (0, _stringToBytes.default)(
oldOptions[key],
(0, _os().totalmem)()
);
break;
case 'watchPlugins':
value = (oldOptions[key] || []).map(watchPlugin => {
if (typeof watchPlugin === 'string') {
return {
config: {},
path: (0, _jestResolve().resolveWatchPlugin)(
newOptions.resolver,
{
filePath: watchPlugin,
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
)
};
} else {
return {
config: watchPlugin[1] || {},
path: (0, _jestResolve().resolveWatchPlugin)(
newOptions.resolver,
{
filePath: watchPlugin[0],
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
)
};
}
});
break;
}
// @ts-expect-error: automock is missing in GlobalConfig, so what
newOptions[key] = value;
return newOptions;
}, newOptions);
if (options.watchman && options.haste?.enableSymlinks) {
throw new (_jestValidate().ValidationError)(
'Validation Error',
'haste.enableSymlinks is incompatible with watchman',
'Either set haste.enableSymlinks to false or do not use watchman'
);
}
newOptions.roots.forEach((root, i) => {
verifyDirectoryExists(root, `roots[${i}]`);
});
try {
// try to resolve windows short paths, ignoring errors (permission errors, mostly)
newOptions.cwd = (0, _jestUtil().tryRealpath)(process.cwd());
} catch {
// ignored
}
newOptions.testSequencer = (0, _jestResolve().resolveSequencer)(
newOptions.resolver,
{
filePath:
options.testSequencer ||
require.resolve(_Defaults.default.testSequencer),
requireResolveFunction: require.resolve,
rootDir: options.rootDir
}
);
if (newOptions.runner === _Defaults.default.runner) {
newOptions.runner = require.resolve(newOptions.runner);
}
newOptions.nonFlagArgs = argv._?.map(arg => `${arg}`);
newOptions.testPathPattern = buildTestPathPattern(argv);
newOptions.json = !!argv.json;
newOptions.testFailureExitCode = parseInt(newOptions.testFailureExitCode, 10);
if (
newOptions.lastCommit ||
newOptions.changedFilesWithAncestor ||
newOptions.changedSince
) {
newOptions.onlyChanged = true;
}
if (argv.all) {
newOptions.onlyChanged = false;
newOptions.onlyFailures = false;
} else if (newOptions.testPathPattern) {
// When passing a test path pattern we don't want to only monitor changed
// files unless `--watch` is also passed.
newOptions.onlyChanged = newOptions.watch;
}
newOptions.randomize = newOptions.randomize || argv.randomize;
newOptions.showSeed =
newOptions.randomize || newOptions.showSeed || argv.showSeed;
const upperBoundSeedValue = 2 ** 31;
// bounds are determined by xoroshiro128plus which is used in v8 and is used here (at time of writing)
newOptions.seed =
argv.seed ??
Math.floor((2 ** 32 - 1) * Math.random() - upperBoundSeedValue);
if (
newOptions.seed < -upperBoundSeedValue ||
newOptions.seed > upperBoundSeedValue - 1
) {
throw new (_jestValidate().ValidationError)(
'Validation Error',
`seed value must be between \`-0x80000000\` and \`0x7fffffff\` inclusive - instead it is ${newOptions.seed}`
);
}
if (!newOptions.onlyChanged) {
newOptions.onlyChanged = false;
}
if (!newOptions.lastCommit) {
newOptions.lastCommit = false;
}
if (!newOptions.onlyFailures) {
newOptions.onlyFailures = false;
}
if (!newOptions.watchAll) {
newOptions.watchAll = false;
}
// as unknown since it can happen. We really need to fix the types here
if (newOptions.moduleNameMapper === _Defaults.default.moduleNameMapper) {
newOptions.moduleNameMapper = [];
}
if (argv.ci != null) {
newOptions.ci = argv.ci;
}
newOptions.updateSnapshot =
newOptions.ci && !argv.updateSnapshot
? 'none'
: argv.updateSnapshot
? 'all'
: 'new';
newOptions.maxConcurrency = parseInt(newOptions.maxConcurrency, 10);
newOptions.maxWorkers = (0, _getMaxWorkers.default)(argv, options);
if (newOptions.testRegex.length > 0 && options.testMatch) {
throw createConfigError(
` Configuration options ${_chalk().default.bold('testMatch')} and` +
` ${_chalk().default.bold('testRegex')} cannot be used together.`
);
}
if (newOptions.testRegex.length > 0 && !options.testMatch) {
// Prevent the default testMatch conflicting with any explicitly
// configured `testRegex` value
newOptions.testMatch = [];
}
// If argv.json is set, coverageReporters shouldn't print a text report.
if (argv.json) {
newOptions.coverageReporters = (newOptions.coverageReporters || []).filter(
reporter => reporter !== 'text'
);
}
// If collectCoverage is enabled while using --findRelatedTests we need to
// avoid having false negatives in the generated coverage report.
// The following: `--findRelatedTests '/rootDir/file1.js' --coverage`
// Is transformed to: `--findRelatedTests '/rootDir/file1.js' --coverage --collectCoverageFrom 'file1.js'`
// where arguments to `--collectCoverageFrom` should be globs (or relative
// paths to the rootDir)
if (newOptions.collectCoverage && argv.findRelatedTests) {
let collectCoverageFrom = newOptions.nonFlagArgs.map(filename => {
filename = (0, _utils.replaceRootDirInPath)(options.rootDir, filename);
return path().isAbsolute(filename)
? path().relative(options.rootDir, filename)
: filename;
});
// Don't override existing collectCoverageFrom options
if (newOptions.collectCoverageFrom) {
collectCoverageFrom = collectCoverageFrom.reduce((patterns, filename) => {
if (
(0, _micromatch().default)(
[
(0, _jestUtil().replacePathSepForGlob)(
path().relative(options.rootDir, filename)
)
],
newOptions.collectCoverageFrom
).length === 0
) {
return patterns;
}
return [...patterns, filename];
}, newOptions.collectCoverageFrom);
}
newOptions.collectCoverageFrom = collectCoverageFrom;
} else if (!newOptions.collectCoverageFrom) {
newOptions.collectCoverageFrom = [];
}
if (!newOptions.findRelatedTests) {
newOptions.findRelatedTests = false;
}
if (!newOptions.projects) {
newOptions.projects = [];
}
if (!newOptions.sandboxInjectedGlobals) {
newOptions.sandboxInjectedGlobals = [];
}
if (!newOptions.forceExit) {
newOptions.forceExit = false;
}
if (!newOptions.logHeapUsage) {
newOptions.logHeapUsage = false;
}
if (argv.shard) {
newOptions.shard = (0, _parseShardPair.parseShardPair)(argv.shard);
}
return {
hasDeprecationWarnings,
options: newOptions
};
}
@@ -0,0 +1,41 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.parseShardPair = void 0;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const parseShardPair = pair => {
const shardPair = pair
.split('/')
.filter(d => /^\d+$/.test(d))
.map(d => parseInt(d, 10))
.filter(shard => !Number.isNaN(shard));
const [shardIndex, shardCount] = shardPair;
if (shardPair.length !== 2) {
throw new Error(
'The shard option requires a string in the format of <n>/<m>.'
);
}
if (shardIndex === 0 || shardCount === 0) {
throw new Error(
'The shard option requires 1-based values, received 0 or lower in the pair.'
);
}
if (shardIndex > shardCount) {
throw new Error(
'The shard option <n>/<m> requires <n> to be lower or equal than <m>.'
);
}
return {
shardCount,
shardIndex
};
};
exports.parseShardPair = parseShardPair;
@@ -0,0 +1,195 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = readConfigFileAndSetRootDir;
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require('graceful-fs'));
fs = function () {
return data;
};
return data;
}
function _parseJson() {
const data = _interopRequireDefault(require('parse-json'));
_parseJson = function () {
return data;
};
return data;
}
function _stripJsonComments() {
const data = _interopRequireDefault(require('strip-json-comments'));
_stripJsonComments = function () {
return data;
};
return data;
}
function _jestUtil() {
const data = require('jest-util');
_jestUtil = function () {
return data;
};
return data;
}
var _constants = require('./constants');
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// Read the configuration and set its `rootDir`
// 1. If it's a `package.json` file, we look into its "jest" property
// 2. If it's a `jest.config.ts` file, we use `ts-node` to transpile & require it
// 3. For any other file, we just require it. If we receive an 'ERR_REQUIRE_ESM'
// from node, perform a dynamic import instead.
async function readConfigFileAndSetRootDir(configPath) {
const isTS = configPath.endsWith(_constants.JEST_CONFIG_EXT_TS);
const isJSON = configPath.endsWith(_constants.JEST_CONFIG_EXT_JSON);
let configObject;
try {
if (isTS) {
configObject = await loadTSConfigFile(configPath);
} else if (isJSON) {
const fileContent = fs().readFileSync(configPath, 'utf8');
configObject = (0, _parseJson().default)(
(0, _stripJsonComments().default)(fileContent),
configPath
);
} else {
configObject = await (0, _jestUtil().requireOrImportModule)(configPath);
}
} catch (error) {
if (isTS) {
throw new Error(
`Jest: Failed to parse the TypeScript config file ${configPath}\n` +
` ${error}`
);
}
throw error;
}
if (configPath.endsWith(_constants.PACKAGE_JSON)) {
// Event if there's no "jest" property in package.json we will still use
// an empty object.
configObject = configObject.jest || {};
}
if (typeof configObject === 'function') {
configObject = await configObject();
}
if (configObject.rootDir) {
// We don't touch it if it has an absolute path specified
if (!path().isAbsolute(configObject.rootDir)) {
// otherwise, we'll resolve it relative to the file's __dirname
configObject = {
...configObject,
rootDir: path().resolve(
path().dirname(configPath),
configObject.rootDir
)
};
}
} else {
// If rootDir is not there, we'll set it to this file's __dirname
configObject = {
...configObject,
rootDir: path().dirname(configPath)
};
}
return configObject;
}
// Load the TypeScript configuration
const loadTSConfigFile = async configPath => {
// Get registered TypeScript compiler instance
const registeredCompiler = await getRegisteredCompiler();
registeredCompiler.enabled(true);
let configObject = (0, _jestUtil().interopRequireDefault)(
require(configPath)
).default;
// In case the config is a function which imports more Typescript code
if (typeof configObject === 'function') {
configObject = await configObject();
}
registeredCompiler.enabled(false);
return configObject;
};
let registeredCompilerPromise;
function getRegisteredCompiler() {
// Cache the promise to avoid multiple registrations
registeredCompilerPromise = registeredCompilerPromise ?? registerTsNode();
return registeredCompilerPromise;
}
async function registerTsNode() {
try {
// Register TypeScript compiler instance
const tsNode = await import('ts-node');
return tsNode.register({
compilerOptions: {
module: 'CommonJS'
},
moduleTypes: {
'**': 'cjs'
}
});
} catch (e) {
if (e.code === 'ERR_MODULE_NOT_FOUND') {
throw new Error(
`Jest: 'ts-node' is required for the TypeScript configuration files. Make sure it is installed\nError: ${e.message}`
);
}
throw e;
}
}
@@ -0,0 +1,217 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = resolveConfigPath;
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function fs() {
const data = _interopRequireWildcard(require('graceful-fs'));
fs = function () {
return data;
};
return data;
}
function _slash() {
const data = _interopRequireDefault(require('slash'));
_slash = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
var _constants = require('./constants');
var _utils = require('./utils');
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const isFile = filePath =>
fs().existsSync(filePath) && !fs().lstatSync(filePath).isDirectory();
const getConfigFilename = ext => _constants.JEST_CONFIG_BASE_NAME + ext;
function resolveConfigPath(
pathToResolve,
cwd,
skipMultipleConfigError = false
) {
if (!path().isAbsolute(cwd)) {
throw new Error(`"cwd" must be an absolute path. cwd: ${cwd}`);
}
const absolutePath = path().isAbsolute(pathToResolve)
? pathToResolve
: path().resolve(cwd, pathToResolve);
if (isFile(absolutePath)) {
return absolutePath;
}
// This is a guard against passing non existing path as a project/config,
// that will otherwise result in a very confusing situation.
// e.g.
// With a directory structure like this:
// my_project/
// package.json
//
// Passing a `my_project/some_directory_that_doesnt_exist` as a project
// name will resolve into a (possibly empty) `my_project/package.json` and
// try to run all tests it finds under `my_project` directory.
if (!fs().existsSync(absolutePath)) {
throw new Error(
"Can't find a root directory while resolving a config file path.\n" +
`Provided path to resolve: ${pathToResolve}\n` +
`cwd: ${cwd}`
);
}
return resolveConfigPathByTraversing(
absolutePath,
pathToResolve,
cwd,
skipMultipleConfigError
);
}
const resolveConfigPathByTraversing = (
pathToResolve,
initialPath,
cwd,
skipMultipleConfigError
) => {
const configFiles = _constants.JEST_CONFIG_EXT_ORDER.map(ext =>
path().resolve(pathToResolve, getConfigFilename(ext))
).filter(isFile);
const packageJson = findPackageJson(pathToResolve);
if (packageJson && hasPackageJsonJestKey(packageJson)) {
configFiles.push(packageJson);
}
if (!skipMultipleConfigError && configFiles.length > 1) {
throw new (_jestValidate().ValidationError)(
...makeMultipleConfigsErrorMessage(configFiles)
);
}
if (configFiles.length > 0 || packageJson) {
return configFiles[0] ?? packageJson;
}
// This is the system root.
// We tried everything, config is nowhere to be found ¯\_(ツ)_/¯
if (pathToResolve === path().dirname(pathToResolve)) {
throw new Error(makeResolutionErrorMessage(initialPath, cwd));
}
// go up a level and try it again
return resolveConfigPathByTraversing(
path().dirname(pathToResolve),
initialPath,
cwd,
skipMultipleConfigError
);
};
const findPackageJson = pathToResolve => {
const packagePath = path().resolve(pathToResolve, _constants.PACKAGE_JSON);
if (isFile(packagePath)) {
return packagePath;
}
return undefined;
};
const hasPackageJsonJestKey = packagePath => {
const content = fs().readFileSync(packagePath, 'utf8');
try {
return 'jest' in JSON.parse(content);
} catch {
// If package is not a valid JSON
return false;
}
};
const makeResolutionErrorMessage = (initialPath, cwd) =>
'Could not find a config file based on provided values:\n' +
`path: "${initialPath}"\n` +
`cwd: "${cwd}"\n` +
'Config paths must be specified by either a direct path to a config\n' +
'file, or a path to a directory. If directory is given, Jest will try to\n' +
`traverse directory tree up, until it finds one of those files in exact order: ${_constants.JEST_CONFIG_EXT_ORDER.map(
ext => `"${getConfigFilename(ext)}"`
).join(' or ')}.`;
function extraIfPackageJson(configPath) {
if (configPath.endsWith(_constants.PACKAGE_JSON)) {
return '`jest` key in ';
}
return '';
}
const makeMultipleConfigsErrorMessage = configPaths => [
`${_utils.BULLET}${_chalk().default.bold('Multiple configurations found')}`,
[
...configPaths.map(
configPath =>
` * ${extraIfPackageJson(configPath)}${(0, _slash().default)(
configPath
)}`
),
'',
' Implicit config resolution does not allow multiple configuration files.',
' Either remove unused config files or select one explicitly with `--config`.'
].join('\n'),
_utils.DOCUMENTATION_NOTE
];
@@ -0,0 +1,58 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = setFromArgv;
var _utils = require('./utils');
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const specialArgs = ['_', '$0', 'h', 'help', 'config'];
function setFromArgv(options, argv) {
const argvToOptions = Object.keys(argv).reduce((options, key) => {
if (argv[key] === undefined || specialArgs.includes(key)) {
return options;
}
switch (key) {
case 'coverage':
options.collectCoverage = argv[key];
break;
case 'json':
options.useStderr = argv[key];
break;
case 'watchAll':
options.watch = false;
options.watchAll = argv[key];
break;
case 'env':
options.testEnvironment = argv[key];
break;
case 'config':
break;
case 'coverageThreshold':
case 'globals':
case 'haste':
case 'moduleNameMapper':
case 'testEnvironmentOptions':
case 'transform':
const str = argv[key];
if ((0, _utils.isJSONString)(str)) {
options[key] = JSON.parse(str);
}
break;
default:
options[key] = argv[key];
}
return options;
}, {});
return {
...options,
...((0, _utils.isJSONString)(argv.config) ? JSON.parse(argv.config) : null),
...argvToOptions
};
}
@@ -0,0 +1,79 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = void 0;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Converts a string representing an amount of memory to bytes.
*
* @param input The value to convert to bytes.
* @param percentageReference The reference value to use when a '%' value is supplied.
*/
function stringToBytes(input, percentageReference) {
if (input === null || input === undefined) {
return input;
}
if (typeof input === 'string') {
if (isNaN(Number.parseFloat(input.slice(-1)))) {
// eslint-disable-next-line prefer-const
let [, numericString, trailingChars] =
input.match(/(.*?)([^0-9.-]+)$/i) || [];
if (trailingChars && numericString) {
const numericValue = Number.parseFloat(numericString);
trailingChars = trailingChars.toLowerCase();
switch (trailingChars) {
case '%':
input = numericValue / 100;
break;
case 'kb':
case 'k':
return numericValue * 1000;
case 'kib':
return numericValue * 1024;
case 'mb':
case 'm':
return numericValue * 1000 * 1000;
case 'mib':
return numericValue * 1024 * 1024;
case 'gb':
case 'g':
return numericValue * 1000 * 1000 * 1000;
case 'gib':
return numericValue * 1024 * 1024 * 1024;
}
}
// It ends in some kind of char so we need to do some parsing
} else {
input = Number.parseFloat(input);
}
}
if (typeof input === 'number') {
if (input <= 1 && input > 0) {
if (percentageReference) {
return Math.floor(input * percentageReference);
} else {
throw new Error(
'For a percentage based memory limit a percentageReference must be supplied'
);
}
} else if (input > 1) {
return Math.floor(input);
} else {
throw new Error('Unexpected numerical input');
}
}
throw new Error('Unexpected input');
}
// https://github.com/import-js/eslint-plugin-import/issues/1590
var _default = stringToBytes;
exports.default = _default;
+172
View File
@@ -0,0 +1,172 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.resolve =
exports.replaceRootDirInPath =
exports.isJSONString =
exports.escapeGlobCharacters =
exports._replaceRootDirTags =
exports.DOCUMENTATION_NOTE =
exports.BULLET =
void 0;
function path() {
const data = _interopRequireWildcard(require('path'));
path = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require('chalk'));
_chalk = function () {
return data;
};
return data;
}
function _jestResolve() {
const data = _interopRequireDefault(require('jest-resolve'));
_jestResolve = function () {
return data;
};
return data;
}
function _jestValidate() {
const data = require('jest-validate');
_jestValidate = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {default: obj};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== 'function') return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function (nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
return {default: obj};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor =
Object.defineProperty && Object.getOwnPropertyDescriptor;
for (var key in obj) {
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor
? Object.getOwnPropertyDescriptor(obj, key)
: null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const BULLET = _chalk().default.bold('\u25cf ');
exports.BULLET = BULLET;
const DOCUMENTATION_NOTE = ` ${_chalk().default.bold(
'Configuration Documentation:'
)}
https://jestjs.io/docs/configuration
`;
exports.DOCUMENTATION_NOTE = DOCUMENTATION_NOTE;
const createValidationError = message =>
new (_jestValidate().ValidationError)(
`${BULLET}Validation Error`,
message,
DOCUMENTATION_NOTE
);
const resolve = (resolver, {key, filePath, rootDir, optional}) => {
const module = _jestResolve().default.findNodeModule(
replaceRootDirInPath(rootDir, filePath),
{
basedir: rootDir,
resolver: resolver || undefined
}
);
if (!module && !optional) {
throw createValidationError(` Module ${_chalk().default.bold(
filePath
)} in the ${_chalk().default.bold(key)} option was not found.
${_chalk().default.bold('<rootDir>')} is: ${rootDir}`);
}
/// can cast as string since nulls will be thrown
return module;
};
exports.resolve = resolve;
const escapeGlobCharacters = path => path.replace(/([()*{}[\]!?\\])/g, '\\$1');
exports.escapeGlobCharacters = escapeGlobCharacters;
const replaceRootDirInPath = (rootDir, filePath) => {
if (!/^<rootDir>/.test(filePath)) {
return filePath;
}
return path().resolve(
rootDir,
path().normalize(`./${filePath.substring('<rootDir>'.length)}`)
);
};
exports.replaceRootDirInPath = replaceRootDirInPath;
const _replaceRootDirInObject = (rootDir, config) => {
const newConfig = {};
for (const configKey in config) {
newConfig[configKey] =
configKey === 'rootDir'
? config[configKey]
: _replaceRootDirTags(rootDir, config[configKey]);
}
return newConfig;
};
const _replaceRootDirTags = (rootDir, config) => {
if (config == null) {
return config;
}
switch (typeof config) {
case 'object':
if (Array.isArray(config)) {
/// can be string[] or {}[]
return config.map(item => _replaceRootDirTags(rootDir, item));
}
if (config instanceof RegExp) {
return config;
}
return _replaceRootDirInObject(rootDir, config);
case 'string':
return replaceRootDirInPath(rootDir, config);
}
return config;
};
exports._replaceRootDirTags = _replaceRootDirTags;
// newtype
const isJSONString = text =>
text != null &&
typeof text === 'string' &&
text.startsWith('{') &&
text.endsWith('}');
exports.isJSONString = isJSONString;
@@ -0,0 +1,24 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = validatePattern;
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
function validatePattern(pattern) {
if (pattern) {
try {
// eslint-disable-next-line no-new
new RegExp(pattern, 'i');
} catch {
return false;
}
}
return true;
}
+71
View File
@@ -0,0 +1,71 @@
{
"name": "jest-config",
"version": "29.7.0",
"repository": {
"type": "git",
"url": "https://github.com/jestjs/jest.git",
"directory": "packages/jest-config"
},
"license": "MIT",
"main": "./build/index.js",
"types": "./build/index.d.ts",
"exports": {
".": {
"types": "./build/index.d.ts",
"default": "./build/index.js"
},
"./package.json": "./package.json"
},
"peerDependencies": {
"@types/node": "*",
"ts-node": ">=9.0.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"ts-node": {
"optional": true
}
},
"dependencies": {
"@babel/core": "^7.11.6",
"@jest/test-sequencer": "^29.7.0",
"@jest/types": "^29.6.3",
"babel-jest": "^29.7.0",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
"deepmerge": "^4.2.2",
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
"jest-circus": "^29.7.0",
"jest-environment-node": "^29.7.0",
"jest-get-type": "^29.6.3",
"jest-regex-util": "^29.6.3",
"jest-resolve": "^29.7.0",
"jest-runner": "^29.7.0",
"jest-util": "^29.7.0",
"jest-validate": "^29.7.0",
"micromatch": "^4.0.4",
"parse-json": "^5.2.0",
"pretty-format": "^29.7.0",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
"devDependencies": {
"@types/glob": "^7.1.1",
"@types/graceful-fs": "^4.1.3",
"@types/micromatch": "^4.0.1",
"@types/parse-json": "^4.0.0",
"semver": "^7.5.3",
"ts-node": "^10.5.0",
"typescript": "^5.0.4"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
},
"publishConfig": {
"access": "public"
},
"gitHead": "4e56991693da7cd4c3730dc3579a1dd1403ee630"
}