PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/metro-file-map/src/plugins
Просмотр файла: MockPlugin.js.flow
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {
FileMapDelta,
FileMapPlugin,
FileMapPluginInitOptions,
MockMap as IMockMap,
Path,
RawMockMap,
} from '../flow-types';
import normalizePathSeparatorsToPosix from '../lib/normalizePathSeparatorsToPosix';
import normalizePathSeparatorsToSystem from '../lib/normalizePathSeparatorsToSystem';
import {RootPathUtils} from '../lib/RootPathUtils';
import getMockName from './mocks/getMockName';
import nullthrows from 'nullthrows';
import path from 'path';
export const CACHE_VERSION = 2;
export default class MockPlugin implements FileMapPlugin<RawMockMap>, IMockMap {
+name = 'mocks';
+#mocksPattern: RegExp;
#raw: RawMockMap;
+#rootDir: Path;
+#pathUtils: RootPathUtils;
+#console: typeof console;
#throwOnModuleCollision: boolean;
constructor({
console,
mocksPattern,
rawMockMap = {
mocks: new Map(),
duplicates: new Map(),
version: CACHE_VERSION,
},
rootDir,
throwOnModuleCollision,
}: $ReadOnly<{
console: typeof console,
mocksPattern: RegExp,
rawMockMap?: RawMockMap,
rootDir: Path,
throwOnModuleCollision: boolean,
}>) {
this.#mocksPattern = mocksPattern;
if (rawMockMap.version !== CACHE_VERSION) {
throw new Error('Incompatible state passed to MockPlugin');
}
this.#raw = rawMockMap;
this.#rootDir = rootDir;
this.#console = console;
this.#pathUtils = new RootPathUtils(rootDir);
this.#throwOnModuleCollision = throwOnModuleCollision;
}
async initialize({
files,
pluginState,
}: FileMapPluginInitOptions<RawMockMap>): Promise<void> {
if (pluginState != null && pluginState.version === this.#raw.version) {
// Use cached state directly if available
this.#raw = pluginState;
} else {
// Otherwise, traverse all files to rebuild
await this.bulkUpdate({
addedOrModified: [
...files.metadataIterator({
includeNodeModules: false,
includeSymlinks: false,
}),
].map(({canonicalPath, metadata}) => [canonicalPath, metadata]),
removed: [],
});
}
}
getMockModule(name: string): ?Path {
const mockPosixRelativePath =
this.#raw.mocks.get(name) || this.#raw.mocks.get(name + '/index');
if (typeof mockPosixRelativePath !== 'string') {
return null;
}
return this.#pathUtils.normalToAbsolute(
normalizePathSeparatorsToSystem(mockPosixRelativePath),
);
}
async bulkUpdate(delta: FileMapDelta): Promise<void> {
// Process removals first so that moves aren't treated as duplicates.
for (const [relativeFilePath] of delta.removed) {
this.onRemovedFile(relativeFilePath);
}
for (const [relativeFilePath] of delta.addedOrModified) {
this.onNewOrModifiedFile(relativeFilePath);
}
}
onNewOrModifiedFile(relativeFilePath: Path): void {
const absoluteFilePath = this.#pathUtils.normalToAbsolute(relativeFilePath);
if (!this.#mocksPattern.test(absoluteFilePath)) {
return;
}
const mockName = getMockName(absoluteFilePath);
const posixRelativePath = normalizePathSeparatorsToPosix(relativeFilePath);
const existingMockPosixPath = this.#raw.mocks.get(mockName);
if (existingMockPosixPath != null) {
if (existingMockPosixPath !== posixRelativePath) {
let duplicates = this.#raw.duplicates.get(mockName);
if (duplicates == null) {
duplicates = new Set([existingMockPosixPath, posixRelativePath]);
this.#raw.duplicates.set(mockName, duplicates);
} else {
duplicates.add(posixRelativePath);
}
this.#console.warn(this.#getMessageForDuplicates(mockName, duplicates));
}
}
// If there are duplicates and we don't throw, the latest mock wins.
// This is to preserve backwards compatibility, but it's unpredictable.
this.#raw.mocks.set(mockName, posixRelativePath);
}
onRemovedFile(relativeFilePath: Path): void {
const absoluteFilePath = this.#pathUtils.normalToAbsolute(relativeFilePath);
if (!this.#mocksPattern.test(absoluteFilePath)) {
return;
}
const mockName = getMockName(absoluteFilePath);
const duplicates = this.#raw.duplicates.get(mockName);
if (duplicates != null) {
const posixRelativePath =
normalizePathSeparatorsToPosix(relativeFilePath);
duplicates.delete(posixRelativePath);
if (duplicates.size === 1) {
this.#raw.duplicates.delete(mockName);
}
// Set the mock to a remaining duplicate. Should never be empty.
const remaining = nullthrows(duplicates.values().next().value);
this.#raw.mocks.set(mockName, remaining);
} else {
this.#raw.mocks.delete(mockName);
}
}
getSerializableSnapshot(): RawMockMap {
return {
mocks: new Map(this.#raw.mocks),
duplicates: new Map(
[...this.#raw.duplicates].map(([k, v]) => [k, new Set(v)]),
),
version: this.#raw.version,
};
}
assertValid(): void {
if (!this.#throwOnModuleCollision) {
return;
}
// Throw an aggregate error for each duplicate.
const errors = [];
for (const [mockName, relativePosixPaths] of this.#raw.duplicates) {
errors.push(this.#getMessageForDuplicates(mockName, relativePosixPaths));
}
if (errors.length > 0) {
throw new Error(
`Mock map has ${errors.length} error${errors.length > 1 ? 's' : ''}:\n${errors.join('\n')}`,
);
}
}
#getMessageForDuplicates(
mockName: string,
relativePosixPaths: $ReadOnlySet<string>,
): string {
return (
'Duplicate manual mock found for `' +
mockName +
'`:\n' +
[...relativePosixPaths]
.map(
relativePosixPath =>
' * <rootDir>' +
path.sep +
this.#pathUtils.absoluteToNormal(
normalizePathSeparatorsToSystem(relativePosixPath),
) +
'\n',
)
.join('')
);
}
getCacheKey(): string {
return (
this.#mocksPattern.source.replaceAll('\\\\', '\\/') +
',' +
this.#mocksPattern.flags
);
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!