nx
Version:
221 lines (220 loc) • 9.3 kB
JavaScript
;
// This file contains methods and utilities that should **only** be used by the plugin worker.
Object.defineProperty(exports, "__esModule", { value: true });
exports.unregisterPluginTSTranspiler = void 0;
exports.readPluginPackageJson = readPluginPackageJson;
exports.resolveLocalNxPlugin = resolveLocalNxPlugin;
exports.registerPluginTSTranspiler = registerPluginTSTranspiler;
exports.getPluginPathAndName = getPluginPathAndName;
exports.loadNxPlugin = loadNxPlugin;
exports.loadNxPluginAsync = loadNxPluginAsync;
const posix_1 = require("node:path/posix");
const installation_directory_1 = require("../../utils/installation-directory");
const package_json_1 = require("../../utils/package-json");
const fileutils_1 = require("../../utils/fileutils");
const workspace_root_1 = require("../../utils/workspace-root");
const node_fs_1 = require("node:fs");
const register_1 = require("../../plugins/js/utils/register");
const find_project_for_path_1 = require("../utils/find-project-for-path");
const path_1 = require("../../utils/path");
const logger_1 = require("../../utils/logger");
const node_path_1 = require("node:path");
const retrieve_workspace_files_1 = require("../utils/retrieve-workspace-files");
const utils_1 = require("./utils");
const internal_api_1 = require("./internal-api");
const error_types_1 = require("../error-types");
const path = require("node:path/posix");
const typescript_1 = require("../../plugins/js/utils/typescript");
function readPluginPackageJson(pluginName, projects, paths = (0, installation_directory_1.getNxRequirePaths)()) {
try {
const result = (0, package_json_1.readModulePackageJsonWithoutFallbacks)(pluginName, paths);
return {
json: result.packageJson,
path: result.path,
};
}
catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
const localPluginPath = resolveLocalNxPlugin(pluginName, projects);
if (localPluginPath) {
const localPluginPackageJson = path.join(localPluginPath.path, 'package.json');
if (!exports.unregisterPluginTSTranspiler) {
registerPluginTSTranspiler();
}
return {
path: localPluginPackageJson,
json: (0, fileutils_1.readJsonFile)(localPluginPackageJson),
};
}
}
throw e;
}
}
function resolveLocalNxPlugin(importPath, projects, root = workspace_root_1.workspaceRoot) {
return lookupLocalPlugin(importPath, projects, root);
}
exports.unregisterPluginTSTranspiler = null;
/**
* Register swc-node or ts-node if they are not currently registered
* with some default settings which work well for Nx plugins.
*/
function registerPluginTSTranspiler() {
// Get the first tsconfig that matches the allowed set
const tsConfigName = [
(0, posix_1.join)(workspace_root_1.workspaceRoot, 'tsconfig.base.json'),
(0, posix_1.join)(workspace_root_1.workspaceRoot, 'tsconfig.json'),
].find((x) => (0, node_fs_1.existsSync)(x));
if (!tsConfigName) {
return;
}
const tsConfig = tsConfigName
? (0, typescript_1.readTsConfig)(tsConfigName)
: {};
const cleanupFns = [
(0, register_1.registerTsConfigPaths)(tsConfigName),
(0, register_1.registerTranspiler)({
experimentalDecorators: true,
emitDecoratorMetadata: true,
...tsConfig.options,
}, tsConfig.raw),
];
exports.unregisterPluginTSTranspiler = () => {
cleanupFns.forEach((fn) => fn?.());
};
}
function lookupLocalPlugin(importPath, projects, root = workspace_root_1.workspaceRoot) {
const projectConfig = findNxProjectForImportPath(importPath, projects, root);
if (!projectConfig) {
return null;
}
return { path: path.join(root, projectConfig.root), projectConfig };
}
function findNxProjectForImportPath(importPath, projects, root = workspace_root_1.workspaceRoot) {
const tsConfigPaths = readTsConfigPaths(root);
const possiblePaths = tsConfigPaths[importPath]?.map((p) => (0, path_1.normalizePath)(path.relative(root, path.join(root, p))));
if (possiblePaths?.length) {
const projectRootMappings = new Map();
const projectNameMap = new Map();
for (const projectRoot in projects) {
const project = projects[projectRoot];
projectRootMappings.set(project.root, project.name);
projectNameMap.set(project.name, project);
}
for (const tsConfigPath of possiblePaths) {
const nxProject = (0, find_project_for_path_1.findProjectForPath)(tsConfigPath, projectRootMappings);
if (nxProject) {
return projectNameMap.get(nxProject);
}
}
logger_1.logger.verbose('Unable to find local plugin', possiblePaths, projectRootMappings);
throw new Error('Unable to resolve local plugin with import path ' + importPath);
}
}
let tsconfigPaths;
function readTsConfigPaths(root = workspace_root_1.workspaceRoot) {
if (!tsconfigPaths) {
const tsconfigPath = ['tsconfig.base.json', 'tsconfig.json']
.map((x) => path.join(root, x))
.filter((x) => (0, node_fs_1.existsSync)(x))[0];
if (!tsconfigPath) {
throw new Error('unable to find tsconfig.base.json or tsconfig.json');
}
const { compilerOptions } = (0, fileutils_1.readJsonFile)(tsconfigPath);
tsconfigPaths = compilerOptions?.paths;
}
return tsconfigPaths ?? {};
}
function readPluginMainFromProjectConfiguration(plugin) {
const { main } = Object.values(plugin.targets).find((x) => [
'@nx/js:tsc',
'@nrwl/js:tsc',
'@nx/js:swc',
'@nrwl/js:swc',
'@nx/node:package',
'@nrwl/node:package',
].includes(x.executor))?.options ||
plugin.targets?.build?.options ||
{};
return main;
}
function getPluginPathAndName(moduleName, paths, projects, root) {
let pluginPath;
let registerTSTranspiler = false;
try {
pluginPath = require.resolve(moduleName, {
paths,
});
const extension = path.extname(pluginPath);
registerTSTranspiler = extension === '.ts';
}
catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
const plugin = resolveLocalNxPlugin(moduleName, projects, root);
if (plugin) {
registerTSTranspiler = true;
const main = readPluginMainFromProjectConfiguration(plugin.projectConfig);
pluginPath = main ? path.join(root, main) : plugin.path;
}
else {
logger_1.logger.error(`Plugin listed in \`nx.json\` not found: ${moduleName}`);
throw e;
}
}
else {
throw e;
}
}
const packageJsonPath = path.join(pluginPath, 'package.json');
// Register the ts-transpiler if we are pointing to a
// plain ts file that's not part of a plugin project
if (registerTSTranspiler) {
registerPluginTSTranspiler();
}
const { name } = !['.ts', '.js'].some((x) => (0, node_path_1.extname)(moduleName) === x) && // Not trying to point to a ts or js file
(0, node_fs_1.existsSync)(packageJsonPath) // plugin has a package.json
? (0, fileutils_1.readJsonFile)(packageJsonPath) // read name from package.json
: { name: moduleName };
return { pluginPath, name };
}
let projectsWithoutInference;
function loadNxPlugin(plugin, root) {
return [
loadNxPluginAsync(plugin, (0, installation_directory_1.getNxRequirePaths)(root), root),
() => { },
];
}
async function loadNxPluginAsync(pluginConfiguration, paths, root) {
const moduleName = typeof pluginConfiguration === 'string'
? pluginConfiguration
: pluginConfiguration.plugin;
try {
try {
require.resolve(moduleName);
}
catch {
// If a plugin cannot be resolved, we will need projects to resolve it
projectsWithoutInference ??=
await (0, retrieve_workspace_files_1.retrieveProjectConfigurationsWithoutPluginInference)(root);
}
performance.mark(`Load Nx Plugin: ${moduleName} - start`);
let { pluginPath, name } = await getPluginPathAndName(moduleName, paths, projectsWithoutInference, root);
const plugin = (0, utils_1.normalizeNxPlugin)(await importPluginModule(pluginPath));
plugin.name ??= name;
performance.mark(`Load Nx Plugin: ${moduleName} - end`);
performance.measure(`Load Nx Plugin: ${moduleName}`, `Load Nx Plugin: ${moduleName} - start`, `Load Nx Plugin: ${moduleName} - end`);
return new internal_api_1.LoadedNxPlugin(plugin, pluginConfiguration);
}
catch (e) {
throw new error_types_1.LoadPluginError(moduleName, e);
}
}
async function importPluginModule(pluginPath) {
const m = await Promise.resolve(`${pluginPath}`).then(s => require(s));
if (m.default &&
('createNodes' in m.default ||
'createNodesV2' in m.default ||
'createDependencies' in m.default)) {
return m.default;
}
return m;
}