fix(misc): ensure plugins are not creating workspace context while creating nodes (#26253)
This commit is contained in:
parent
a308e1dc6b
commit
6f223005b8
@ -129,6 +129,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [getProjects](../../devkit/documents/getProjects)
|
- [getProjects](../../devkit/documents/getProjects)
|
||||||
- [getWorkspaceLayout](../../devkit/documents/getWorkspaceLayout)
|
- [getWorkspaceLayout](../../devkit/documents/getWorkspaceLayout)
|
||||||
- [glob](../../devkit/documents/glob)
|
- [glob](../../devkit/documents/glob)
|
||||||
|
- [globAsync](../../devkit/documents/globAsync)
|
||||||
- [hashArray](../../devkit/documents/hashArray)
|
- [hashArray](../../devkit/documents/hashArray)
|
||||||
- [installPackagesTask](../../devkit/documents/installPackagesTask)
|
- [installPackagesTask](../../devkit/documents/installPackagesTask)
|
||||||
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
|
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
|
||||||
|
|||||||
@ -18,3 +18,7 @@ Paths should be unix-style with forward slashes.
|
|||||||
`string`[]
|
`string`[]
|
||||||
|
|
||||||
Normalized paths in the workspace that match the provided glob patterns.
|
Normalized paths in the workspace that match the provided glob patterns.
|
||||||
|
|
||||||
|
**`Deprecated`**
|
||||||
|
|
||||||
|
Use [globAsync](../../devkit/documents/globAsync) instead.
|
||||||
|
|||||||
20
docs/generated/devkit/globAsync.md
Normal file
20
docs/generated/devkit/globAsync.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Function: globAsync
|
||||||
|
|
||||||
|
▸ **globAsync**(`tree`, `patterns`): `Promise`\<`string`[]\>
|
||||||
|
|
||||||
|
Performs a tree-aware glob search on the files in a workspace. Able to find newly
|
||||||
|
created files and hides deleted files before the updates are committed to disk.
|
||||||
|
Paths should be unix-style with forward slashes.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| :--------- | :------------------------------------ | :---------------------- |
|
||||||
|
| `tree` | [`Tree`](../../devkit/documents/Tree) | The file system tree |
|
||||||
|
| `patterns` | `string`[] | A list of glob patterns |
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
`Promise`\<`string`[]\>
|
||||||
|
|
||||||
|
Normalized paths in the workspace that match the provided glob patterns.
|
||||||
@ -129,6 +129,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [getProjects](../../devkit/documents/getProjects)
|
- [getProjects](../../devkit/documents/getProjects)
|
||||||
- [getWorkspaceLayout](../../devkit/documents/getWorkspaceLayout)
|
- [getWorkspaceLayout](../../devkit/documents/getWorkspaceLayout)
|
||||||
- [glob](../../devkit/documents/glob)
|
- [glob](../../devkit/documents/glob)
|
||||||
|
- [globAsync](../../devkit/documents/globAsync)
|
||||||
- [hashArray](../../devkit/documents/hashArray)
|
- [hashArray](../../devkit/documents/hashArray)
|
||||||
- [installPackagesTask](../../devkit/documents/installPackagesTask)
|
- [installPackagesTask](../../devkit/documents/installPackagesTask)
|
||||||
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
|
- [isWorkspacesEnabled](../../devkit/documents/isWorkspacesEnabled)
|
||||||
|
|||||||
@ -12,4 +12,5 @@ module.exports = {
|
|||||||
coverageReporters: ['html'],
|
coverageReporters: ['html'],
|
||||||
maxWorkers: 1,
|
maxWorkers: 1,
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
|
setupFiles: ['../../scripts/unit-test-setup.js'],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -75,6 +75,11 @@ describe('Cypress builder', () => {
|
|||||||
configuration,
|
configuration,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
(devkit as any).logger = {
|
||||||
|
warn: jest.fn(),
|
||||||
|
log: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
};
|
||||||
cypressRun = jest
|
cypressRun = jest
|
||||||
.spyOn(Cypress, 'run')
|
.spyOn(Cypress, 'run')
|
||||||
.mockReturnValue(Promise.resolve({}));
|
.mockReturnValue(Promise.resolve({}));
|
||||||
|
|||||||
@ -19,12 +19,13 @@ import { getLockFileName } from '@nx/js';
|
|||||||
|
|
||||||
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
||||||
import { existsSync, readdirSync } from 'fs';
|
import { existsSync, readdirSync } from 'fs';
|
||||||
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
|
||||||
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
||||||
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
||||||
import { NX_PLUGIN_OPTIONS } from '../utils/constants';
|
import { NX_PLUGIN_OPTIONS } from '../utils/constants';
|
||||||
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
||||||
import { hashObject } from 'nx/src/devkit-internals';
|
import { hashObject } from 'nx/src/devkit-internals';
|
||||||
|
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||||
|
|
||||||
export interface CypressPluginOptions {
|
export interface CypressPluginOptions {
|
||||||
ciTargetName?: string;
|
ciTargetName?: string;
|
||||||
@ -98,9 +99,12 @@ async function createNodesInternal(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildCypressTargets(
|
targetsCache[hash] ??= await buildCypressTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
@ -237,7 +241,7 @@ async function buildCypressTargets(
|
|||||||
: Array.isArray(cypressConfig.e2e.excludeSpecPattern)
|
: Array.isArray(cypressConfig.e2e.excludeSpecPattern)
|
||||||
? cypressConfig.e2e.excludeSpecPattern.map((p) => join(projectRoot, p))
|
? cypressConfig.e2e.excludeSpecPattern.map((p) => join(projectRoot, p))
|
||||||
: [join(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
|
: [join(projectRoot, cypressConfig.e2e.excludeSpecPattern)];
|
||||||
const specFiles = globWithWorkspaceContext(
|
const specFiles = await globWithWorkspaceContext(
|
||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
specPatterns,
|
specPatterns,
|
||||||
excludeSpecPatterns
|
excludeSpecPatterns
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export const createDependencies: CreateDependencies = () => {
|
|||||||
|
|
||||||
export const createNodes: CreateNodes<DetoxPluginOptions> = [
|
export const createNodes: CreateNodes<DetoxPluginOptions> = [
|
||||||
'**/{detox.config,.detoxrc}.{json,js}',
|
'**/{detox.config,.detoxrc}.{json,js}',
|
||||||
(configFilePath, options, context) => {
|
async (configFilePath, options, context) => {
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
const projectRoot = dirname(configFilePath);
|
const projectRoot = dirname(configFilePath);
|
||||||
|
|
||||||
@ -52,9 +52,12 @@ export const createNodes: CreateNodes<DetoxPluginOptions> = [
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= buildDetoxTargets(projectRoot, options, context);
|
targetsCache[hash] ??= buildDetoxTargets(projectRoot, options, context);
|
||||||
|
|
||||||
|
|||||||
@ -3,14 +3,14 @@ import { CreateNodesContext, hashArray } from 'nx/src/devkit-exports';
|
|||||||
|
|
||||||
import { hashObject, hashWithWorkspaceContext } from 'nx/src/devkit-internals';
|
import { hashObject, hashWithWorkspaceContext } from 'nx/src/devkit-internals';
|
||||||
|
|
||||||
export function calculateHashForCreateNodes(
|
export async function calculateHashForCreateNodes(
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
options: object,
|
options: object,
|
||||||
context: CreateNodesContext,
|
context: CreateNodesContext,
|
||||||
additionalGlobs: string[] = []
|
additionalGlobs: string[] = []
|
||||||
): string {
|
): Promise<string> {
|
||||||
return hashArray([
|
return hashArray([
|
||||||
hashWithWorkspaceContext(context.workspaceRoot, [
|
await hashWithWorkspaceContext(context.workspaceRoot, [
|
||||||
join(projectRoot, '**/*'),
|
join(projectRoot, '**/*'),
|
||||||
...additionalGlobs,
|
...additionalGlobs,
|
||||||
]),
|
]),
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
|
|||||||
import { WORKSPACE_PLUGIN_DIR } from '../../constants';
|
import { WORKSPACE_PLUGIN_DIR } from '../../constants';
|
||||||
import update from './rename-workspace-rules';
|
import update from './rename-workspace-rules';
|
||||||
|
|
||||||
|
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||||
|
|
||||||
const rule1Name = 'test-rule';
|
const rule1Name = 'test-rule';
|
||||||
const rule2Name = 'my-rule';
|
const rule2Name = 'my-rule';
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'nx/src/internal-testing-utils/mock-project-graph';
|
|||||||
import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nx/devkit';
|
import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { LinterInitOptions, lintInitGenerator } from './init';
|
import { LinterInitOptions, lintInitGenerator } from './init';
|
||||||
|
import { setWorkspaceRoot } from 'nx/src/utils/workspace-root';
|
||||||
|
|
||||||
describe('@nx/eslint:init', () => {
|
describe('@nx/eslint:init', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -10,6 +11,7 @@ describe('@nx/eslint:init', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
setWorkspaceRoot(tree.root);
|
||||||
options = {
|
options = {
|
||||||
addPlugin: true,
|
addPlugin: true,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export const createNodes: CreateNodes<EslintPluginOptions> = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectFiles = globWithWorkspaceContext(
|
const projectFiles = await globWithWorkspaceContext(
|
||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
[
|
[
|
||||||
'project.json',
|
'project.json',
|
||||||
@ -77,7 +77,7 @@ export const createNodes: CreateNodes<EslintPluginOptions> = [
|
|||||||
const nestedProjectRootPatterns = excludePatterns.slice(index + 1);
|
const nestedProjectRootPatterns = excludePatterns.slice(index + 1);
|
||||||
|
|
||||||
// Ignore project roots where the project does not contain any lintable files
|
// Ignore project roots where the project does not contain any lintable files
|
||||||
const lintableFiles = globWithWorkspaceContext(
|
const lintableFiles = await globWithWorkspaceContext(
|
||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
[join(childProjectRoot, `**/*.{${options.extensions.join(',')}}`)],
|
[join(childProjectRoot, `**/*.{${options.extensions.join(',')}}`)],
|
||||||
// exclude nested eslint roots and nested project roots
|
// exclude nested eslint roots and nested project roots
|
||||||
|
|||||||
@ -72,9 +72,12 @@ export const createNodes: CreateNodes<ExpoPluginOptions> = [
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= buildExpoTargets(projectRoot, options, context);
|
targetsCache[hash] ??= buildExpoTargets(projectRoot, options, context);
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ export const createNodesV2: CreateNodesV2<GradlePluginOptions> = [
|
|||||||
);
|
);
|
||||||
const targetsCache = readTargetsCache(cachePath);
|
const targetsCache = readTargetsCache(cachePath);
|
||||||
|
|
||||||
populateGradleReport(context.workspaceRoot);
|
await populateGradleReport(context.workspaceRoot);
|
||||||
const gradleReport = getCurrentGradleReport();
|
const gradleReport = getCurrentGradleReport();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -93,14 +93,14 @@ export const makeCreateNodes =
|
|||||||
gradleReport: GradleReport,
|
gradleReport: GradleReport,
|
||||||
targetsCache: GradleTargets
|
targetsCache: GradleTargets
|
||||||
): CreateNodesFunction =>
|
): CreateNodesFunction =>
|
||||||
(
|
async (
|
||||||
gradleFilePath,
|
gradleFilePath,
|
||||||
options: GradlePluginOptions | undefined,
|
options: GradlePluginOptions | undefined,
|
||||||
context: CreateNodesContext
|
context: CreateNodesContext
|
||||||
) => {
|
) => {
|
||||||
const projectRoot = dirname(gradleFilePath);
|
const projectRoot = dirname(gradleFilePath);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(
|
const hash = await calculateHashForCreateNodes(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
options ?? {},
|
options ?? {},
|
||||||
context
|
context
|
||||||
@ -128,14 +128,14 @@ export const makeCreateNodes =
|
|||||||
*/
|
*/
|
||||||
export const createNodes: CreateNodes<GradlePluginOptions> = [
|
export const createNodes: CreateNodes<GradlePluginOptions> = [
|
||||||
gradleConfigGlob,
|
gradleConfigGlob,
|
||||||
(configFile, options, context) => {
|
async (configFile, options, context) => {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||||
);
|
);
|
||||||
populateGradleReport(context.workspaceRoot);
|
await populateGradleReport(context.workspaceRoot);
|
||||||
const gradleReport = getCurrentGradleReport();
|
const gradleReport = getCurrentGradleReport();
|
||||||
const internalCreateNodes = makeCreateNodes(gradleReport, {});
|
const internalCreateNodes = makeCreateNodes(gradleReport, {});
|
||||||
return internalCreateNodes(configFile, options, context);
|
return await internalCreateNodes(configFile, options, context);
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -36,8 +36,10 @@ export function getCurrentGradleReport() {
|
|||||||
return gradleReportCache;
|
return gradleReportCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function populateGradleReport(workspaceRoot: string): void {
|
export async function populateGradleReport(
|
||||||
const gradleConfigHash = hashWithWorkspaceContext(workspaceRoot, [
|
workspaceRoot: string
|
||||||
|
): Promise<void> {
|
||||||
|
const gradleConfigHash = await hashWithWorkspaceContext(workspaceRoot, [
|
||||||
gradleConfigGlob,
|
gradleConfigGlob,
|
||||||
]);
|
]);
|
||||||
if (gradleReportCache && gradleConfigHash === gradleCurrentConfigHash) {
|
if (gradleReportCache && gradleConfigHash === gradleCurrentConfigHash) {
|
||||||
|
|||||||
@ -127,7 +127,7 @@ async function createNodesInternal(
|
|||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context);
|
const hash = await calculateHashForCreateNodes(projectRoot, options, context);
|
||||||
targetsCache[hash] ??= await buildJestTargets(
|
targetsCache[hash] ??= await buildJestTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export const PLUGIN_NAME = '@nx/js/typescript';
|
|||||||
|
|
||||||
export const createNodes: CreateNodes<TscPluginOptions> = [
|
export const createNodes: CreateNodes<TscPluginOptions> = [
|
||||||
'**/tsconfig*.json',
|
'**/tsconfig*.json',
|
||||||
(configFilePath, options, context) => {
|
async (configFilePath, options, context) => {
|
||||||
const pluginOptions = normalizePluginOptions(options);
|
const pluginOptions = normalizePluginOptions(options);
|
||||||
const projectRoot = dirname(configFilePath);
|
const projectRoot = dirname(configFilePath);
|
||||||
const fullConfigPath = joinPathFragments(
|
const fullConfigPath = joinPathFragments(
|
||||||
@ -101,7 +101,7 @@ export const createNodes: CreateNodes<TscPluginOptions> = [
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeHash = calculateHashForCreateNodes(
|
const nodeHash = await calculateHashForCreateNodes(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
pluginOptions,
|
pluginOptions,
|
||||||
context,
|
context,
|
||||||
|
|||||||
@ -7,4 +7,5 @@ export default {
|
|||||||
globals: {},
|
globals: {},
|
||||||
displayName: 'nest',
|
displayName: 'nest',
|
||||||
preset: '../../jest.preset.js',
|
preset: '../../jest.preset.js',
|
||||||
|
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
|
||||||
};
|
};
|
||||||
|
|||||||
12
packages/nest/test-setup.ts
Normal file
12
packages/nest/test-setup.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// If a test uses a util from devkit, but that util
|
||||||
|
// lives in the Nx package and creates the project graph,
|
||||||
|
// we need to mock the resolved value inside the Nx package
|
||||||
|
jest
|
||||||
|
.spyOn(
|
||||||
|
require('nx/src/project-graph/project-graph'),
|
||||||
|
'createProjectGraphAsync'
|
||||||
|
)
|
||||||
|
.mockResolvedValue({
|
||||||
|
nodes: {},
|
||||||
|
dependencies: {},
|
||||||
|
});
|
||||||
@ -11,7 +11,8 @@
|
|||||||
"**/*.test.ts",
|
"**/*.test.ts",
|
||||||
"**/*_spec.ts",
|
"**/*_spec.ts",
|
||||||
"**/*_test.ts",
|
"**/*_test.ts",
|
||||||
"jest.config.ts"
|
"jest.config.ts",
|
||||||
|
"test-setup.ts"
|
||||||
],
|
],
|
||||||
"include": ["**/*.ts"]
|
"include": ["**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
"**/*.spec.jsx",
|
"**/*.spec.jsx",
|
||||||
"**/*.test.jsx",
|
"**/*.test.jsx",
|
||||||
"**/*.d.ts",
|
"**/*.d.ts",
|
||||||
"jest.config.ts"
|
"jest.config.ts",
|
||||||
|
"test-setup.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,9 +63,12 @@ export const createNodes: CreateNodes<NextPluginOptions> = [
|
|||||||
}
|
}
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildNextTargets(
|
targetsCache[hash] ??= await buildNextTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
|
|||||||
@ -62,9 +62,12 @@ export const createNodes: CreateNodes<NuxtPluginOptions> = [
|
|||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
targetsCache[hash] ??= await buildNuxtTargets(
|
targetsCache[hash] ??= await buildNuxtTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
|||||||
@ -5,6 +5,14 @@ import {
|
|||||||
import { createTreeWithEmptyWorkspace } from '../generators/testing-utils/create-tree-with-empty-workspace';
|
import { createTreeWithEmptyWorkspace } from '../generators/testing-utils/create-tree-with-empty-workspace';
|
||||||
import { addProjectConfiguration } from '../generators/utils/project-configuration';
|
import { addProjectConfiguration } from '../generators/utils/project-configuration';
|
||||||
|
|
||||||
|
jest.mock('../project-graph/project-graph', () => ({
|
||||||
|
...jest.requireActual('../project-graph/project-graph'),
|
||||||
|
createProjectGraphAsync: () => ({
|
||||||
|
nodes: {},
|
||||||
|
externalNodes: {},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('ngcli-adapter', () => {
|
describe('ngcli-adapter', () => {
|
||||||
it('arrayBufferToString should support large buffers', () => {
|
it('arrayBufferToString should support large buffers', () => {
|
||||||
const largeString = 'a'.repeat(1000000);
|
const largeString = 'a'.repeat(1000000);
|
||||||
|
|||||||
@ -290,7 +290,7 @@ async function addBundler(options: NormalizedOptions) {
|
|||||||
options.isStandalone,
|
options.isStandalone,
|
||||||
options.appIsJs
|
options.appIsJs
|
||||||
);
|
);
|
||||||
renameJsToJsx(options.reactAppName, options.isStandalone);
|
await renameJsToJsx(options.reactAppName, options.isStandalone);
|
||||||
} else {
|
} else {
|
||||||
output.log({ title: '🧑🔧 Setting up craco + Webpack' });
|
output.log({ title: '🧑🔧 Setting up craco + Webpack' });
|
||||||
const { addCracoCommandsToPackageScripts } = await import(
|
const { addCracoCommandsToPackageScripts } = await import(
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { globWithWorkspaceContext } from '../../../../utils/workspace-context';
|
|||||||
import { fileExists } from '../../../../utils/fileutils';
|
import { fileExists } from '../../../../utils/fileutils';
|
||||||
|
|
||||||
// Vite cannot process JSX like <div> or <Header> unless the file is named .jsx or .tsx
|
// Vite cannot process JSX like <div> or <Header> unless the file is named .jsx or .tsx
|
||||||
export function renameJsToJsx(appName: string, isStandalone: boolean) {
|
export async function renameJsToJsx(appName: string, isStandalone: boolean) {
|
||||||
const files = globWithWorkspaceContext(process.cwd(), [
|
const files = await globWithWorkspaceContext(process.cwd(), [
|
||||||
isStandalone ? 'src/**/*.js' : `apps/${appName}/src/**/*.js`,
|
isStandalone ? 'src/**/*.js' : `apps/${appName}/src/**/*.js`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -168,7 +168,7 @@ async function detectPlugins(): Promise<{
|
|||||||
updatePackageScripts: boolean;
|
updatePackageScripts: boolean;
|
||||||
}> {
|
}> {
|
||||||
let files = ['package.json'].concat(
|
let files = ['package.json'].concat(
|
||||||
globWithWorkspaceContext(process.cwd(), ['**/*/package.json'])
|
await globWithWorkspaceContext(process.cwd(), ['**/*/package.json'])
|
||||||
);
|
);
|
||||||
|
|
||||||
const detectedPlugins = new Set<string>();
|
const detectedPlugins = new Set<string>();
|
||||||
|
|||||||
@ -42,7 +42,7 @@ describe('Workspaces', () => {
|
|||||||
readNxJson(fs.tempDir).plugins,
|
readNxJson(fs.tempDir).plugins,
|
||||||
fs.tempDir
|
fs.tempDir
|
||||||
);
|
);
|
||||||
const res = retrieveProjectConfigurations(
|
const res = await retrieveProjectConfigurations(
|
||||||
plugins,
|
plugins,
|
||||||
fs.tempDir,
|
fs.tempDir,
|
||||||
readNxJson(fs.tempDir)
|
readNxJson(fs.tempDir)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { readFileSync, statSync } from 'fs';
|
|||||||
import { FileHandle, open } from 'fs/promises';
|
import { FileHandle, open } from 'fs/promises';
|
||||||
import { ensureDirSync, ensureFileSync } from 'fs-extra';
|
import { ensureDirSync, ensureFileSync } from 'fs-extra';
|
||||||
import { connect } from 'net';
|
import { connect } from 'net';
|
||||||
import { join } from 'path';
|
import { extname, join } from 'path';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import { output } from '../../utils/output';
|
import { output } from '../../utils/output';
|
||||||
import { getFullOsSocketPath, killSocketOrPath } from '../socket-utils';
|
import { getFullOsSocketPath, killSocketOrPath } from '../socket-utils';
|
||||||
@ -30,6 +30,21 @@ import {
|
|||||||
ProjectGraphError,
|
ProjectGraphError,
|
||||||
} from '../../project-graph/error-types';
|
} from '../../project-graph/error-types';
|
||||||
import { loadRootEnvFiles } from '../../utils/dotenv';
|
import { loadRootEnvFiles } from '../../utils/dotenv';
|
||||||
|
import { HandleGlobMessage } from '../message-types/glob';
|
||||||
|
import {
|
||||||
|
GET_NX_WORKSPACE_FILES,
|
||||||
|
HandleNxWorkspaceFilesMessage,
|
||||||
|
} from '../message-types/get-nx-workspace-files';
|
||||||
|
import {
|
||||||
|
GET_CONTEXT_FILE_DATA,
|
||||||
|
HandleContextFileDataMessage,
|
||||||
|
} from '../message-types/get-context-file-data';
|
||||||
|
import {
|
||||||
|
GET_FILES_IN_DIRECTORY,
|
||||||
|
HandleGetFilesInDirectoryMessage,
|
||||||
|
} from '../message-types/get-files-in-directory';
|
||||||
|
import { HASH_GLOB, HandleHashGlobMessage } from '../message-types/hash-glob';
|
||||||
|
import { NxWorkspaceFiles } from '../../native';
|
||||||
|
|
||||||
const DAEMON_ENV_SETTINGS = {
|
const DAEMON_ENV_SETTINGS = {
|
||||||
NX_PROJECT_GLOB_CACHE: 'false',
|
NX_PROJECT_GLOB_CACHE: 'false',
|
||||||
@ -256,6 +271,49 @@ export class DaemonClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glob(globs: string[], exclude?: string[]): Promise<string[]> {
|
||||||
|
const message: HandleGlobMessage = {
|
||||||
|
type: 'GLOB',
|
||||||
|
globs,
|
||||||
|
exclude,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorkspaceContextFileData(): Promise<FileData[]> {
|
||||||
|
const message: HandleContextFileDataMessage = {
|
||||||
|
type: GET_CONTEXT_FILE_DATA,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorkspaceFiles(
|
||||||
|
projectRootMap: Record<string, string>
|
||||||
|
): Promise<NxWorkspaceFiles> {
|
||||||
|
const message: HandleNxWorkspaceFilesMessage = {
|
||||||
|
type: GET_NX_WORKSPACE_FILES,
|
||||||
|
projectRootMap,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilesInDirectory(dir: string): Promise<string[]> {
|
||||||
|
const message: HandleGetFilesInDirectoryMessage = {
|
||||||
|
type: GET_FILES_IN_DIRECTORY,
|
||||||
|
dir,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashGlob(globs: string[], exclude?: string[]): Promise<string> {
|
||||||
|
const message: HandleHashGlobMessage = {
|
||||||
|
type: HASH_GLOB,
|
||||||
|
globs,
|
||||||
|
exclude,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
async isServerAvailable(): Promise<boolean> {
|
async isServerAvailable(): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
try {
|
try {
|
||||||
@ -414,14 +472,17 @@ export class DaemonClient {
|
|||||||
|
|
||||||
const backgroundProcess = spawn(
|
const backgroundProcess = spawn(
|
||||||
process.execPath,
|
process.execPath,
|
||||||
[join(__dirname, '../server/start.js')],
|
[join(__dirname, `../server/start.js`)],
|
||||||
{
|
{
|
||||||
cwd: workspaceRoot,
|
cwd: workspaceRoot,
|
||||||
stdio: ['ignore', this._out.fd, this._err.fd],
|
stdio: ['ignore', this._out.fd, this._err.fd],
|
||||||
detached: true,
|
detached: true,
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
shell: false,
|
shell: false,
|
||||||
env: { ...process.env, ...DAEMON_ENV_SETTINGS },
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...DAEMON_ENV_SETTINGS,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
backgroundProcess.unref();
|
backgroundProcess.unref();
|
||||||
|
|||||||
3
packages/nx/src/daemon/is-on-daemon.ts
Normal file
3
packages/nx/src/daemon/is-on-daemon.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function isOnDaemon() {
|
||||||
|
return !!global.NX_DAEMON;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
export const GET_CONTEXT_FILE_DATA = 'GET_CONTEXT_FILE_DATA' as const;
|
||||||
|
|
||||||
|
export type HandleContextFileDataMessage = {
|
||||||
|
type: typeof GET_CONTEXT_FILE_DATA;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleContextFileDataMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleContextFileDataMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === GET_CONTEXT_FILE_DATA
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
export const GET_FILES_IN_DIRECTORY = 'GET_FILES_IN_DIRECTORY' as const;
|
||||||
|
|
||||||
|
export type HandleGetFilesInDirectoryMessage = {
|
||||||
|
type: typeof GET_FILES_IN_DIRECTORY;
|
||||||
|
dir: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleGetFilesInDirectoryMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleGetFilesInDirectoryMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === GET_FILES_IN_DIRECTORY
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
export const GET_NX_WORKSPACE_FILES = 'GET_NX_WORKSPACE_FILES' as const;
|
||||||
|
|
||||||
|
export type HandleNxWorkspaceFilesMessage = {
|
||||||
|
type: typeof GET_NX_WORKSPACE_FILES;
|
||||||
|
projectRootMap: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleNxWorkspaceFilesMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleNxWorkspaceFilesMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === GET_NX_WORKSPACE_FILES
|
||||||
|
);
|
||||||
|
}
|
||||||
18
packages/nx/src/daemon/message-types/glob.ts
Normal file
18
packages/nx/src/daemon/message-types/glob.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const GLOB = 'GLOB' as const;
|
||||||
|
|
||||||
|
export type HandleGlobMessage = {
|
||||||
|
type: typeof GLOB;
|
||||||
|
globs: string[];
|
||||||
|
exclude?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleGlobMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleGlobMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === GLOB
|
||||||
|
);
|
||||||
|
}
|
||||||
18
packages/nx/src/daemon/message-types/hash-glob.ts
Normal file
18
packages/nx/src/daemon/message-types/hash-glob.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const HASH_GLOB = 'HASH_GLOB' as const;
|
||||||
|
|
||||||
|
export type HandleHashGlobMessage = {
|
||||||
|
type: typeof HASH_GLOB;
|
||||||
|
globs: string[];
|
||||||
|
exclude?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleHashGlobMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleHashGlobMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === HASH_GLOB
|
||||||
|
);
|
||||||
|
}
|
||||||
18
packages/nx/src/daemon/message-types/update-context-files.ts
Normal file
18
packages/nx/src/daemon/message-types/update-context-files.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const GLOB = 'GLOB' as const;
|
||||||
|
|
||||||
|
export type HandleUpdateContextMessage = {
|
||||||
|
type: typeof GLOB;
|
||||||
|
updatedFiles: string[];
|
||||||
|
deletedFiles: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandleUpdateContextMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandleUpdateContextMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === GLOB
|
||||||
|
);
|
||||||
|
}
|
||||||
11
packages/nx/src/daemon/server/handle-context-file-data.ts
Normal file
11
packages/nx/src/daemon/server/handle-context-file-data.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { getAllFileDataInContext } from '../../utils/workspace-context';
|
||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import { HandlerResult } from './server';
|
||||||
|
|
||||||
|
export async function handleContextFileData(): Promise<HandlerResult> {
|
||||||
|
const files = await getAllFileDataInContext(workspaceRoot);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(files),
|
||||||
|
description: 'handleContextFileData',
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { getFilesInDirectoryUsingContext } from '../../utils/workspace-context';
|
||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import { HandlerResult } from './server';
|
||||||
|
|
||||||
|
export async function handleGetFilesInDirectory(
|
||||||
|
dir: string
|
||||||
|
): Promise<HandlerResult> {
|
||||||
|
const files = await getFilesInDirectoryUsingContext(workspaceRoot, dir);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(files),
|
||||||
|
description: 'handleNxWorkspaceFiles',
|
||||||
|
};
|
||||||
|
}
|
||||||
14
packages/nx/src/daemon/server/handle-glob.ts
Normal file
14
packages/nx/src/daemon/server/handle-glob.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import { globWithWorkspaceContext } from '../../utils/workspace-context';
|
||||||
|
import { HandlerResult } from './server';
|
||||||
|
|
||||||
|
export async function handleGlob(
|
||||||
|
globs: string[],
|
||||||
|
exclude?: string[]
|
||||||
|
): Promise<HandlerResult> {
|
||||||
|
const files = await globWithWorkspaceContext(workspaceRoot, globs, exclude);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(files),
|
||||||
|
description: 'handleGlob',
|
||||||
|
};
|
||||||
|
}
|
||||||
14
packages/nx/src/daemon/server/handle-hash-glob.ts
Normal file
14
packages/nx/src/daemon/server/handle-hash-glob.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import { hashWithWorkspaceContext } from '../../utils/workspace-context';
|
||||||
|
import { HandlerResult } from './server';
|
||||||
|
|
||||||
|
export async function handleHashGlob(
|
||||||
|
globs: string[],
|
||||||
|
exclude?: string[]
|
||||||
|
): Promise<HandlerResult> {
|
||||||
|
const files = await hashWithWorkspaceContext(workspaceRoot, globs, exclude);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(files),
|
||||||
|
description: 'handleHashGlob',
|
||||||
|
};
|
||||||
|
}
|
||||||
16
packages/nx/src/daemon/server/handle-nx-workspace-files.ts
Normal file
16
packages/nx/src/daemon/server/handle-nx-workspace-files.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { getNxWorkspaceFilesFromContext } from '../../utils/workspace-context';
|
||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import { HandlerResult } from './server';
|
||||||
|
|
||||||
|
export async function handleNxWorkspaceFiles(
|
||||||
|
projectRootMap: Record<string, string>
|
||||||
|
): Promise<HandlerResult> {
|
||||||
|
const files = await getNxWorkspaceFilesFromContext(
|
||||||
|
workspaceRoot,
|
||||||
|
projectRootMap
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(files),
|
||||||
|
description: 'handleNxWorkspaceFiles',
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { getAllFileDataInContext } from '../../utils/workspace-context';
|
|
||||||
import { workspaceRoot } from '../../utils/workspace-root';
|
|
||||||
|
|
||||||
export async function handleRequestFileData() {
|
|
||||||
const response = JSON.stringify(getAllFileDataInContext(workspaceRoot));
|
|
||||||
return {
|
|
||||||
response,
|
|
||||||
description: 'handleRequestFileData',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -26,7 +26,6 @@ import {
|
|||||||
handleRecordOutputsHash,
|
handleRecordOutputsHash,
|
||||||
} from './handle-outputs-tracking';
|
} from './handle-outputs-tracking';
|
||||||
import { handleProcessInBackground } from './handle-process-in-background';
|
import { handleProcessInBackground } from './handle-process-in-background';
|
||||||
import { handleRequestFileData } from './handle-request-file-data';
|
|
||||||
import { handleRequestProjectGraph } from './handle-request-project-graph';
|
import { handleRequestProjectGraph } from './handle-request-project-graph';
|
||||||
import { handleRequestShutdown } from './handle-request-shutdown';
|
import { handleRequestShutdown } from './handle-request-shutdown';
|
||||||
import { serverLogger } from './logger';
|
import { serverLogger } from './logger';
|
||||||
@ -52,11 +51,32 @@ import {
|
|||||||
watchOutputFiles,
|
watchOutputFiles,
|
||||||
watchWorkspace,
|
watchWorkspace,
|
||||||
} from './watcher';
|
} from './watcher';
|
||||||
|
import { handleGlob } from './handle-glob';
|
||||||
|
import { GLOB, isHandleGlobMessage } from '../message-types/glob';
|
||||||
|
import {
|
||||||
|
GET_NX_WORKSPACE_FILES,
|
||||||
|
isHandleNxWorkspaceFilesMessage,
|
||||||
|
} from '../message-types/get-nx-workspace-files';
|
||||||
|
import { handleNxWorkspaceFiles } from './handle-nx-workspace-files';
|
||||||
|
import {
|
||||||
|
GET_CONTEXT_FILE_DATA,
|
||||||
|
isHandleContextFileDataMessage,
|
||||||
|
} from '../message-types/get-context-file-data';
|
||||||
|
import { handleContextFileData } from './handle-context-file-data';
|
||||||
|
import {
|
||||||
|
GET_FILES_IN_DIRECTORY,
|
||||||
|
isHandleGetFilesInDirectoryMessage,
|
||||||
|
} from '../message-types/get-files-in-directory';
|
||||||
|
import { handleGetFilesInDirectory } from './handle-get-files-in-directory';
|
||||||
|
import { HASH_GLOB, isHandleHashGlobMessage } from '../message-types/hash-glob';
|
||||||
|
import { handleHashGlob } from './handle-hash-glob';
|
||||||
|
|
||||||
let performanceObserver: PerformanceObserver | undefined;
|
let performanceObserver: PerformanceObserver | undefined;
|
||||||
let workspaceWatcherError: Error | undefined;
|
let workspaceWatcherError: Error | undefined;
|
||||||
let outputsWatcherError: Error | undefined;
|
let outputsWatcherError: Error | undefined;
|
||||||
|
|
||||||
|
global.NX_DAEMON = true;
|
||||||
|
|
||||||
export type HandlerResult = {
|
export type HandlerResult = {
|
||||||
description: string;
|
description: string;
|
||||||
error?: any;
|
error?: any;
|
||||||
@ -111,11 +131,12 @@ async function handleMessage(socket, data: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (daemonIsOutdated()) {
|
const outdated = daemonIsOutdated();
|
||||||
|
if (outdated) {
|
||||||
await respondWithErrorAndExit(
|
await respondWithErrorAndExit(
|
||||||
socket,
|
socket,
|
||||||
`Lock files changed`,
|
`Daemon outdated`,
|
||||||
new Error('LOCK-FILES-CHANGED')
|
new Error(outdated)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,10 +164,6 @@ async function handleMessage(socket, data: string) {
|
|||||||
);
|
);
|
||||||
} else if (payload.type === 'HASH_TASKS') {
|
} else if (payload.type === 'HASH_TASKS') {
|
||||||
await handleResult(socket, 'HASH_TASKS', () => handleHashTasks(payload));
|
await handleResult(socket, 'HASH_TASKS', () => handleHashTasks(payload));
|
||||||
} else if (payload.type === 'REQUEST_FILE_DATA') {
|
|
||||||
await handleResult(socket, 'REQUEST_FILE_DATA', () =>
|
|
||||||
handleRequestFileData()
|
|
||||||
);
|
|
||||||
} else if (payload.type === 'PROCESS_IN_BACKGROUND') {
|
} else if (payload.type === 'PROCESS_IN_BACKGROUND') {
|
||||||
await handleResult(socket, 'PROCESS_IN_BACKGROUND', () =>
|
await handleResult(socket, 'PROCESS_IN_BACKGROUND', () =>
|
||||||
handleProcessInBackground(payload)
|
handleProcessInBackground(payload)
|
||||||
@ -165,6 +182,26 @@ async function handleMessage(socket, data: string) {
|
|||||||
);
|
);
|
||||||
} else if (payload.type === 'REGISTER_FILE_WATCHER') {
|
} else if (payload.type === 'REGISTER_FILE_WATCHER') {
|
||||||
registeredFileWatcherSockets.push({ socket, config: payload.config });
|
registeredFileWatcherSockets.push({ socket, config: payload.config });
|
||||||
|
} else if (isHandleGlobMessage(payload)) {
|
||||||
|
await handleResult(socket, GLOB, () =>
|
||||||
|
handleGlob(payload.globs, payload.exclude)
|
||||||
|
);
|
||||||
|
} else if (isHandleNxWorkspaceFilesMessage(payload)) {
|
||||||
|
await handleResult(socket, GET_NX_WORKSPACE_FILES, () =>
|
||||||
|
handleNxWorkspaceFiles(payload.projectRootMap)
|
||||||
|
);
|
||||||
|
} else if (isHandleGetFilesInDirectoryMessage(payload)) {
|
||||||
|
await handleResult(socket, GET_FILES_IN_DIRECTORY, () =>
|
||||||
|
handleGetFilesInDirectory(payload.dir)
|
||||||
|
);
|
||||||
|
} else if (isHandleContextFileDataMessage(payload)) {
|
||||||
|
await handleResult(socket, GET_CONTEXT_FILE_DATA, () =>
|
||||||
|
handleContextFileData()
|
||||||
|
);
|
||||||
|
} else if (isHandleHashGlobMessage(payload)) {
|
||||||
|
await handleResult(socket, HASH_GLOB, () =>
|
||||||
|
handleHashGlob(payload.globs, payload.exclude)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
await respondWithErrorAndExit(
|
await respondWithErrorAndExit(
|
||||||
socket,
|
socket,
|
||||||
@ -233,8 +270,13 @@ function registerProcessTerminationListeners() {
|
|||||||
|
|
||||||
let existingLockHash: string | undefined;
|
let existingLockHash: string | undefined;
|
||||||
|
|
||||||
function daemonIsOutdated(): boolean {
|
function daemonIsOutdated(): string | null {
|
||||||
return nxVersionChanged() || lockFileHashChanged();
|
if (nxVersionChanged()) {
|
||||||
|
return 'NX_VERSION_CHANGED';
|
||||||
|
} else if (lockFileHashChanged()) {
|
||||||
|
return 'LOCK_FILES_CHANGED';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nxVersionChanged(): boolean {
|
function nxVersionChanged(): boolean {
|
||||||
@ -291,10 +333,11 @@ const handleWorkspaceChanges: FileWatcherCallback = async (
|
|||||||
try {
|
try {
|
||||||
resetInactivityTimeout(handleInactivityTimeout);
|
resetInactivityTimeout(handleInactivityTimeout);
|
||||||
|
|
||||||
if (daemonIsOutdated()) {
|
const outdatedReason = daemonIsOutdated();
|
||||||
|
if (outdatedReason) {
|
||||||
await handleServerProcessTermination({
|
await handleServerProcessTermination({
|
||||||
server,
|
server,
|
||||||
reason: 'Lock file changed',
|
reason: outdatedReason,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,7 +132,7 @@ export {
|
|||||||
/**
|
/**
|
||||||
* @category Generators
|
* @category Generators
|
||||||
*/
|
*/
|
||||||
export { glob } from './generators/utils/glob';
|
export { glob, globAsync } from './generators/utils/glob';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @category Generators
|
* @category Generators
|
||||||
|
|||||||
@ -1,7 +1,28 @@
|
|||||||
import { minimatch } from 'minimatch';
|
import { minimatch } from 'minimatch';
|
||||||
import { Tree } from '../tree';
|
import { Tree } from '../tree';
|
||||||
import { combineGlobPatterns } from '../../utils/globs';
|
import { combineGlobPatterns } from '../../utils/globs';
|
||||||
import { globWithWorkspaceContext } from '../../utils/workspace-context';
|
import {
|
||||||
|
globWithWorkspaceContext,
|
||||||
|
globWithWorkspaceContextSync,
|
||||||
|
} from '../../utils/workspace-context';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a tree-aware glob search on the files in a workspace. Able to find newly
|
||||||
|
* created files and hides deleted files before the updates are committed to disk.
|
||||||
|
* Paths should be unix-style with forward slashes.
|
||||||
|
*
|
||||||
|
* @param tree The file system tree
|
||||||
|
* @param patterns A list of glob patterns
|
||||||
|
* @returns Normalized paths in the workspace that match the provided glob patterns.
|
||||||
|
* @deprecated Use {@link globAsync} instead.
|
||||||
|
*/
|
||||||
|
export function glob(tree: Tree, patterns: string[]): string[] {
|
||||||
|
return combineGlobResultsWithTree(
|
||||||
|
tree,
|
||||||
|
patterns,
|
||||||
|
globWithWorkspaceContextSync(tree.root, patterns)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a tree-aware glob search on the files in a workspace. Able to find newly
|
* Performs a tree-aware glob search on the files in a workspace. Able to find newly
|
||||||
@ -12,8 +33,23 @@ import { globWithWorkspaceContext } from '../../utils/workspace-context';
|
|||||||
* @param patterns A list of glob patterns
|
* @param patterns A list of glob patterns
|
||||||
* @returns Normalized paths in the workspace that match the provided glob patterns.
|
* @returns Normalized paths in the workspace that match the provided glob patterns.
|
||||||
*/
|
*/
|
||||||
export function glob(tree: Tree, patterns: string[]): string[] {
|
export async function globAsync(
|
||||||
const matches = new Set(globWithWorkspaceContext(tree.root, patterns));
|
tree: Tree,
|
||||||
|
patterns: string[]
|
||||||
|
): Promise<string[]> {
|
||||||
|
return combineGlobResultsWithTree(
|
||||||
|
tree,
|
||||||
|
patterns,
|
||||||
|
await globWithWorkspaceContext(tree.root, patterns)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function combineGlobResultsWithTree(
|
||||||
|
tree: Tree,
|
||||||
|
patterns: string[],
|
||||||
|
results: string[]
|
||||||
|
) {
|
||||||
|
const matches = new Set(results);
|
||||||
|
|
||||||
const combinedGlob = combineGlobPatterns(patterns);
|
const combinedGlob = combineGlobPatterns(patterns);
|
||||||
const matcher = minimatch.makeRe(combinedGlob);
|
const matcher = minimatch.makeRe(combinedGlob);
|
||||||
|
|||||||
@ -4,12 +4,8 @@ import { basename, join, relative } from 'path';
|
|||||||
import {
|
import {
|
||||||
buildProjectConfigurationFromPackageJson,
|
buildProjectConfigurationFromPackageJson,
|
||||||
getGlobPatternsFromPackageManagerWorkspaces,
|
getGlobPatternsFromPackageManagerWorkspaces,
|
||||||
createNodes as packageJsonWorkspacesCreateNodes,
|
|
||||||
} from '../../plugins/package-json-workspaces';
|
} from '../../plugins/package-json-workspaces';
|
||||||
import {
|
import { buildProjectFromProjectJson } from '../../plugins/project-json/build-nodes/project-json';
|
||||||
buildProjectFromProjectJson,
|
|
||||||
ProjectJsonProjectsPlugin,
|
|
||||||
} from '../../plugins/project-json/build-nodes/project-json';
|
|
||||||
import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
|
import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
|
||||||
import {
|
import {
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
@ -19,8 +15,7 @@ import {
|
|||||||
mergeProjectConfigurationIntoRootMap,
|
mergeProjectConfigurationIntoRootMap,
|
||||||
readProjectConfigurationsFromRootMap,
|
readProjectConfigurationsFromRootMap,
|
||||||
} from '../../project-graph/utils/project-configuration-utils';
|
} from '../../project-graph/utils/project-configuration-utils';
|
||||||
import { configurationGlobs } from '../../project-graph/utils/retrieve-workspace-files';
|
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
|
||||||
import { globWithWorkspaceContext } from '../../utils/workspace-context';
|
|
||||||
import { output } from '../../utils/output';
|
import { output } from '../../utils/output';
|
||||||
import { PackageJson } from '../../utils/package-json';
|
import { PackageJson } from '../../utils/package-json';
|
||||||
import { joinPathFragments, normalizePath } from '../../utils/path';
|
import { joinPathFragments, normalizePath } from '../../utils/path';
|
||||||
@ -28,7 +23,6 @@ import { readJson, writeJson } from './json';
|
|||||||
import { readNxJson } from './nx-json';
|
import { readNxJson } from './nx-json';
|
||||||
|
|
||||||
import type { Tree } from '../tree';
|
import type { Tree } from '../tree';
|
||||||
import { NxPlugin } from '../../project-graph/plugins';
|
|
||||||
|
|
||||||
export { readNxJson, updateNxJson } from './nx-json';
|
export { readNxJson, updateNxJson } from './nx-json';
|
||||||
|
|
||||||
@ -200,7 +194,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
|
|||||||
readJson(tree, p, { expectComments: true })
|
readJson(tree, p, { expectComments: true })
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
const globbedFiles = globWithWorkspaceContext(tree.root, patterns);
|
const globbedFiles = globWithWorkspaceContextSync(tree.root, patterns);
|
||||||
const createdFiles = findCreatedProjectFiles(tree, patterns);
|
const createdFiles = findCreatedProjectFiles(tree, patterns);
|
||||||
const deletedFiles = findDeletedProjectFiles(tree, patterns);
|
const deletedFiles = findDeletedProjectFiles(tree, patterns);
|
||||||
const projectFiles = [...globbedFiles, ...createdFiles].filter(
|
const projectFiles = [...globbedFiles, ...createdFiles].filter(
|
||||||
|
|||||||
@ -89,7 +89,7 @@ describe('explicit package json dependencies', () => {
|
|||||||
|
|
||||||
const fileMap = createFileMap(
|
const fileMap = createFileMap(
|
||||||
projectsConfigurations as any,
|
projectsConfigurations as any,
|
||||||
getAllFileDataInContext(tempFs.tempDir)
|
await getAllFileDataInContext(tempFs.tempDir)
|
||||||
).fileMap;
|
).fileMap;
|
||||||
|
|
||||||
const builder = new ProjectGraphBuilder(undefined, fileMap.projectFileMap);
|
const builder = new ProjectGraphBuilder(undefined, fileMap.projectFileMap);
|
||||||
|
|||||||
@ -39,12 +39,7 @@ export async function createFileMapUsingProjectGraph(
|
|||||||
): Promise<WorkspaceFileMap> {
|
): Promise<WorkspaceFileMap> {
|
||||||
const configs = readProjectsConfigurationFromProjectGraph(graph);
|
const configs = readProjectsConfigurationFromProjectGraph(graph);
|
||||||
|
|
||||||
let files: FileData[];
|
let files: FileData[] = await getAllFileDataInContext(workspaceRoot);
|
||||||
if (daemonClient.enabled()) {
|
|
||||||
files = await daemonClient.getAllFileData();
|
|
||||||
} else {
|
|
||||||
files = getAllFileDataInContext(workspaceRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return createFileMap(configs, files);
|
return createFileMap(configs, files);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { existsSync, readFileSync } from 'fs';
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import { extname, join, relative, sep } from 'path';
|
import { basename, extname, join, relative, sep } from 'path';
|
||||||
import { readNxJson } from '../config/configuration';
|
import { readNxJson } from '../config/configuration';
|
||||||
import { FileData } from '../config/project-graph';
|
import { FileData } from '../config/project-graph';
|
||||||
import {
|
import {
|
||||||
@ -17,16 +17,18 @@ import {
|
|||||||
} from './project-graph';
|
} from './project-graph';
|
||||||
import { toOldFormat } from '../adapter/angular-json';
|
import { toOldFormat } from '../adapter/angular-json';
|
||||||
import { getIgnoreObject } from '../utils/ignore';
|
import { getIgnoreObject } from '../utils/ignore';
|
||||||
import { retrieveProjectConfigurationPaths } from './utils/retrieve-workspace-files';
|
|
||||||
import {
|
import {
|
||||||
mergeProjectConfigurationIntoRootMap,
|
mergeProjectConfigurationIntoRootMap,
|
||||||
readProjectConfigurationsFromRootMap,
|
readProjectConfigurationsFromRootMap,
|
||||||
} from './utils/project-configuration-utils';
|
} from './utils/project-configuration-utils';
|
||||||
import { NxJsonConfiguration } from '../config/nx-json';
|
import {
|
||||||
import { getDefaultPluginsSync } from '../utils/nx-plugin.deprecated';
|
buildProjectConfigurationFromPackageJson,
|
||||||
import { minimatch } from 'minimatch';
|
getGlobPatternsFromPackageManagerWorkspaces,
|
||||||
import { CreateNodesResult } from '../devkit-exports';
|
} from '../plugins/package-json-workspaces';
|
||||||
import { PackageJsonProjectsNextToProjectJsonPlugin } from '../plugins/project-json/build-nodes/package-json-next-to-project-json';
|
import { globWithWorkspaceContextSync } from '../utils/workspace-context';
|
||||||
|
import { buildProjectFromProjectJson } from '../plugins/project-json/build-nodes/project-json';
|
||||||
|
import { PackageJson } from '../utils/package-json';
|
||||||
|
import { NxJsonConfiguration } from '../devkit-exports';
|
||||||
|
|
||||||
export interface Change {
|
export interface Change {
|
||||||
type: string;
|
type: string;
|
||||||
@ -151,7 +153,7 @@ export function readWorkspaceConfig(opts: {
|
|||||||
} catch {
|
} catch {
|
||||||
configuration = {
|
configuration = {
|
||||||
version: 2,
|
version: 2,
|
||||||
projects: getProjectsSyncNoInference(root, nxJson).projects,
|
projects: getProjectsSync(root, nxJson),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (opts.format === 'angularCli') {
|
if (opts.format === 'angularCli') {
|
||||||
@ -179,50 +181,59 @@ export { FileData };
|
|||||||
/**
|
/**
|
||||||
* TODO(v20): Remove this function.
|
* TODO(v20): Remove this function.
|
||||||
*/
|
*/
|
||||||
function getProjectsSyncNoInference(root: string, nxJson: NxJsonConfiguration) {
|
function getProjectsSync(
|
||||||
const allConfigFiles = retrieveProjectConfigurationPaths(
|
root: string,
|
||||||
root,
|
nxJson: NxJsonConfiguration
|
||||||
getDefaultPluginsSync(root)
|
): {
|
||||||
);
|
[name: string]: ProjectConfiguration;
|
||||||
const plugins = [
|
} {
|
||||||
PackageJsonProjectsNextToProjectJsonPlugin,
|
/**
|
||||||
...getDefaultPluginsSync(root),
|
* We can't update projects that come from plugins anyways, so we are going
|
||||||
|
* to ignore them for now. Plugins should add their own add/create/update methods
|
||||||
|
* if they would like to use devkit to update inferred projects.
|
||||||
|
*/
|
||||||
|
const patterns = [
|
||||||
|
'**/project.json',
|
||||||
|
'project.json',
|
||||||
|
...getGlobPatternsFromPackageManagerWorkspaces(root, readJsonFile),
|
||||||
];
|
];
|
||||||
|
const projectFiles = globWithWorkspaceContextSync(root, patterns);
|
||||||
|
|
||||||
const projectRootMap: Record<string, ProjectConfiguration> = {};
|
const rootMap: Record<string, ProjectConfiguration> = {};
|
||||||
|
for (const projectFile of projectFiles) {
|
||||||
// We iterate over plugins first - this ensures that plugins specified first take precedence.
|
if (basename(projectFile) === 'project.json') {
|
||||||
for (const plugin of plugins) {
|
const json = readJsonFile(projectFile);
|
||||||
const [pattern, createNodes] = plugin.createNodes ?? [];
|
const config = buildProjectFromProjectJson(json, projectFile);
|
||||||
if (!pattern) {
|
mergeProjectConfigurationIntoRootMap(
|
||||||
continue;
|
rootMap,
|
||||||
}
|
config,
|
||||||
const matchingConfigFiles = allConfigFiles.filter((file) =>
|
undefined,
|
||||||
minimatch(file, pattern, { dot: true })
|
undefined,
|
||||||
);
|
true
|
||||||
for (const file of matchingConfigFiles) {
|
);
|
||||||
if (minimatch(file, pattern, { dot: true })) {
|
} else if (basename(projectFile) === 'package.json') {
|
||||||
let r = createNodes(
|
const packageJson = readJsonFile<PackageJson>(projectFile);
|
||||||
file,
|
const config = buildProjectConfigurationFromPackageJson(
|
||||||
{},
|
packageJson,
|
||||||
|
projectFile,
|
||||||
|
nxJson
|
||||||
|
);
|
||||||
|
if (!rootMap[config.root]) {
|
||||||
|
mergeProjectConfigurationIntoRootMap(
|
||||||
|
rootMap,
|
||||||
|
// Inferred targets, tags, etc don't show up when running generators
|
||||||
|
// This is to help avoid running into issues when trying to update the workspace
|
||||||
{
|
{
|
||||||
nxJsonConfiguration: nxJson,
|
name: config.name,
|
||||||
workspaceRoot: root,
|
root: config.root,
|
||||||
configFiles: matchingConfigFiles,
|
},
|
||||||
}
|
undefined,
|
||||||
) as CreateNodesResult;
|
undefined,
|
||||||
for (const node in r.projects) {
|
true
|
||||||
const project = {
|
);
|
||||||
root: node,
|
|
||||||
...r.projects[node],
|
|
||||||
};
|
|
||||||
mergeProjectConfigurationIntoRootMap(projectRootMap, project);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return readProjectConfigurationsFromRootMap(rootMap);
|
||||||
projects: readProjectConfigurationsFromRootMap(projectRootMap),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,17 +28,23 @@ export function loadRemoteNxPlugin(
|
|||||||
// but its typescript.
|
// but its typescript.
|
||||||
const isWorkerTypescript = path.extname(__filename) === '.ts';
|
const isWorkerTypescript = path.extname(__filename) === '.ts';
|
||||||
const workerPath = path.join(__dirname, 'plugin-worker');
|
const workerPath = path.join(__dirname, 'plugin-worker');
|
||||||
|
|
||||||
|
const env: Record<string, string> = {
|
||||||
|
...process.env,
|
||||||
|
...(isWorkerTypescript
|
||||||
|
? {
|
||||||
|
// Ensures that the worker uses the same tsconfig as the main process
|
||||||
|
TS_NODE_PROJECT: path.join(
|
||||||
|
__dirname,
|
||||||
|
'../../../../tsconfig.lib.json'
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
|
||||||
const worker = fork(workerPath, [], {
|
const worker = fork(workerPath, [], {
|
||||||
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
||||||
env: {
|
env,
|
||||||
...process.env,
|
|
||||||
...(isWorkerTypescript
|
|
||||||
? {
|
|
||||||
// Ensures that the worker uses the same tsconfig as the main process
|
|
||||||
TS_NODE_PROJECT: path.join(__dirname, '../../../tsconfig.lib.json'),
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
execArgv: [
|
execArgv: [
|
||||||
...process.execArgv,
|
...process.execArgv,
|
||||||
// If the worker is typescript, we need to register ts-node
|
// If the worker is typescript, we need to register ts-node
|
||||||
|
|||||||
@ -25,7 +25,7 @@ describe('retrieveProjectConfigurationPaths', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const configPaths = retrieveProjectConfigurationPaths(fs.tempDir, [
|
const configPaths = await retrieveProjectConfigurationPaths(fs.tempDir, [
|
||||||
{
|
{
|
||||||
createNodes: [
|
createNodes: [
|
||||||
'{project.json,**/project.json}',
|
'{project.json,**/project.json}',
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export async function retrieveWorkspaceFiles(
|
|||||||
performance.mark('get-workspace-files:start');
|
performance.mark('get-workspace-files:start');
|
||||||
|
|
||||||
const { projectFileMap, globalFiles, externalReferences } =
|
const { projectFileMap, globalFiles, externalReferences } =
|
||||||
getNxWorkspaceFilesFromContext(workspaceRoot, projectRootMap);
|
await getNxWorkspaceFilesFromContext(workspaceRoot, projectRootMap);
|
||||||
performance.mark('get-workspace-files:end');
|
performance.mark('get-workspace-files:end');
|
||||||
performance.measure(
|
performance.measure(
|
||||||
'get-workspace-files',
|
'get-workspace-files',
|
||||||
@ -60,13 +60,16 @@ export async function retrieveWorkspaceFiles(
|
|||||||
* Walk through the workspace and return `ProjectConfigurations`. Only use this if the projectFileMap is not needed.
|
* Walk through the workspace and return `ProjectConfigurations`. Only use this if the projectFileMap is not needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function retrieveProjectConfigurations(
|
export async function retrieveProjectConfigurations(
|
||||||
plugins: LoadedNxPlugin[],
|
plugins: LoadedNxPlugin[],
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
nxJson: NxJsonConfiguration
|
nxJson: NxJsonConfiguration
|
||||||
): Promise<ConfigurationResult> {
|
): Promise<ConfigurationResult> {
|
||||||
const globPatterns = configurationGlobs(plugins);
|
const globPatterns = configurationGlobs(plugins);
|
||||||
const workspaceFiles = globWithWorkspaceContext(workspaceRoot, globPatterns);
|
const workspaceFiles = await globWithWorkspaceContext(
|
||||||
|
workspaceRoot,
|
||||||
|
globPatterns
|
||||||
|
);
|
||||||
|
|
||||||
return createProjectConfigurations(
|
return createProjectConfigurations(
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
@ -98,7 +101,11 @@ export async function retrieveProjectConfigurationsWithAngularProjects(
|
|||||||
workspaceRoot
|
workspaceRoot
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = retrieveProjectConfigurations(plugins, workspaceRoot, nxJson);
|
const res = await retrieveProjectConfigurations(
|
||||||
|
plugins,
|
||||||
|
workspaceRoot,
|
||||||
|
nxJson
|
||||||
|
);
|
||||||
cleanup();
|
cleanup();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -106,7 +113,7 @@ export async function retrieveProjectConfigurationsWithAngularProjects(
|
|||||||
export function retrieveProjectConfigurationPaths(
|
export function retrieveProjectConfigurationPaths(
|
||||||
root: string,
|
root: string,
|
||||||
plugins: Array<{ createNodes?: readonly [string, ...unknown[]] } & unknown>
|
plugins: Array<{ createNodes?: readonly [string, ...unknown[]] } & unknown>
|
||||||
): string[] {
|
): Promise<string[]> {
|
||||||
const projectGlobPatterns = configurationGlobs(plugins);
|
const projectGlobPatterns = configurationGlobs(plugins);
|
||||||
return globWithWorkspaceContext(root, projectGlobPatterns);
|
return globWithWorkspaceContext(root, projectGlobPatterns);
|
||||||
}
|
}
|
||||||
@ -122,7 +129,10 @@ export async function retrieveProjectConfigurationsWithoutPluginInference(
|
|||||||
): Promise<Record<string, ProjectConfiguration>> {
|
): Promise<Record<string, ProjectConfiguration>> {
|
||||||
const nxJson = readNxJson(root);
|
const nxJson = readNxJson(root);
|
||||||
const [plugins, cleanup] = await loadNxPlugins([]); // only load default plugins
|
const [plugins, cleanup] = await loadNxPlugins([]); // only load default plugins
|
||||||
const projectGlobPatterns = retrieveProjectConfigurationPaths(root, plugins);
|
const projectGlobPatterns = await retrieveProjectConfigurationPaths(
|
||||||
|
root,
|
||||||
|
plugins
|
||||||
|
);
|
||||||
const cacheKey = root + ',' + projectGlobPatterns.join(',');
|
const cacheKey = root + ',' + projectGlobPatterns.join(',');
|
||||||
|
|
||||||
if (projectsWithoutPluginCache.has(cacheKey)) {
|
if (projectsWithoutPluginCache.has(cacheKey)) {
|
||||||
@ -130,7 +140,7 @@ export async function retrieveProjectConfigurationsWithoutPluginInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const projectFiles =
|
const projectFiles =
|
||||||
globWithWorkspaceContext(root, projectGlobPatterns) ?? [];
|
(await globWithWorkspaceContext(root, projectGlobPatterns)) ?? [];
|
||||||
const { projects } = await createProjectConfigurations(
|
const { projects } = await createProjectConfigurations(
|
||||||
root,
|
root,
|
||||||
nxJson,
|
nxJson,
|
||||||
|
|||||||
@ -1,12 +1,7 @@
|
|||||||
import { FileData } from '../config/project-graph';
|
import { FileData } from '../config/project-graph';
|
||||||
import { daemonClient } from '../daemon/client/client';
|
|
||||||
import { getAllFileDataInContext } from './workspace-context';
|
import { getAllFileDataInContext } from './workspace-context';
|
||||||
import { workspaceRoot } from './workspace-root';
|
import { workspaceRoot } from './workspace-root';
|
||||||
|
|
||||||
export function allFileData(): Promise<FileData[]> {
|
export function allFileData(): Promise<FileData[]> {
|
||||||
if (daemonClient.enabled()) {
|
return getAllFileDataInContext(workspaceRoot);
|
||||||
return daemonClient.getAllFileData();
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(getAllFileDataInContext(workspaceRoot));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import type { NxWorkspaceFilesExternals, WorkspaceContext } from '../native';
|
import type { NxWorkspaceFilesExternals, WorkspaceContext } from '../native';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import { cacheDirectoryForWorkspace } from './cache-directory';
|
import { cacheDirectoryForWorkspace } from './cache-directory';
|
||||||
|
import { isOnDaemon } from '../daemon/is-on-daemon';
|
||||||
|
import { daemonClient } from '../daemon/client/client';
|
||||||
|
|
||||||
let workspaceContext: WorkspaceContext | undefined;
|
let workspaceContext: WorkspaceContext | undefined;
|
||||||
|
|
||||||
@ -20,15 +22,25 @@ export function setupWorkspaceContext(workspaceRoot: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNxWorkspaceFilesFromContext(
|
export async function getNxWorkspaceFilesFromContext(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
projectRootMap: Record<string, string>
|
projectRootMap: Record<string, string>
|
||||||
) {
|
) {
|
||||||
ensureContextAvailable(workspaceRoot);
|
if (isOnDaemon() || !daemonClient.enabled()) {
|
||||||
return workspaceContext.getWorkspaceFiles(projectRootMap);
|
ensureContextAvailable(workspaceRoot);
|
||||||
|
return workspaceContext.getWorkspaceFiles(projectRootMap);
|
||||||
|
}
|
||||||
|
return daemonClient.getWorkspaceFiles(projectRootMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function globWithWorkspaceContext(
|
/**
|
||||||
|
* Sync method to get files matching globs from workspace context.
|
||||||
|
* NOTE: This method will create the workspace context if it doesn't exist.
|
||||||
|
* It should only be used within Nx internal in code paths that **must** be sync.
|
||||||
|
* If used in an isolated plugin thread this will cause the workspace context
|
||||||
|
* to be recreated which is slow.
|
||||||
|
*/
|
||||||
|
export function globWithWorkspaceContextSync(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
globs: string[],
|
globs: string[],
|
||||||
exclude?: string[]
|
exclude?: string[]
|
||||||
@ -37,13 +49,29 @@ export function globWithWorkspaceContext(
|
|||||||
return workspaceContext.glob(globs, exclude);
|
return workspaceContext.glob(globs, exclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hashWithWorkspaceContext(
|
export async function globWithWorkspaceContext(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
globs: string[],
|
globs: string[],
|
||||||
exclude?: string[]
|
exclude?: string[]
|
||||||
) {
|
) {
|
||||||
ensureContextAvailable(workspaceRoot);
|
if (isOnDaemon() || !daemonClient.enabled()) {
|
||||||
return workspaceContext.hashFilesMatchingGlob(globs, exclude);
|
ensureContextAvailable(workspaceRoot);
|
||||||
|
return workspaceContext.glob(globs, exclude);
|
||||||
|
} else {
|
||||||
|
return daemonClient.glob(globs, exclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function hashWithWorkspaceContext(
|
||||||
|
workspaceRoot: string,
|
||||||
|
globs: string[],
|
||||||
|
exclude?: string[]
|
||||||
|
) {
|
||||||
|
if (isOnDaemon() || !daemonClient.enabled()) {
|
||||||
|
ensureContextAvailable(workspaceRoot);
|
||||||
|
return workspaceContext.hashFilesMatchingGlob(globs, exclude);
|
||||||
|
}
|
||||||
|
return daemonClient.hashGlob(globs, exclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateFilesInContext(
|
export function updateFilesInContext(
|
||||||
@ -53,17 +81,23 @@ export function updateFilesInContext(
|
|||||||
return workspaceContext?.incrementalUpdate(updatedFiles, deletedFiles);
|
return workspaceContext?.incrementalUpdate(updatedFiles, deletedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllFileDataInContext(workspaceRoot: string) {
|
export async function getAllFileDataInContext(workspaceRoot: string) {
|
||||||
ensureContextAvailable(workspaceRoot);
|
if (isOnDaemon() || !daemonClient.enabled()) {
|
||||||
return workspaceContext.allFileData();
|
ensureContextAvailable(workspaceRoot);
|
||||||
|
return workspaceContext.allFileData();
|
||||||
|
}
|
||||||
|
return daemonClient.getWorkspaceContextFileData();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFilesInDirectoryUsingContext(
|
export async function getFilesInDirectoryUsingContext(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
dir: string
|
dir: string
|
||||||
) {
|
) {
|
||||||
ensureContextAvailable(workspaceRoot);
|
if (isOnDaemon() || !daemonClient.enabled()) {
|
||||||
return workspaceContext.getFilesInDirectory(dir);
|
ensureContextAvailable(workspaceRoot);
|
||||||
|
return workspaceContext.getFilesInDirectory(dir);
|
||||||
|
}
|
||||||
|
return daemonClient.getFilesInDirectory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateProjectFiles(
|
export function updateProjectFiles(
|
||||||
|
|||||||
@ -108,9 +108,12 @@ async function createNodesInternal(
|
|||||||
|
|
||||||
const normalizedOptions = normalizeOptions(options);
|
const normalizedOptions = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildPlaywrightTargets(
|
targetsCache[hash] ??= await buildPlaywrightTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
@ -199,7 +202,7 @@ async function buildPlaywrightTargets(
|
|||||||
playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
|
playwrightConfig.testMatch ??= '**/*.@(spec|test).?(c|m)[jt]s?(x)';
|
||||||
|
|
||||||
const dependsOn: TargetConfiguration['dependsOn'] = [];
|
const dependsOn: TargetConfiguration['dependsOn'] = [];
|
||||||
forEachTestFile(
|
await forEachTestFile(
|
||||||
(testFile) => {
|
(testFile) => {
|
||||||
const relativeSpecFilePath = normalizePath(
|
const relativeSpecFilePath = normalizePath(
|
||||||
relative(projectRoot, testFile)
|
relative(projectRoot, testFile)
|
||||||
@ -246,7 +249,7 @@ async function buildPlaywrightTargets(
|
|||||||
return { targets, metadata };
|
return { targets, metadata };
|
||||||
}
|
}
|
||||||
|
|
||||||
function forEachTestFile(
|
async function forEachTestFile(
|
||||||
cb: (path: string) => void,
|
cb: (path: string) => void,
|
||||||
opts: {
|
opts: {
|
||||||
context: CreateNodesContext;
|
context: CreateNodesContext;
|
||||||
@ -254,7 +257,7 @@ function forEachTestFile(
|
|||||||
config: PlaywrightTestConfig;
|
config: PlaywrightTestConfig;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const files = getFilesInDirectoryUsingContext(
|
const files = await getFilesInDirectoryUsingContext(
|
||||||
opts.context.workspaceRoot,
|
opts.context.workspaceRoot,
|
||||||
opts.path
|
opts.path
|
||||||
);
|
);
|
||||||
|
|||||||
@ -70,9 +70,12 @@ export const createNodes: CreateNodes<ReactNativePluginOptions> = [
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= buildReactNativeTargets(
|
targetsCache[hash] ??= buildReactNativeTargets(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
|||||||
@ -66,9 +66,12 @@ export const createNodes: CreateNodes<RemixPluginOptions> = [
|
|||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
targetsCache[hash] ??= await buildRemixTargets(
|
targetsCache[hash] ??= await buildRemixTargets(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
|||||||
@ -6,10 +6,39 @@ import {
|
|||||||
|
|
||||||
describe('createWatchPaths', () => {
|
describe('createWatchPaths', () => {
|
||||||
it('should list root paths of dependencies relative to project root', async () => {
|
it('should list root paths of dependencies relative to project root', async () => {
|
||||||
const testDir = joinPathFragments(workspaceRoot, 'e2e/remix');
|
// This test is written based on the Nx repo's project graph.
|
||||||
|
jest
|
||||||
|
.spyOn(require('@nx/devkit'), 'createProjectGraphAsync')
|
||||||
|
.mockResolvedValue({
|
||||||
|
nodes: {
|
||||||
|
parent: {
|
||||||
|
type: 'app',
|
||||||
|
name: 'parent',
|
||||||
|
data: { root: 'apps/parent' },
|
||||||
|
},
|
||||||
|
lib: {
|
||||||
|
type: 'lib',
|
||||||
|
name: 'lib',
|
||||||
|
data: { root: 'packages/lib' },
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
type: 'app',
|
||||||
|
name: 'example',
|
||||||
|
data: { root: 'examples/example' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
parent: [
|
||||||
|
{ type: 'static', source: 'parent', target: 'lib' },
|
||||||
|
{ type: 'static', source: 'parent', target: 'example' },
|
||||||
|
],
|
||||||
|
example: [{ type: 'static', source: 'example', target: 'lib' }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const testDir = joinPathFragments(workspaceRoot, 'apps/parent');
|
||||||
|
|
||||||
const paths = await createWatchPaths(testDir);
|
const paths = await createWatchPaths(testDir);
|
||||||
expect(paths).toEqual(['../../packages', '../../graph', '../../e2e/utils']);
|
expect(paths).toEqual(['../../packages', '../../examples']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -63,9 +63,12 @@ export const createNodes: CreateNodes<RollupPluginOptions> = [
|
|||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
targetsCache[hash] ??= await buildRollupTarget(
|
targetsCache[hash] ??= await buildRollupTarget(
|
||||||
configFilePath,
|
configFilePath,
|
||||||
|
|||||||
@ -72,9 +72,12 @@ export const createNodes: CreateNodes<StorybookPluginOptions> = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
|
|
||||||
const projectName = buildProjectName(projectRoot, context.workspaceRoot);
|
const projectName = buildProjectName(projectRoot, context.workspaceRoot);
|
||||||
|
|
||||||
|
|||||||
@ -44,9 +44,10 @@ describe('@nx/vite/plugin', () => {
|
|||||||
production: ['!{projectRoot}/**/*.spec.ts'],
|
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
workspaceRoot: '',
|
workspaceRoot: tempFs.tempDir,
|
||||||
};
|
};
|
||||||
tempFs.createFileSync('index.html', '');
|
tempFs.createFileSync('index.html', '');
|
||||||
|
tempFs.createFileSync('package.json', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
workspaceRoot,
|
|
||||||
writeJsonFile,
|
writeJsonFile,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { dirname, isAbsolute, join, relative } from 'path';
|
import { dirname, isAbsolute, join, relative } from 'path';
|
||||||
@ -118,7 +117,8 @@ async function buildViteTargets(
|
|||||||
|
|
||||||
const { buildOutputs, testOutputs, hasTest, isBuildable } = getOutputs(
|
const { buildOutputs, testOutputs, hasTest, isBuildable } = getOutputs(
|
||||||
viteConfig,
|
viteConfig,
|
||||||
projectRoot
|
projectRoot,
|
||||||
|
context.workspaceRoot
|
||||||
);
|
);
|
||||||
|
|
||||||
const namedInputs = getNamedInputs(projectRoot, context);
|
const namedInputs = getNamedInputs(projectRoot, context);
|
||||||
@ -244,7 +244,8 @@ function serveStaticTarget(options: VitePluginOptions) {
|
|||||||
|
|
||||||
function getOutputs(
|
function getOutputs(
|
||||||
viteConfig: Record<string, any> | undefined,
|
viteConfig: Record<string, any> | undefined,
|
||||||
projectRoot: string
|
projectRoot: string,
|
||||||
|
workspaceRoot: string
|
||||||
): {
|
): {
|
||||||
buildOutputs: string[];
|
buildOutputs: string[];
|
||||||
testOutputs: string[];
|
testOutputs: string[];
|
||||||
@ -256,6 +257,7 @@ function getOutputs(
|
|||||||
const buildOutputPath = normalizeOutputPath(
|
const buildOutputPath = normalizeOutputPath(
|
||||||
build?.outDir,
|
build?.outDir,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
workspaceRoot,
|
||||||
'dist'
|
'dist'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -267,6 +269,7 @@ function getOutputs(
|
|||||||
const reportsDirectoryPath = normalizeOutputPath(
|
const reportsDirectoryPath = normalizeOutputPath(
|
||||||
test?.coverage?.reportsDirectory,
|
test?.coverage?.reportsDirectory,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
|
workspaceRoot,
|
||||||
'coverage'
|
'coverage'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -281,6 +284,7 @@ function getOutputs(
|
|||||||
function normalizeOutputPath(
|
function normalizeOutputPath(
|
||||||
outputPath: string | undefined,
|
outputPath: string | undefined,
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
|
workspaceRoot: string,
|
||||||
path: 'coverage' | 'dist'
|
path: 'coverage' | 'dist'
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!outputPath) {
|
if (!outputPath) {
|
||||||
|
|||||||
@ -69,9 +69,12 @@ export const createNodes: CreateNodes<WebpackPluginOptions> = [
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = calculateHashForCreateNodes(projectRoot, options, context, [
|
const hash = await calculateHashForCreateNodes(
|
||||||
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
projectRoot,
|
||||||
]);
|
options,
|
||||||
|
context,
|
||||||
|
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
||||||
|
);
|
||||||
const targets = targetsCache[hash]
|
const targets = targetsCache[hash]
|
||||||
? targetsCache[hash]
|
? targetsCache[hash]
|
||||||
: await createWebpackTargets(
|
: await createWebpackTargets(
|
||||||
|
|||||||
34
scripts/unit-test-setup.js
Normal file
34
scripts/unit-test-setup.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module.exports = () => {
|
||||||
|
/**
|
||||||
|
* When the daemon is enabled during unit tests,
|
||||||
|
* and the daemon is already running, the daemon-client.ts
|
||||||
|
* code will be used, but it will hit the already running
|
||||||
|
* daemon which is from the installed version of Nx.
|
||||||
|
*
|
||||||
|
* In the vast majority of cases, this is fine. However,
|
||||||
|
* if a new message type has been added to the daemon in
|
||||||
|
* the source code, and isn't yet in the installed version,
|
||||||
|
* any test that hits that codepath will fail. This is because
|
||||||
|
* the installed version of the daemon doesn't know how to
|
||||||
|
* handle the new message type.
|
||||||
|
*
|
||||||
|
* To prevent this, we disable the daemon during unit tests.
|
||||||
|
*/
|
||||||
|
process.env.NX_DAEMON = 'false';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When `createProjectGraphAsync` is called during tests,
|
||||||
|
* if its not mocked, it will return the Nx repo's project
|
||||||
|
* graph. We don't want any unit tests to depend on the structure
|
||||||
|
* of the Nx repo, so we mock it to return an empty project graph.
|
||||||
|
*/
|
||||||
|
jest.doMock('@nx/devkit', () => ({
|
||||||
|
...jest.requireActual('@nx/devkit'),
|
||||||
|
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||||
|
return {
|
||||||
|
nodes: {},
|
||||||
|
dependencies: {},
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
};
|
||||||
@ -1,5 +1,13 @@
|
|||||||
|
const nxPreset = require('@nx/jest/preset').default;
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export default {
|
export default {
|
||||||
|
...nxPreset,
|
||||||
|
testTimeout: 35000,
|
||||||
|
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||||
|
coverageReporters: ['html'],
|
||||||
|
maxWorkers: 1,
|
||||||
|
testEnvironment: 'node',
|
||||||
displayName: 'typedoc-theme',
|
displayName: 'typedoc-theme',
|
||||||
|
|
||||||
globals: {},
|
globals: {},
|
||||||
@ -14,5 +22,5 @@ export default {
|
|||||||
resolver: '../scripts/patched-jest-resolver.js',
|
resolver: '../scripts/patched-jest-resolver.js',
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||||
coverageDirectory: '../coverage/typedoc-theme',
|
coverageDirectory: '../coverage/typedoc-theme',
|
||||||
preset: '../jest.preset.js',
|
setupFiles: [],
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user