feat(core): use custom resolution to resolve from source local plugins with artifacts pointing to the outputs (#29222)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> Local Nx plugins in the new TS setup can't be resolved properly if they aren't built first. Graph plugins can't be built either because the graph is needed to run a task, but the plugin must be built to construct the graph. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Local Nx plugins should work in the new TS setup. A custom resolution is added to resolve the local plugin artifacts from the source. It will try to use a `development` condition from the `exports` entry in `package.json` if it exists. If it doesn't, it will fall back to guess the source based on the artifact path and some commonly known/used source dirs: `.`, `./src`, `./src/lib`. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
5bdda1daac
commit
48cd50a550
@ -8,7 +8,7 @@ A node describing a project in a workspace
|
|||||||
|
|
||||||
- [data](../../devkit/documents/ProjectGraphProjectNode#data): ProjectConfiguration & Object
|
- [data](../../devkit/documents/ProjectGraphProjectNode#data): ProjectConfiguration & Object
|
||||||
- [name](../../devkit/documents/ProjectGraphProjectNode#name): string
|
- [name](../../devkit/documents/ProjectGraphProjectNode#name): string
|
||||||
- [type](../../devkit/documents/ProjectGraphProjectNode#type): "app" | "e2e" | "lib"
|
- [type](../../devkit/documents/ProjectGraphProjectNode#type): "lib" | "app" | "e2e"
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
@ -28,4 +28,4 @@ Additional metadata about a project
|
|||||||
|
|
||||||
### type
|
### type
|
||||||
|
|
||||||
• **type**: `"app"` \| `"e2e"` \| `"lib"`
|
• **type**: `"lib"` \| `"app"` \| `"e2e"`
|
||||||
|
|||||||
193
e2e/plugin/src/nx-plugin-ts-solution.test.ts
Normal file
193
e2e/plugin/src/nx-plugin-ts-solution.test.ts
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
createFile,
|
||||||
|
newProject,
|
||||||
|
renameFile,
|
||||||
|
runCLI,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
import {
|
||||||
|
ASYNC_GENERATOR_EXECUTOR_CONTENTS,
|
||||||
|
NX_PLUGIN_V2_CONTENTS,
|
||||||
|
} from './nx-plugin.fixtures';
|
||||||
|
|
||||||
|
describe('Nx Plugin (TS solution)', () => {
|
||||||
|
let workspaceName: string;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
workspaceName = newProject({ preset: 'ts', packages: ['@nx/plugin'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
|
it('should be able to infer projects and targets', async () => {
|
||||||
|
const plugin = uniq('plugin');
|
||||||
|
runCLI(`generate @nx/plugin:plugin packages/${plugin}`);
|
||||||
|
|
||||||
|
// Setup project inference + target inference
|
||||||
|
updateFile(`packages/${plugin}/src/index.ts`, NX_PLUGIN_V2_CONTENTS);
|
||||||
|
|
||||||
|
// Register plugin in nx.json (required for inference)
|
||||||
|
updateJson(`nx.json`, (nxJson) => {
|
||||||
|
nxJson.plugins = [
|
||||||
|
{
|
||||||
|
plugin: `@${workspaceName}/${plugin}`,
|
||||||
|
options: { inferredTags: ['my-tag'] },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return nxJson;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create project that should be inferred by Nx
|
||||||
|
const inferredProject = uniq('inferred');
|
||||||
|
createFile(
|
||||||
|
`packages/${inferredProject}/package.json`,
|
||||||
|
JSON.stringify({
|
||||||
|
name: inferredProject,
|
||||||
|
version: '0.0.1',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
createFile(`packages/${inferredProject}/my-project-file`);
|
||||||
|
|
||||||
|
// Attempt to use inferred project w/ Nx
|
||||||
|
expect(runCLI(`build ${inferredProject}`)).toContain(
|
||||||
|
'custom registered target'
|
||||||
|
);
|
||||||
|
const configuration = JSON.parse(
|
||||||
|
runCLI(`show project ${inferredProject} --json`)
|
||||||
|
);
|
||||||
|
expect(configuration.tags).toContain('my-tag');
|
||||||
|
expect(configuration.metadata.technologies).toEqual(['my-plugin']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to use local generators and executors', async () => {
|
||||||
|
const plugin = uniq('plugin');
|
||||||
|
const generator = uniq('generator');
|
||||||
|
const executor = uniq('executor');
|
||||||
|
const generatedProject = uniq('project');
|
||||||
|
|
||||||
|
runCLI(`generate @nx/plugin:plugin packages/${plugin}`);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/plugin:generator --name ${generator} --path packages/${plugin}/src/generators/${generator}/generator`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/plugin:executor --name ${executor} --path packages/${plugin}/src/executors/${executor}/executor`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`packages/${plugin}/src/executors/${executor}/executor.ts`,
|
||||||
|
ASYNC_GENERATOR_EXECUTOR_CONTENTS
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @${workspaceName}/${plugin}:${generator} --name ${generatedProject}`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(`libs/${generatedProject}/project.json`, (project) => {
|
||||||
|
project.targets['execute'] = {
|
||||||
|
executor: `@${workspaceName}/${plugin}:${executor}`,
|
||||||
|
};
|
||||||
|
return project;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() => checkFilesExist(`libs/${generatedProject}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`execute ${generatedProject}`)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to resolve local generators and executors using package.json development condition export', async () => {
|
||||||
|
const plugin = uniq('plugin');
|
||||||
|
const generator = uniq('generator');
|
||||||
|
const executor = uniq('executor');
|
||||||
|
const generatedProject = uniq('project');
|
||||||
|
|
||||||
|
runCLI(`generate @nx/plugin:plugin packages/${plugin}`);
|
||||||
|
|
||||||
|
// move/generate everything in the "code" folder, which is not a standard location and wouldn't
|
||||||
|
// be considered by the fall back resolution logic, so the only way it could be resolved is if
|
||||||
|
// the development condition export is used
|
||||||
|
renameFile(
|
||||||
|
`packages/${plugin}/src/index.ts`,
|
||||||
|
`packages/${plugin}/code/index.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/plugin:generator --name ${generator} --path packages/${plugin}/code/generators/${generator}/generator`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/plugin:executor --name ${executor} --path packages/${plugin}/code/executors/${executor}/executor`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(`packages/${plugin}/package.json`, (pkg) => {
|
||||||
|
pkg.nx.sourceRoot = `packages/${plugin}/code`;
|
||||||
|
pkg.nx.targets.build.options.main = `packages/${plugin}/code/index.ts`;
|
||||||
|
pkg.nx.targets.build.options.rootDir = `packages/${plugin}/code`;
|
||||||
|
pkg.nx.targets.build.options.assets.forEach(
|
||||||
|
(asset: { input: string }) => {
|
||||||
|
asset.input = `./packages/${plugin}/code`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
pkg.exports = {
|
||||||
|
'.': {
|
||||||
|
types: './dist/index.d.ts',
|
||||||
|
development: './code/index.ts',
|
||||||
|
default: './dist/index.js',
|
||||||
|
},
|
||||||
|
'./package.json': './package.json',
|
||||||
|
'./generators.json': {
|
||||||
|
development: './generators.json',
|
||||||
|
default: './generators.json',
|
||||||
|
},
|
||||||
|
'./executors.json': './executors.json',
|
||||||
|
'./dist/generators/*/schema.json': {
|
||||||
|
development: './code/generators/*/schema.json',
|
||||||
|
default: './dist/generators/*/schema.json',
|
||||||
|
},
|
||||||
|
'./dist/generators/*/generator': {
|
||||||
|
types: './dist/generators/*/generator.d.ts',
|
||||||
|
development: './code/generators/*/generator.ts',
|
||||||
|
default: './dist/generators/*/generator.js',
|
||||||
|
},
|
||||||
|
'./dist/executors/*/schema.json': {
|
||||||
|
development: './code/executors/*/schema.json',
|
||||||
|
default: './dist/executors/*/schema.json',
|
||||||
|
},
|
||||||
|
'./dist/executors/*/executor': {
|
||||||
|
types: './dist/executors/*/executor.d.ts',
|
||||||
|
development: './code/executors/*/executor.ts',
|
||||||
|
default: './dist/executors/*/executor.js',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return pkg;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateJson(`packages/${plugin}/tsconfig.lib.json`, (tsconfig) => {
|
||||||
|
tsconfig.compilerOptions.rootDir = 'code';
|
||||||
|
tsconfig.include = ['code/**/*.ts'];
|
||||||
|
return tsconfig;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`packages/${plugin}/code/executors/${executor}/executor.ts`,
|
||||||
|
ASYNC_GENERATOR_EXECUTOR_CONTENTS
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @${workspaceName}/${plugin}:${generator} --name ${generatedProject}`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(`libs/${generatedProject}/project.json`, (project) => {
|
||||||
|
project.targets['execute'] = {
|
||||||
|
executor: `@${workspaceName}/${plugin}:${executor}`,
|
||||||
|
};
|
||||||
|
return project;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() => checkFilesExist(`libs/${generatedProject}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`execute ${generatedProject}`)).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -272,7 +272,7 @@
|
|||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-textarea-autosize": "^8.5.3",
|
"react-textarea-autosize": "^8.5.3",
|
||||||
"regenerator-runtime": "0.13.7",
|
"regenerator-runtime": "0.13.7",
|
||||||
"resolve.exports": "1.1.0",
|
"resolve.exports": "2.0.3",
|
||||||
"rollup": "^4.14.0",
|
"rollup": "^4.14.0",
|
||||||
"rollup-plugin-copy": "^3.5.0",
|
"rollup-plugin-copy": "^3.5.0",
|
||||||
"rollup-plugin-postcss": "^4.0.2",
|
"rollup-plugin-postcss": "^4.0.2",
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
"jest-resolve": "^29.4.1",
|
"jest-resolve": "^29.4.1",
|
||||||
"jest-util": "^29.4.1",
|
"jest-util": "^29.4.1",
|
||||||
"minimatch": "9.0.3",
|
"minimatch": "9.0.3",
|
||||||
"resolve.exports": "1.1.0",
|
"resolve.exports": "2.0.3",
|
||||||
"semver": "^7.5.3",
|
"semver": "^7.5.3",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"yargs-parser": "21.1.1"
|
"yargs-parser": "21.1.1"
|
||||||
|
|||||||
@ -50,7 +50,7 @@ module.exports = function (path: string, options: ResolverOptions) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolveExports(pkg, path) || path;
|
return resolveExports(pkg, path)?.[0] || path;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,7 @@
|
|||||||
"npm-run-path": "^4.0.1",
|
"npm-run-path": "^4.0.1",
|
||||||
"open": "^8.4.0",
|
"open": "^8.4.0",
|
||||||
"ora": "5.3.0",
|
"ora": "5.3.0",
|
||||||
|
"resolve.exports": "2.0.3",
|
||||||
"semver": "^7.5.3",
|
"semver": "^7.5.3",
|
||||||
"string-width": "^4.2.3",
|
"string-width": "^4.2.3",
|
||||||
"tar-stream": "~2.2.0",
|
"tar-stream": "~2.2.0",
|
||||||
|
|||||||
@ -1183,7 +1183,9 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
|
|||||||
optionSchema: builderInfo.schema,
|
optionSchema: builderInfo.schema,
|
||||||
import: resolveImplementation(
|
import: resolveImplementation(
|
||||||
executorConfig.implementation,
|
executorConfig.implementation,
|
||||||
dirname(executorsFilePath)
|
dirname(executorsFilePath),
|
||||||
|
packageName,
|
||||||
|
this.projects
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1240,25 +1242,33 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
|
|||||||
const { executorsFilePath, executorConfig, isNgCompat } =
|
const { executorsFilePath, executorConfig, isNgCompat } =
|
||||||
this.readExecutorsJson(nodeModule, executor);
|
this.readExecutorsJson(nodeModule, executor);
|
||||||
const executorsDir = dirname(executorsFilePath);
|
const executorsDir = dirname(executorsFilePath);
|
||||||
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
|
const schemaPath = resolveSchema(
|
||||||
|
executorConfig.schema,
|
||||||
|
executorsDir,
|
||||||
|
nodeModule,
|
||||||
|
this.projects
|
||||||
|
);
|
||||||
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
||||||
|
|
||||||
const implementationFactory = this.getImplementationFactory<Executor>(
|
const implementationFactory = this.getImplementationFactory<Executor>(
|
||||||
executorConfig.implementation,
|
executorConfig.implementation,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule
|
||||||
);
|
);
|
||||||
|
|
||||||
const batchImplementationFactory = executorConfig.batchImplementation
|
const batchImplementationFactory = executorConfig.batchImplementation
|
||||||
? this.getImplementationFactory<TaskGraphExecutor>(
|
? this.getImplementationFactory<TaskGraphExecutor>(
|
||||||
executorConfig.batchImplementation,
|
executorConfig.batchImplementation,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const hasherFactory = executorConfig.hasher
|
const hasherFactory = executorConfig.hasher
|
||||||
? this.getImplementationFactory<CustomHasher>(
|
? this.getImplementationFactory<CustomHasher>(
|
||||||
executorConfig.hasher,
|
executorConfig.hasher,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@ -1278,9 +1288,15 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
|
|||||||
|
|
||||||
private getImplementationFactory<T>(
|
private getImplementationFactory<T>(
|
||||||
implementation: string,
|
implementation: string,
|
||||||
executorsDir: string
|
executorsDir: string,
|
||||||
|
packageName: string
|
||||||
): () => T {
|
): () => T {
|
||||||
return getImplementationFactory(implementation, executorsDir);
|
return getImplementationFactory(
|
||||||
|
implementation,
|
||||||
|
executorsDir,
|
||||||
|
packageName,
|
||||||
|
this.projects
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,12 @@ export function getGeneratorInformation(
|
|||||||
generatorsJson.generators?.[normalizedGeneratorName] ||
|
generatorsJson.generators?.[normalizedGeneratorName] ||
|
||||||
generatorsJson.schematics?.[normalizedGeneratorName];
|
generatorsJson.schematics?.[normalizedGeneratorName];
|
||||||
const isNgCompat = !generatorsJson.generators?.[normalizedGeneratorName];
|
const isNgCompat = !generatorsJson.generators?.[normalizedGeneratorName];
|
||||||
const schemaPath = resolveSchema(generatorConfig.schema, generatorsDir);
|
const schemaPath = resolveSchema(
|
||||||
|
generatorConfig.schema,
|
||||||
|
generatorsDir,
|
||||||
|
collectionName,
|
||||||
|
projects
|
||||||
|
);
|
||||||
const schema = readJsonFile(schemaPath);
|
const schema = readJsonFile(schemaPath);
|
||||||
if (!schema.properties || typeof schema.properties !== 'object') {
|
if (!schema.properties || typeof schema.properties !== 'object') {
|
||||||
schema.properties = {};
|
schema.properties = {};
|
||||||
@ -49,7 +54,9 @@ export function getGeneratorInformation(
|
|||||||
generatorConfig.implementation || generatorConfig.factory;
|
generatorConfig.implementation || generatorConfig.factory;
|
||||||
const implementationFactory = getImplementationFactory<Generator>(
|
const implementationFactory = getImplementationFactory<Generator>(
|
||||||
generatorConfig.implementation,
|
generatorConfig.implementation,
|
||||||
generatorsDir
|
generatorsDir,
|
||||||
|
collectionName,
|
||||||
|
projects
|
||||||
);
|
);
|
||||||
const normalizedGeneratorConfiguration: GeneratorsJsonEntry = {
|
const normalizedGeneratorConfiguration: GeneratorsJsonEntry = {
|
||||||
...generatorConfig,
|
...generatorConfig,
|
||||||
|
|||||||
@ -55,25 +55,36 @@ export function getExecutorInformation(
|
|||||||
projects
|
projects
|
||||||
);
|
);
|
||||||
const executorsDir = dirname(executorsFilePath);
|
const executorsDir = dirname(executorsFilePath);
|
||||||
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
|
const schemaPath = resolveSchema(
|
||||||
|
executorConfig.schema,
|
||||||
|
executorsDir,
|
||||||
|
nodeModule,
|
||||||
|
projects
|
||||||
|
);
|
||||||
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));
|
||||||
|
|
||||||
const implementationFactory = getImplementationFactory<Executor>(
|
const implementationFactory = getImplementationFactory<Executor>(
|
||||||
executorConfig.implementation,
|
executorConfig.implementation,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule,
|
||||||
|
projects
|
||||||
);
|
);
|
||||||
|
|
||||||
const batchImplementationFactory = executorConfig.batchImplementation
|
const batchImplementationFactory = executorConfig.batchImplementation
|
||||||
? getImplementationFactory<TaskGraphExecutor>(
|
? getImplementationFactory<TaskGraphExecutor>(
|
||||||
executorConfig.batchImplementation,
|
executorConfig.batchImplementation,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule,
|
||||||
|
projects
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const hasherFactory = executorConfig.hasher
|
const hasherFactory = executorConfig.hasher
|
||||||
? getImplementationFactory<CustomHasher>(
|
? getImplementationFactory<CustomHasher>(
|
||||||
executorConfig.hasher,
|
executorConfig.hasher,
|
||||||
executorsDir
|
executorsDir,
|
||||||
|
nodeModule,
|
||||||
|
projects
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { extname, join } from 'path';
|
import { extname, join } from 'path';
|
||||||
|
import { resolve as resolveExports } from 'resolve.exports';
|
||||||
|
import { getPackageEntryPointsToProjectMap } from '../plugins/js/utils/packages';
|
||||||
import { registerPluginTSTranspiler } from '../project-graph/plugins';
|
import { registerPluginTSTranspiler } from '../project-graph/plugins';
|
||||||
|
import { normalizePath } from '../utils/path';
|
||||||
|
import type { ProjectConfiguration } from './workspace-json-project-json';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used to get the implementation factory of an executor or generator.
|
* This function is used to get the implementation factory of an executor or generator.
|
||||||
@ -10,14 +14,18 @@ import { registerPluginTSTranspiler } from '../project-graph/plugins';
|
|||||||
*/
|
*/
|
||||||
export function getImplementationFactory<T>(
|
export function getImplementationFactory<T>(
|
||||||
implementation: string,
|
implementation: string,
|
||||||
directory: string
|
directory: string,
|
||||||
|
packageName: string,
|
||||||
|
projects: Record<string, ProjectConfiguration>
|
||||||
): () => T {
|
): () => T {
|
||||||
const [implementationModulePath, implementationExportName] =
|
const [implementationModulePath, implementationExportName] =
|
||||||
implementation.split('#');
|
implementation.split('#');
|
||||||
return () => {
|
return () => {
|
||||||
const modulePath = resolveImplementation(
|
const modulePath = resolveImplementation(
|
||||||
implementationModulePath,
|
implementationModulePath,
|
||||||
directory
|
directory,
|
||||||
|
packageName,
|
||||||
|
projects
|
||||||
);
|
);
|
||||||
if (extname(modulePath) === '.ts') {
|
if (extname(modulePath) === '.ts') {
|
||||||
registerPluginTSTranspiler();
|
registerPluginTSTranspiler();
|
||||||
@ -37,12 +45,31 @@ export function getImplementationFactory<T>(
|
|||||||
*/
|
*/
|
||||||
export function resolveImplementation(
|
export function resolveImplementation(
|
||||||
implementationModulePath: string,
|
implementationModulePath: string,
|
||||||
directory: string
|
directory: string,
|
||||||
|
packageName: string,
|
||||||
|
projects: Record<string, ProjectConfiguration>
|
||||||
): string {
|
): string {
|
||||||
const validImplementations = ['', '.js', '.ts'].map(
|
const validImplementations = ['', '.js', '.ts'].map(
|
||||||
(x) => implementationModulePath + x
|
(x) => implementationModulePath + x
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!directory.includes('node_modules')) {
|
||||||
|
// It might be a local plugin where the implementation path points to the
|
||||||
|
// outputs which might not exist or can be stale. We prioritize finding
|
||||||
|
// the implementation from the source over the outputs.
|
||||||
|
for (const maybeImplementation of validImplementations) {
|
||||||
|
const maybeImplementationFromSource = tryResolveFromSource(
|
||||||
|
maybeImplementation,
|
||||||
|
directory,
|
||||||
|
packageName,
|
||||||
|
projects
|
||||||
|
);
|
||||||
|
if (maybeImplementationFromSource) {
|
||||||
|
return maybeImplementationFromSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const maybeImplementation of validImplementations) {
|
for (const maybeImplementation of validImplementations) {
|
||||||
const maybeImplementationPath = join(directory, maybeImplementation);
|
const maybeImplementationPath = join(directory, maybeImplementation);
|
||||||
if (existsSync(maybeImplementationPath)) {
|
if (existsSync(maybeImplementationPath)) {
|
||||||
@ -61,7 +88,27 @@ export function resolveImplementation(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveSchema(schemaPath: string, directory: string): string {
|
export function resolveSchema(
|
||||||
|
schemaPath: string,
|
||||||
|
directory: string,
|
||||||
|
packageName: string,
|
||||||
|
projects: Record<string, ProjectConfiguration>
|
||||||
|
): string {
|
||||||
|
if (!directory.includes('node_modules')) {
|
||||||
|
// It might be a local plugin where the schema path points to the outputs
|
||||||
|
// which might not exist or can be stale. We prioritize finding the schema
|
||||||
|
// from the source over the outputs.
|
||||||
|
const schemaPathFromSource = tryResolveFromSource(
|
||||||
|
schemaPath,
|
||||||
|
directory,
|
||||||
|
packageName,
|
||||||
|
projects
|
||||||
|
);
|
||||||
|
if (schemaPathFromSource) {
|
||||||
|
return schemaPathFromSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const maybeSchemaPath = join(directory, schemaPath);
|
const maybeSchemaPath = join(directory, schemaPath);
|
||||||
if (existsSync(maybeSchemaPath)) {
|
if (existsSync(maybeSchemaPath)) {
|
||||||
return maybeSchemaPath;
|
return maybeSchemaPath;
|
||||||
@ -71,3 +118,60 @@ export function resolveSchema(schemaPath: string, directory: string): string {
|
|||||||
paths: [directory],
|
paths: [directory],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let packageEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
||||||
|
function tryResolveFromSource(
|
||||||
|
path: string,
|
||||||
|
directory: string,
|
||||||
|
packageName: string,
|
||||||
|
projects: Record<string, ProjectConfiguration>
|
||||||
|
): string | null {
|
||||||
|
packageEntryPointsToProjectMap ??=
|
||||||
|
getPackageEntryPointsToProjectMap(projects);
|
||||||
|
const localProject = packageEntryPointsToProjectMap[packageName];
|
||||||
|
if (!localProject) {
|
||||||
|
// it doesn't match any of the package names from the local projects
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fromExports = resolveExports(
|
||||||
|
{
|
||||||
|
name: localProject.metadata!.js!.packageName,
|
||||||
|
exports: localProject.metadata!.js!.packageExports,
|
||||||
|
},
|
||||||
|
path,
|
||||||
|
{ conditions: ['development'] }
|
||||||
|
);
|
||||||
|
if (fromExports && fromExports.length) {
|
||||||
|
for (const exportPath of fromExports) {
|
||||||
|
if (existsSync(join(directory, exportPath))) {
|
||||||
|
return join(directory, exportPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fall back to try to "guess" the source by checking the path in some common directories:
|
||||||
|
* - the root of the project
|
||||||
|
* - the src directory
|
||||||
|
* - the src/lib directory
|
||||||
|
*/
|
||||||
|
const segments = normalizePath(path).replace(/^\.\//, '').split('/');
|
||||||
|
for (let i = 1; i < segments.length; i++) {
|
||||||
|
const possiblePaths = [
|
||||||
|
join(directory, ...segments.slice(i)),
|
||||||
|
join(directory, 'src', ...segments.slice(i)),
|
||||||
|
join(directory, 'src', 'lib', ...segments.slice(i)),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const possiblePath of possiblePaths) {
|
||||||
|
if (existsSync(possiblePath)) {
|
||||||
|
return possiblePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@ -57,6 +57,9 @@ describe('Workspaces', () => {
|
|||||||
{
|
{
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "my-package description",
|
"description": "my-package description",
|
||||||
|
"js": {
|
||||||
|
"packageName": "my-package",
|
||||||
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
},
|
},
|
||||||
"name": "my-package",
|
"name": "my-package",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { PackageJson } from '../utils/package-json';
|
||||||
import type {
|
import type {
|
||||||
NxJsonConfiguration,
|
NxJsonConfiguration,
|
||||||
NxReleaseVersionConfiguration,
|
NxReleaseVersionConfiguration,
|
||||||
@ -136,6 +137,10 @@ export interface ProjectMetadata {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
js?: {
|
||||||
|
packageName: string;
|
||||||
|
packageExports: undefined | PackageJson['exports'];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TargetMetadata {
|
export interface TargetMetadata {
|
||||||
|
|||||||
26
packages/nx/src/plugins/js/utils/packages.ts
Normal file
26
packages/nx/src/plugins/js/utils/packages.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { join } from 'node:path/posix';
|
||||||
|
import type { ProjectConfiguration } from '../../../config/workspace-json-project-json';
|
||||||
|
|
||||||
|
export function getPackageEntryPointsToProjectMap(
|
||||||
|
projects: Record<string, ProjectConfiguration>
|
||||||
|
): Record<string, ProjectConfiguration> {
|
||||||
|
const result: Record<string, ProjectConfiguration> = {};
|
||||||
|
for (const project of Object.values(projects)) {
|
||||||
|
if (!project.metadata?.js) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { packageName, packageExports } = project.metadata.js;
|
||||||
|
if (!packageExports || typeof packageExports === 'string') {
|
||||||
|
// no `exports` or it points to a file, which would be the equivalent of
|
||||||
|
// an '.' export, in which case the package name is the entry point
|
||||||
|
result[packageName] = project;
|
||||||
|
} else {
|
||||||
|
for (const entryPoint of Object.keys(packageExports)) {
|
||||||
|
result[join(packageName, entryPoint)] = project;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@ -55,6 +55,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
".": {
|
".": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "root",
|
||||||
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
"NPM Scripts": [
|
"NPM Scripts": [
|
||||||
"echo",
|
"echo",
|
||||||
@ -98,6 +102,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/lib-a": {
|
"packages/lib-a": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "lib-a description",
|
"description": "lib-a description",
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "lib-a",
|
||||||
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
"NPM Scripts": [
|
"NPM Scripts": [
|
||||||
"test",
|
"test",
|
||||||
@ -148,6 +156,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "lib-b description",
|
"description": "lib-b description",
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "lib-b",
|
||||||
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
"NPM Scripts": [
|
"NPM Scripts": [
|
||||||
"build",
|
"build",
|
||||||
@ -252,6 +264,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/vite": {
|
"packages/vite": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "vite",
|
||||||
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
},
|
},
|
||||||
"name": "vite",
|
"name": "vite",
|
||||||
@ -350,6 +366,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/vite": {
|
"packages/vite": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "vite",
|
||||||
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
},
|
},
|
||||||
"name": "vite",
|
"name": "vite",
|
||||||
@ -444,6 +464,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/vite": {
|
"packages/vite": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "vite",
|
||||||
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
},
|
},
|
||||||
"name": "vite",
|
"name": "vite",
|
||||||
@ -522,6 +546,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/a": {
|
"packages/a": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "root",
|
||||||
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
"NPM Scripts": [
|
"NPM Scripts": [
|
||||||
"build",
|
"build",
|
||||||
@ -600,6 +628,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/a": {
|
"packages/a": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "root",
|
||||||
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
"NPM Scripts": [
|
"NPM Scripts": [
|
||||||
"build",
|
"build",
|
||||||
@ -685,6 +717,10 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"packages/a": {
|
"packages/a": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
|
"js": {
|
||||||
|
"packageExports": undefined,
|
||||||
|
"packageName": "root",
|
||||||
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
},
|
},
|
||||||
"name": "root",
|
"name": "root",
|
||||||
@ -796,4 +832,72 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
].projectType
|
].projectType
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should store package name and exports in the project metadata', () => {
|
||||||
|
vol.fromJSON(
|
||||||
|
{
|
||||||
|
'packages/lib-a/package.json': JSON.stringify({
|
||||||
|
name: 'lib-a',
|
||||||
|
description: 'lib-a description',
|
||||||
|
scripts: { test: 'jest' },
|
||||||
|
exports: {
|
||||||
|
'./package.json': './package.json',
|
||||||
|
'.': './dist/index.js',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
'/root'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
createNodeFromPackageJson('packages/lib-a/package.json', '/root', {})
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"packages/lib-a": {
|
||||||
|
"metadata": {
|
||||||
|
"description": "lib-a description",
|
||||||
|
"js": {
|
||||||
|
"packageExports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
},
|
||||||
|
"packageName": "lib-a",
|
||||||
|
},
|
||||||
|
"targetGroups": {
|
||||||
|
"NPM Scripts": [
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"name": "lib-a",
|
||||||
|
"root": "packages/lib-a",
|
||||||
|
"sourceRoot": "packages/lib-a",
|
||||||
|
"tags": [
|
||||||
|
"npm:public",
|
||||||
|
],
|
||||||
|
"targets": {
|
||||||
|
"nx-release-publish": {
|
||||||
|
"dependsOn": [
|
||||||
|
"^nx-release-publish",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:release-publish",
|
||||||
|
"options": {},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "nx:run-script",
|
||||||
|
"metadata": {
|
||||||
|
"runCommand": "npm run test",
|
||||||
|
"scriptContent": "jest",
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"script": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -138,6 +138,12 @@ export function createNodeFromPackageJson(
|
|||||||
const hash = hashObject({
|
const hash = hashObject({
|
||||||
...json,
|
...json,
|
||||||
root: projectRoot,
|
root: projectRoot,
|
||||||
|
/**
|
||||||
|
* Increment this number to force processing the package.json again. Do it
|
||||||
|
* when the implementation of this plugin is changed and results in different
|
||||||
|
* results for the same package.json contents.
|
||||||
|
*/
|
||||||
|
bust: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const cached = cache[hash];
|
const cached = cache[hash];
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { LoadPluginError } from '../error-types';
|
|||||||
import path = require('node:path/posix');
|
import path = require('node:path/posix');
|
||||||
import { readTsConfig } from '../../plugins/js/utils/typescript';
|
import { readTsConfig } from '../../plugins/js/utils/typescript';
|
||||||
import { loadResolvedNxPluginAsync } from './load-resolved-plugin';
|
import { loadResolvedNxPluginAsync } from './load-resolved-plugin';
|
||||||
|
import { getPackageEntryPointsToProjectMap } from '../../plugins/js/utils/packages';
|
||||||
|
|
||||||
export function readPluginPackageJson(
|
export function readPluginPackageJson(
|
||||||
pluginName: string,
|
pluginName: string,
|
||||||
@ -124,39 +125,49 @@ function lookupLocalPlugin(
|
|||||||
return { path: path.join(root, projectConfig.root), projectConfig };
|
return { path: path.join(root, projectConfig.root), projectConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let packageEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
||||||
function findNxProjectForImportPath(
|
function findNxProjectForImportPath(
|
||||||
importPath: string,
|
importPath: string,
|
||||||
projects: Record<string, ProjectConfiguration>,
|
projects: Record<string, ProjectConfiguration>,
|
||||||
root = workspaceRoot
|
root = workspaceRoot
|
||||||
): ProjectConfiguration | null {
|
): ProjectConfiguration | null {
|
||||||
const tsConfigPaths: Record<string, string[]> = readTsConfigPaths(root);
|
const tsConfigPaths: Record<string, string[]> = readTsConfigPaths(root);
|
||||||
const possiblePaths = tsConfigPaths[importPath]?.map((p) =>
|
const possibleTsPaths =
|
||||||
|
tsConfigPaths[importPath]?.map((p) =>
|
||||||
normalizePath(path.relative(root, path.join(root, p)))
|
normalizePath(path.relative(root, path.join(root, p)))
|
||||||
);
|
) ?? [];
|
||||||
if (possiblePaths?.length) {
|
|
||||||
const projectRootMappings: ProjectRootMappings = new Map();
|
const projectRootMappings: ProjectRootMappings = new Map();
|
||||||
|
if (possibleTsPaths.length) {
|
||||||
const projectNameMap = new Map<string, ProjectConfiguration>();
|
const projectNameMap = new Map<string, ProjectConfiguration>();
|
||||||
for (const projectRoot in projects) {
|
for (const projectRoot in projects) {
|
||||||
const project = projects[projectRoot];
|
const project = projects[projectRoot];
|
||||||
projectRootMappings.set(project.root, project.name);
|
projectRootMappings.set(project.root, project.name);
|
||||||
projectNameMap.set(project.name, project);
|
projectNameMap.set(project.name, project);
|
||||||
}
|
}
|
||||||
for (const tsConfigPath of possiblePaths) {
|
for (const tsConfigPath of possibleTsPaths) {
|
||||||
const nxProject = findProjectForPath(tsConfigPath, projectRootMappings);
|
const nxProject = findProjectForPath(tsConfigPath, projectRootMappings);
|
||||||
if (nxProject) {
|
if (nxProject) {
|
||||||
return projectNameMap.get(nxProject);
|
return projectNameMap.get(nxProject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packageEntryPointsToProjectMap ??=
|
||||||
|
getPackageEntryPointsToProjectMap(projects);
|
||||||
|
if (packageEntryPointsToProjectMap[importPath]) {
|
||||||
|
return packageEntryPointsToProjectMap[importPath];
|
||||||
|
}
|
||||||
|
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
'Unable to find local plugin',
|
'Unable to find local plugin',
|
||||||
possiblePaths,
|
possibleTsPaths,
|
||||||
projectRootMappings
|
projectRootMappings
|
||||||
);
|
);
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Unable to resolve local plugin with import path ' + importPath
|
'Unable to resolve local plugin with import path ' + importPath
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let tsconfigPaths: Record<string, string[]>;
|
let tsconfigPaths: Record<string, string[]>;
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,13 @@ export interface PackageJson {
|
|||||||
| string
|
| string
|
||||||
| Record<
|
| Record<
|
||||||
string,
|
string,
|
||||||
string | { types?: string; require?: string; import?: string }
|
| string
|
||||||
|
| {
|
||||||
|
types?: string;
|
||||||
|
require?: string;
|
||||||
|
import?: string;
|
||||||
|
development?: string;
|
||||||
|
}
|
||||||
>;
|
>;
|
||||||
dependencies?: Record<string, string>;
|
dependencies?: Record<string, string>;
|
||||||
devDependencies?: Record<string, string>;
|
devDependencies?: Record<string, string>;
|
||||||
@ -149,13 +155,17 @@ let packageManagerCommand: PackageManagerCommands | undefined;
|
|||||||
export function getMetadataFromPackageJson(
|
export function getMetadataFromPackageJson(
|
||||||
packageJson: PackageJson
|
packageJson: PackageJson
|
||||||
): ProjectMetadata {
|
): ProjectMetadata {
|
||||||
const { scripts, nx, description } = packageJson ?? {};
|
const { scripts, nx, description, name, exports } = packageJson;
|
||||||
const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
|
const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
|
||||||
return {
|
return {
|
||||||
targetGroups: {
|
targetGroups: {
|
||||||
...(includedScripts.length ? { 'NPM Scripts': includedScripts } : {}),
|
...(includedScripts.length ? { 'NPM Scripts': includedScripts } : {}),
|
||||||
},
|
},
|
||||||
description,
|
description,
|
||||||
|
js: {
|
||||||
|
packageName: name,
|
||||||
|
packageExports: exports,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@ -902,8 +902,8 @@ importers:
|
|||||||
specifier: ^8.5.3
|
specifier: ^8.5.3
|
||||||
version: 8.5.3(@types/react@18.3.1)(react@18.3.1)
|
version: 8.5.3(@types/react@18.3.1)(react@18.3.1)
|
||||||
resolve.exports:
|
resolve.exports:
|
||||||
specifier: 1.1.0
|
specifier: 2.0.3
|
||||||
version: 1.1.0
|
version: 2.0.3
|
||||||
rollup:
|
rollup:
|
||||||
specifier: ^4.14.0
|
specifier: ^4.14.0
|
||||||
version: 4.22.0
|
version: 4.22.0
|
||||||
@ -15058,8 +15058,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==}
|
resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
resolve.exports@2.0.2:
|
resolve.exports@2.0.3:
|
||||||
resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==}
|
resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
resolve@1.22.8:
|
resolve@1.22.8:
|
||||||
@ -28326,7 +28326,7 @@ snapshots:
|
|||||||
'@jspm/core': 2.0.1
|
'@jspm/core': 2.0.1
|
||||||
esbuild: 0.17.6
|
esbuild: 0.17.6
|
||||||
local-pkg: 0.5.0
|
local-pkg: 0.5.0
|
||||||
resolve.exports: 2.0.2
|
resolve.exports: 2.0.3
|
||||||
|
|
||||||
esbuild-register@3.6.0(esbuild@0.19.5):
|
esbuild-register@3.6.0(esbuild@0.19.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -30895,7 +30895,7 @@ snapshots:
|
|||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
jest-validate: 29.7.0
|
jest-validate: 29.7.0
|
||||||
resolve: 1.22.8
|
resolve: 1.22.8
|
||||||
resolve.exports: 2.0.2
|
resolve.exports: 2.0.3
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
|
|
||||||
jest-runner@29.7.0:
|
jest-runner@29.7.0:
|
||||||
@ -35074,7 +35074,7 @@ snapshots:
|
|||||||
|
|
||||||
resolve.exports@1.1.0: {}
|
resolve.exports@1.1.0: {}
|
||||||
|
|
||||||
resolve.exports@2.0.2: {}
|
resolve.exports@2.0.3: {}
|
||||||
|
|
||||||
resolve@1.22.8:
|
resolve@1.22.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user