@@ -167,6 +167,10 @@ class PackageManager {
|
||||
downloadResult = await this.installFromFile(parsed);
|
||||
break;
|
||||
}
|
||||
case 'workspace': {
|
||||
downloadResult = await this.installFromWorkspace(parsed);
|
||||
break;
|
||||
}
|
||||
case 'registry':
|
||||
default: {
|
||||
// Resolve version first
|
||||
@@ -789,6 +793,11 @@ class PackageManager {
|
||||
return this.parseFileSpec(spec);
|
||||
}
|
||||
|
||||
// Handle workspace dependencies
|
||||
if (this.isWorkspaceSpec(spec)) {
|
||||
return this.parseWorkspaceSpec(spec);
|
||||
}
|
||||
|
||||
// Handle standard npm packages
|
||||
const match = spec.match(/^(@?[^@]+)(?:@(.+))?$/);
|
||||
return {
|
||||
@@ -808,6 +817,16 @@ class PackageManager {
|
||||
spec.includes('git@');
|
||||
}
|
||||
|
||||
isWorkspaceSpec(spec) {
|
||||
// Check if it's a workspace dependency
|
||||
const match = spec.match(/^(@?[^@]+)@(.+)$/);
|
||||
if (match) {
|
||||
const version = match[2];
|
||||
return version.startsWith('workspace:');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
parseGitSpec(gitSpec) {
|
||||
let url = gitSpec;
|
||||
let ref = 'main'; // Changed from 'master' to 'main' (modern default)
|
||||
@@ -847,6 +866,23 @@ class PackageManager {
|
||||
};
|
||||
}
|
||||
|
||||
parseWorkspaceSpec(spec) {
|
||||
const match = spec.match(/^(@?[^@]+)@workspace:(.*)$/);
|
||||
if (!match) {
|
||||
throw new Error(`Invalid workspace spec: ${spec}`);
|
||||
}
|
||||
|
||||
const name = match[1];
|
||||
const workspaceVersion = match[2]; // Could be *, ^1.0.0, ~1.0.0, etc.
|
||||
|
||||
return {
|
||||
name: name,
|
||||
version: workspaceVersion,
|
||||
source: 'workspace',
|
||||
originalSpec: spec
|
||||
};
|
||||
}
|
||||
|
||||
parseFileSpec(fileSpec) {
|
||||
const cleanPath = fileSpec.replace('file:', '');
|
||||
const name = path.basename(cleanPath);
|
||||
@@ -1225,6 +1261,139 @@ class PackageManager {
|
||||
}
|
||||
}
|
||||
|
||||
async installFromWorkspace(workspaceSpec) {
|
||||
try {
|
||||
const packageName = workspaceSpec.name;
|
||||
const workspaceVersion = workspaceSpec.version;
|
||||
|
||||
// Find the workspace package
|
||||
const workspacePackage = await this.findWorkspacePackage(packageName, workspaceVersion);
|
||||
|
||||
if (!workspacePackage) {
|
||||
throw new Error(`Workspace package ${packageName} not found`);
|
||||
}
|
||||
|
||||
// Install from the workspace directory
|
||||
const fileSpec = {
|
||||
name: packageName,
|
||||
path: workspacePackage.path,
|
||||
source: 'file'
|
||||
};
|
||||
|
||||
return await this.installFromFile(fileSpec);
|
||||
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to install workspace package ${workspaceSpec.name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async findWorkspacePackage(packageName, workspaceVersion) {
|
||||
try {
|
||||
// Read the workspace root package.json to find workspace configuration
|
||||
const rootPackageJsonPath = path.join(this.projectRoot, 'package.json');
|
||||
|
||||
if (!await fs.pathExists(rootPackageJsonPath)) {
|
||||
throw new Error('No package.json found in project root');
|
||||
}
|
||||
|
||||
const rootPackageJson = await fs.readJson(rootPackageJsonPath);
|
||||
|
||||
// Check for workspace configuration
|
||||
let workspacePatterns = [];
|
||||
|
||||
// Handle different workspace configuration formats
|
||||
if (rootPackageJson.workspaces) {
|
||||
if (Array.isArray(rootPackageJson.workspaces)) {
|
||||
workspacePatterns = rootPackageJson.workspaces;
|
||||
} else if (rootPackageJson.workspaces.packages) {
|
||||
workspacePatterns = rootPackageJson.workspaces.packages;
|
||||
}
|
||||
}
|
||||
|
||||
if (workspacePatterns.length === 0) {
|
||||
throw new Error('No workspace configuration found');
|
||||
}
|
||||
|
||||
// Search for the package in workspace directories
|
||||
for (const pattern of workspacePatterns) {
|
||||
const workspaceDirs = await this.expandWorkspacePattern(pattern);
|
||||
|
||||
for (const workspaceDir of workspaceDirs) {
|
||||
const packageJsonPath = path.join(this.projectRoot, workspaceDir, 'package.json');
|
||||
|
||||
if (await fs.pathExists(packageJsonPath)) {
|
||||
const packageJson = await fs.readJson(packageJsonPath);
|
||||
|
||||
if (packageJson.name === packageName) {
|
||||
// Check if version matches workspace requirement
|
||||
if (this.matchesWorkspaceVersion(packageJson.version, workspaceVersion)) {
|
||||
return {
|
||||
name: packageName,
|
||||
version: packageJson.version,
|
||||
path: path.join(this.projectRoot, workspaceDir),
|
||||
packageJson: packageJson
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to find workspace package ${packageName}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async expandWorkspacePattern(pattern) {
|
||||
const glob = require('glob');
|
||||
|
||||
try {
|
||||
// Use glob to expand workspace patterns
|
||||
const matches = await new Promise((resolve, reject) => {
|
||||
glob(pattern, { cwd: this.projectRoot }, (err, files) => {
|
||||
if (err) reject(err);
|
||||
else resolve(files);
|
||||
});
|
||||
});
|
||||
|
||||
// Filter to only directories that contain package.json
|
||||
const workspaceDirs = [];
|
||||
for (const match of matches) {
|
||||
const packageJsonPath = path.join(this.projectRoot, match, 'package.json');
|
||||
if (await fs.pathExists(packageJsonPath)) {
|
||||
workspaceDirs.push(match);
|
||||
}
|
||||
}
|
||||
|
||||
return workspaceDirs;
|
||||
|
||||
} catch (error) {
|
||||
console.warn(chalk.yellow(`Warning: Failed to expand workspace pattern ${pattern}: ${error.message}`));
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
matchesWorkspaceVersion(packageVersion, workspaceVersion) {
|
||||
// Handle different workspace version formats
|
||||
if (workspaceVersion === '*') {
|
||||
return true; // Any version matches
|
||||
}
|
||||
|
||||
if (workspaceVersion.startsWith('^') || workspaceVersion.startsWith('~')) {
|
||||
// Use semver to check if version satisfies range
|
||||
return semver.satisfies(packageVersion, workspaceVersion);
|
||||
}
|
||||
|
||||
if (workspaceVersion === packageVersion) {
|
||||
return true; // Exact match
|
||||
}
|
||||
|
||||
// Default to true for other cases (workspace should generally match)
|
||||
return true;
|
||||
}
|
||||
|
||||
async runPostInstallScripts(packageName, packageDir) {
|
||||
try {
|
||||
const packageJsonPath = path.join(packageDir, 'package.json');
|
||||
|
||||
Referencia en una nueva incidencia
Block a user