Skip to content

Commit

Permalink
Revert "feat: Support for yarn workspaces (#493)" (#936)
Browse files Browse the repository at this point in the history
This reverts commit 3e8410b.
  • Loading branch information
joaomoreno authored Feb 23, 2024
1 parent 6e959ca commit a080290
Show file tree
Hide file tree
Showing 33 changed files with 101 additions and 1,139 deletions.
52 changes: 12 additions & 40 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"chalk": "^2.4.2",
"cheerio": "^1.0.0-rc.9",
"commander": "^6.2.1",
"find-yarn-workspace-root": "^2.0.0",
"glob": "^7.0.6",
"hosted-git-info": "^4.0.2",
"jsonc-parser": "^3.2.0",
Expand Down
150 changes: 66 additions & 84 deletions src/npm.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import * as path from 'path';
import * as fs from 'fs';
import * as cp from 'child_process';
import findWorkspaceRoot from 'find-yarn-workspace-root';
import { Manifest } from './manifest';
import { readNodeManifest } from './package';
import { CancellationToken, log } from './util';
import parseSemver from 'parse-semver';
import { CancellationToken, log, nonnull } from './util';

const exists = (file: string) =>
fs.promises.stat(file).then(
Expand Down Expand Up @@ -64,67 +62,51 @@ async function checkNPM(cancellationToken?: CancellationToken): Promise<void> {
}
}

function getNpmDependencies(cwd: string): Promise<SourceAndDestination[]> {
function getNpmDependencies(cwd: string): Promise<string[]> {
return checkNPM()
.then(() =>
exec('npm list --production --parseable --depth=99999 --loglevel=error', { cwd, maxBuffer: 5000 * 1024 })
)
.then(({ stdout }) => stdout.split(/[\r\n]/).filter(dir => path.isAbsolute(dir))
.map(dir => {
return {
src: dir,
dest: path.relative(cwd, dir)
}
}));
.then(({ stdout }) => stdout.split(/[\r\n]/).filter(dir => path.isAbsolute(dir)));
}

interface YarnTreeNode {
name: string;
children: YarnTreeNode[];
}

export interface YarnDependency {
name: string;
path: SourceAndDestination;
path: string;
children: YarnDependency[];
}

export interface SourceAndDestination {
src: string;
dest: string;
}
function asYarnDependency(prefix: string, tree: YarnTreeNode, prune: boolean): YarnDependency | null {
if (prune && /@[\^~]/.test(tree.name)) {
return null;
}

async function asYarnDependencies(root: string, rootDependencies: string[]): Promise<YarnDependency[]> {
const resolve = async (prefix: string, dependencies: string[], collected: Map<string, YarnDependency> = new Map()): Promise<YarnDependency[]> => await Promise.all(dependencies
.map(async (name: string) => {
let newPrefix = prefix, depPath = null, depManifest = null;
while (!depManifest && root.length <= newPrefix.length) {
depPath = path.join(newPrefix, 'node_modules', name);
try {
depManifest = await readNodeManifest(depPath);
} catch (err) {
newPrefix = path.join(newPrefix, '..');
if (newPrefix.length < root.length) {
throw err;
}
}
}
let name: string;

if (!depPath || !depManifest) {
throw new Error(`Error finding dependencies`);
}
try {
const parseResult = parseSemver(tree.name);
name = parseResult.name;
} catch (err) {
name = tree.name.replace(/^([^@+])@.*$/, '$1');
}

const result: YarnDependency = {
name,
path: {
src: depPath,
dest: path.relative(root, depPath),
},
children: [],
};
const shouldResolveChildren = !collected.has(depPath);
collected.set(depPath, result);
if (shouldResolveChildren) {
result.children = await resolve(depPath, Object.keys(depManifest.dependencies || {}), collected);
}
return result;
}));
return resolve(root, rootDependencies);
const dependencyPath = path.join(prefix, name);
const children: YarnDependency[] = [];

for (const child of tree.children || []) {
const dep = asYarnDependency(path.join(prefix, name, 'node_modules'), child, prune);

if (dep) {
children.push(dep);
}
}

return { name, path: dependencyPath, children };
}

function selectYarnDependencies(deps: YarnDependency[], packagedDependencies: string[]): YarnDependency[] {
Expand Down Expand Up @@ -172,10 +154,26 @@ function selectYarnDependencies(deps: YarnDependency[], packagedDependencies: st
return reached.values;
}

async function getYarnProductionDependencies(root: string, manifest: Manifest, packagedDependencies?: string[]): Promise<YarnDependency[]> {
async function getYarnProductionDependencies(cwd: string, packagedDependencies?: string[]): Promise<YarnDependency[]> {
const raw = await new Promise<string>((c, e) =>
cp.exec(
'yarn list --prod --json',
{ cwd, encoding: 'utf8', env: { ...process.env }, maxBuffer: 5000 * 1024 },
(err, stdout) => (err ? e(err) : c(stdout))
)
);
const match = /^{"type":"tree".*$/m.exec(raw);

if (!match || match.length !== 1) {
throw new Error('Could not parse result of `yarn list --json`');
}

const usingPackagedDependencies = Array.isArray(packagedDependencies);
const trees = JSON.parse(match[0]).data.trees as YarnTreeNode[];

let result = await asYarnDependencies(root, Object.keys(manifest.dependencies || {}));
let result = trees
.map(tree => asYarnDependency(path.join(cwd, 'node_modules'), tree, !usingPackagedDependencies))
.filter(nonnull);

if (usingPackagedDependencies) {
result = selectYarnDependencies(result, packagedDependencies!);
Expand All @@ -184,35 +182,22 @@ async function getYarnProductionDependencies(root: string, manifest: Manifest, p
return result;
}

async function getYarnDependencies(cwd: string, root: string, manifest: Manifest, packagedDependencies?: string[]): Promise<SourceAndDestination[]> {
const result: SourceAndDestination[] = [{
src: cwd,
dest: ''
}];

if (await exists(path.join(root, 'yarn.lock'))) {
const deps = await getYarnProductionDependencies(root, manifest, packagedDependencies);
const flatten = (dep: YarnDependency) => {
result.push(dep.path);
dep.children.forEach(flatten);
};
deps.forEach(flatten);
}

const dedup = new Map();
async function getYarnDependencies(cwd: string, packagedDependencies?: string[]): Promise<string[]> {
const result = new Set([cwd]);

for (const item of result) {
if (!dedup.has(item.src)) {
dedup.set(item.src, item);
}
}
const deps = await getYarnProductionDependencies(cwd, packagedDependencies);
const flatten = (dep: YarnDependency) => {
result.add(dep.path);
dep.children.forEach(flatten);
};
deps.forEach(flatten);

return [...dedup.values()];
return [...result];
}

export async function detectYarn(root: string) {
export async function detectYarn(cwd: string): Promise<boolean> {
for (const name of ['yarn.lock', '.yarnrc', '.yarnrc.yaml', '.pnp.cjs', '.yarn']) {
if (await exists(path.join(root, name))) {
if (await exists(path.join(cwd, name))) {
if (!process.env['VSCE_TESTS']) {
log.info(
`Detected presence of ${name}. Using 'yarn' instead of 'npm' (to override this pass '--no-yarn' on the command line).`
Expand All @@ -226,16 +211,13 @@ export async function detectYarn(root: string) {

export async function getDependencies(
cwd: string,
manifest: Manifest,
dependencies: 'npm' | 'yarn' | 'none' | undefined,
packagedDependencies?: string[]
): Promise<SourceAndDestination[]> {
const root = findWorkspaceRoot(cwd) || cwd;

): Promise<string[]> {
if (dependencies === 'none') {
return [{ src: root, dest: '' }];
} else if (dependencies === 'yarn' || (dependencies === undefined && (await detectYarn(root)))) {
return await getYarnDependencies(cwd, root, manifest, packagedDependencies);
return [cwd];
} else if (dependencies === 'yarn' || (dependencies === undefined && (await detectYarn(cwd)))) {
return await getYarnDependencies(cwd, packagedDependencies);
} else {
return await getNpmDependencies(cwd);
}
Expand Down
Loading

0 comments on commit a080290

Please sign in to comment.