Skip to content

Commit

Permalink
perf: asynchronously retrieve all collection info (schematics, genera…
Browse files Browse the repository at this point in the history
…tors, builders and executors) (#1160)
  • Loading branch information
Cammisuli authored Oct 22, 2021
1 parent 2cb1815 commit e193eb8
Show file tree
Hide file tree
Showing 23 changed files with 622 additions and 809 deletions.
24 changes: 15 additions & 9 deletions apps/vscode/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
getOutputChannel,
getTelemetry,
initTelemetry,
readAllGeneratorCollections,
getGenerators,
teardownTelemetry,
watchFile,
} from '@nx-console/server';
Expand All @@ -45,6 +45,7 @@ import {
NxProjectTreeProvider,
} from '@nx-console/vscode/nx-project-view';
import { environment } from './environments/environment';
import { Awaited } from '@nx-console/schema';

import {
WorkspaceJsonSchema,
Expand Down Expand Up @@ -276,7 +277,13 @@ async function setWorkspace(workspaceJsonPath: string) {

async function setApplicationAndLibraryContext(workspaceJsonPath: string) {
const { getNxConfig } = await import('@nx-console/vscode/nx-workspace');
const nxConfig = await getNxConfig(dirname(workspaceJsonPath));

let nxConfig: Awaited<ReturnType<typeof getNxConfig>>;
try {
nxConfig = await getNxConfig(dirname(workspaceJsonPath));
} catch {
return;
}

commands.executeCommand('setContext', 'nxAppsDir', [
join(
Expand All @@ -291,20 +298,19 @@ async function setApplicationAndLibraryContext(workspaceJsonPath: string) {
),
]);

const generatorCollections = await readAllGeneratorCollections(
workspaceJsonPath
);
const generatorCollections = await getGenerators(workspaceJsonPath);

let hasApplicationGenerators = false;
let hasLibraryGenerators = false;

generatorCollections.forEach((generatorCollection) => {
generatorCollection.generators.forEach((generator) => {
if (generator.type === 'application') {
if (generatorCollection.data) {
if (generatorCollection.data.type === 'application') {
hasApplicationGenerators = true;
} else if (generator.type === 'library') {
} else if (generatorCollection.data.type === 'library') {
hasLibraryGenerators = true;
}
});
}
});

commands.executeCommand(
Expand Down
18 changes: 16 additions & 2 deletions libs/schema/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ export interface TaskExecutionSchema {
contextValues?: Record<string, string | number | boolean | undefined>;
}

export interface GeneratorCollection {
export interface CollectionInfo {
name: string;
generators: Generator[];
path: string;
type: 'executor' | 'generator';
data?: Generator;
}

export enum GeneratorType {
Expand Down Expand Up @@ -94,3 +96,15 @@ export interface Targets {

export const WORKSPACE_GENERATOR_NAME_REGEX =
/^workspace-(schematic|generator):(.+)/;

/**
* Should be in Typescript 4.4+ remove this when we upgrade to that version
*/
export type Awaited<T> = T extends null | undefined
? T // special case for `null | undefined` when not in `--strictNullChecks` mode
: // eslint-disable-next-line @typescript-eslint/ban-types
T extends object & { then(onfulfilled: infer F): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
? F extends (value: infer V) => any // if the argument to `then` is callable, extracts the argument
? Awaited<V> // recursively unwrap the value
: never // the argument to `then` was not callable
: T;
8 changes: 4 additions & 4 deletions libs/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
export * from './lib/abstract-tree-provider';
export * from './lib/extensions';
export * from './lib/stores';
export * from './lib/select-generator';
export * from './lib/telemetry';
export * from './lib/utils/output-channel';
export * from './lib/utils/read-projects';
export * from './lib/utils/read-generator-collections';
export * from './lib/utils/get-generators';
export * from './lib/utils/get-executors';
export * from './lib/utils/read-collections';
export {
fileExistsSync,
readAndParseJson,
readAndCacheJsonFile,
normalizeSchema,
cacheJson,
clearJsonCache,
toWorkspaceFormat,
listOfUnnestedNpmPackages,
} from './lib/utils/utils';
export { watchFile } from './lib/utils/watch-file';
319 changes: 0 additions & 319 deletions libs/server/src/lib/extensions.ts

This file was deleted.

58 changes: 0 additions & 58 deletions libs/server/src/lib/select-generator.ts

This file was deleted.

14 changes: 14 additions & 0 deletions libs/server/src/lib/utils/get-executors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { CollectionInfo } from '@nx-console/schema';
import { readCollectionsFromNodeModules } from './read-collections';

export async function getExecutors(
workspaceJsonPath: string,
clearPackageJsonCache: boolean
): Promise<CollectionInfo[]> {
return (
await readCollectionsFromNodeModules(
workspaceJsonPath,
clearPackageJsonCache
)
).filter((collection) => collection.type === 'executor');
}
102 changes: 102 additions & 0 deletions libs/server/src/lib/utils/get-generators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { CollectionInfo, GeneratorType } from '@nx-console/schema';
import { basename, join } from 'path';

import {
directoryExists,
fileExistsSync,
listFiles,
normalizeSchema,
readAndCacheJsonFile,
} from './utils';
import {
getCollectionInfo,
readCollectionsFromNodeModules,
} from './read-collections';

export async function getGenerators(
workspaceJsonPath: string
): Promise<CollectionInfo[]> {
const basedir = join(workspaceJsonPath, '..');
const collections = await readCollectionsFromNodeModules(
workspaceJsonPath,
false
);
let generatorCollections = collections.filter(
(collection) => collection.type === 'generator'
);

generatorCollections = [
...generatorCollections,
...(await checkAndReadWorkspaceGenerators(
basedir,
join('tools', 'schematics')
)),
...(await checkAndReadWorkspaceGenerators(
basedir,
join('tools', 'generators')
)),
];
return generatorCollections.filter(
(collection): collection is CollectionInfo => !!collection.data
);
}

async function checkAndReadWorkspaceGenerators(
basedir: string,
workspaceGeneratorsPath: string
) {
if (await directoryExists(join(basedir, workspaceGeneratorsPath))) {
const collection = await readWorkspaceGeneratorsCollection(
basedir,
workspaceGeneratorsPath
);
return collection;
}
return Promise.resolve([]);
}

async function readWorkspaceGeneratorsCollection(
basedir: string,
workspaceGeneratorsPath: string
): Promise<CollectionInfo[]> {
const collectionDir = join(basedir, workspaceGeneratorsPath);
const collectionName = 'workspace-generator';
const collectionPath = join(collectionDir, 'collection.json');
if (fileExistsSync(collectionPath)) {
const collection = await readAndCacheJsonFile(
'collection.json',
collectionDir
);

return getCollectionInfo(
collectionName,
collectionPath,
collectionDir,
{},
collection.json
);
} else {
return await Promise.all(
listFiles(collectionDir)
.filter((f) => basename(f) === 'schema.json')
.map(async (f) => {
const schemaJson = await readAndCacheJsonFile(f, '');
const name = schemaJson.json.id || schemaJson.json.$id;
const type: GeneratorType =
schemaJson.json['x-type'] ?? GeneratorType.Other;
return {
name: collectionName,
type: 'generator',
path: collectionDir,
data: {
name,
collection: collectionName,
options: await normalizeSchema(schemaJson.json),
description: '',
type,
},
} as CollectionInfo;
})
);
}
}
Loading

0 comments on commit e193eb8

Please sign in to comment.