Skip to content

Commit

Permalink
chore(core): fixup sync apis
Browse files Browse the repository at this point in the history
  • Loading branch information
AgentEnder committed May 29, 2024
1 parent 26e3d76 commit d88b016
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 67 deletions.
4 changes: 4 additions & 0 deletions docs/generated/devkit/glob.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ Paths should be unix-style with forward slashes.
`string`[]

Normalized paths in the workspace that match the provided glob patterns.

**`Deprecated`**

Use globAsync instead.
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ async function addBundler(options: NormalizedOptions) {
options.isStandalone,
options.appIsJs
);
renameJsToJsx(options.reactAppName, options.isStandalone);
await renameJsToJsx(options.reactAppName, options.isStandalone);
} else {
output.log({ title: '🧑‍🔧 Setting up craco + Webpack' });
const { addCracoCommandsToPackageScripts } = await import(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { globWithWorkspaceContext } from '../../../../utils/workspace-context';
import { fileExists } from '../../../../utils/fileutils';

// Vite cannot process JSX like <div> or <Header> unless the file is named .jsx or .tsx
export function renameJsToJsx(appName: string, isStandalone: boolean) {
const files = globWithWorkspaceContext(process.cwd(), [
export async function renameJsToJsx(appName: string, isStandalone: boolean) {
const files = await globWithWorkspaceContext(process.cwd(), [
isStandalone ? 'src/**/*.js' : `apps/${appName}/src/**/*.js`,
]);

Expand Down
2 changes: 1 addition & 1 deletion packages/nx/src/command-line/init/init-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ async function detectPlugins(): Promise<{
updatePackageScripts: boolean;
}> {
let files = ['package.json'].concat(
globWithWorkspaceContext(process.cwd(), ['**/*/package.json'])
await globWithWorkspaceContext(process.cwd(), ['**/*/package.json'])
);

const detectedPlugins = new Set<string>();
Expand Down
2 changes: 1 addition & 1 deletion packages/nx/src/daemon/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export class DaemonClient {
return this.sendToDaemonViaQueue(message);
}

getFilesInDirectory(dir: string): Promise<FileData[]> {
getFilesInDirectory(dir: string): Promise<string[]> {
const message: HandleGetFilesInDirectoryMessage = {
type: GET_FILES_IN_DIRECTORY,
dir,
Expand Down
40 changes: 38 additions & 2 deletions packages/nx/src/generators/utils/glob.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { minimatch } from 'minimatch';
import { Tree } from '../tree';
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
Expand All @@ -11,9 +14,42 @@ import { globWithWorkspaceContext } from '../../utils/workspace-context';
* @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[] {
const matches = new Set(globWithWorkspaceContext(tree.root, patterns));
return combineGlobResultsWithTree(
tree,
patterns,
globWithWorkspaceContextSync(tree.root, patterns)
);
}

/**
* 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.
*/
export async function globAsync(
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 matcher = minimatch.makeRe(combinedGlob);
Expand Down
8 changes: 2 additions & 6 deletions packages/nx/src/generators/utils/project-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import { basename, join, relative } from 'path';
import {
buildProjectConfigurationFromPackageJson,
getGlobPatternsFromPackageManagerWorkspaces,
createNodes as packageJsonWorkspacesCreateNodes,
} from '../../plugins/package-json-workspaces';
import {
buildProjectFromProjectJson,
ProjectJsonProjectsPlugin,
} from '../../plugins/project-json/build-nodes/project-json';
import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
import {
Expand All @@ -19,16 +17,14 @@ import {
mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap,
} from '../../project-graph/utils/project-configuration-utils';
import { configurationGlobs } from '../../project-graph/utils/retrieve-workspace-files';
import { globWithWorkspaceContext } from '../../utils/workspace-context';
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
import { output } from '../../utils/output';
import { PackageJson } from '../../utils/package-json';
import { joinPathFragments, normalizePath } from '../../utils/path';
import { readJson, writeJson } from './json';
import { readNxJson } from './nx-json';

import type { Tree } from '../tree';
import { NxPlugin } from '../../project-graph/plugins';

export { readNxJson, updateNxJson } from './nx-json';

Expand Down Expand Up @@ -200,7 +196,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
readJson(tree, p, { expectComments: true })
),
];
const globbedFiles = globWithWorkspaceContext(tree.root, patterns);
const globbedFiles = globWithWorkspaceContextSync(tree.root, patterns);
const createdFiles = findCreatedProjectFiles(tree, patterns);
const deletedFiles = findDeletedProjectFiles(tree, patterns);
const projectFiles = [...globbedFiles, ...createdFiles].filter(
Expand Down
7 changes: 1 addition & 6 deletions packages/nx/src/project-graph/file-map-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ export async function createFileMapUsingProjectGraph(
): Promise<WorkspaceFileMap> {
const configs = readProjectsConfigurationFromProjectGraph(graph);

let files: FileData[];
if (daemonClient.enabled()) {
files = await daemonClient.getAllFileData();
} else {
files = getAllFileDataInContext(workspaceRoot);
}
let files: FileData[] = await getAllFileDataInContext(workspaceRoot);

return createFileMap(configs, files);
}
Expand Down
107 changes: 59 additions & 48 deletions packages/nx/src/project-graph/file-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { execSync } from 'child_process';
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 { FileData } from '../config/project-graph';
import {
Expand All @@ -17,16 +17,18 @@ import {
} from './project-graph';
import { toOldFormat } from '../adapter/angular-json';
import { getIgnoreObject } from '../utils/ignore';
import { retrieveProjectConfigurationPaths } from './utils/retrieve-workspace-files';
import {
mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap,
} from './utils/project-configuration-utils';
import { NxJsonConfiguration } from '../config/nx-json';
import { getDefaultPluginsSync } from '../utils/nx-plugin.deprecated';
import { minimatch } from 'minimatch';
import { CreateNodesResult } from '../devkit-exports';
import { PackageJsonProjectsNextToProjectJsonPlugin } from '../plugins/project-json/build-nodes/package-json-next-to-project-json';
import {
buildProjectConfigurationFromPackageJson,
getGlobPatternsFromPackageManagerWorkspaces,
} from '../plugins/package-json-workspaces';
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 {
type: string;
Expand Down Expand Up @@ -151,7 +153,7 @@ export function readWorkspaceConfig(opts: {
} catch {
configuration = {
version: 2,
projects: getProjectsSyncNoInference(root, nxJson).projects,
projects: getProjectsSync(root, nxJson),
};
}
if (opts.format === 'angularCli') {
Expand Down Expand Up @@ -179,50 +181,59 @@ export { FileData };
/**
* TODO(v20): Remove this function.
*/
function getProjectsSyncNoInference(root: string, nxJson: NxJsonConfiguration) {
const allConfigFiles = retrieveProjectConfigurationPaths(
root,
getDefaultPluginsSync(root)
);
const plugins = [
PackageJsonProjectsNextToProjectJsonPlugin,
...getDefaultPluginsSync(root),
function getProjectsSync(
root: string,
nxJson: NxJsonConfiguration
): {
[name: string]: ProjectConfiguration;
} {
/**
* 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 projectRootMap: Record<string, ProjectConfiguration> = {};

// We iterate over plugins first - this ensures that plugins specified first take precedence.
for (const plugin of plugins) {
const [pattern, createNodes] = plugin.createNodes ?? [];
if (!pattern) {
continue;
}
const matchingConfigFiles = allConfigFiles.filter((file) =>
minimatch(file, pattern, { dot: true })
);
for (const file of matchingConfigFiles) {
if (minimatch(file, pattern, { dot: true })) {
let r = createNodes(
file,
{},
const projectFiles = globWithWorkspaceContextSync(root, patterns);

const rootMap: Record<string, ProjectConfiguration> = {};
for (const projectFile of projectFiles) {
if (basename(projectFile) === 'project.json') {
const json = readJsonFile(projectFile);
const config = buildProjectFromProjectJson(json, projectFile);
mergeProjectConfigurationIntoRootMap(
rootMap,
config,
undefined,
undefined,
true
);
} else if (basename(projectFile) === 'package.json') {
const packageJson = readJsonFile<PackageJson>(projectFile);
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,
workspaceRoot: root,
configFiles: matchingConfigFiles,
}
) as CreateNodesResult;
for (const node in r.projects) {
const project = {
root: node,
...r.projects[node],
};
mergeProjectConfigurationIntoRootMap(projectRootMap, project);
}
name: config.name,
root: config.root,
},
undefined,
undefined,
true
);
}
}
}

return {
projects: readProjectConfigurationsFromRootMap(projectRootMap),
};
return readProjectConfigurationsFromRootMap(rootMap);
}
16 changes: 16 additions & 0 deletions packages/nx/src/utils/workspace-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ export async function getNxWorkspaceFilesFromContext(
return daemonClient.getWorkspaceFiles(projectRootMap);
}

/**
* 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,
globs: string[],
exclude?: string[]
) {
ensureContextAvailable(workspaceRoot);
return workspaceContext.glob(globs, exclude);
}

export async function globWithWorkspaceContext(
workspaceRoot: string,
globs: string[],
Expand Down

0 comments on commit d88b016

Please sign in to comment.