Skip to content

Commit

Permalink
fix(@angular-devkit/schematics): running external schematics with yar…
Browse files Browse the repository at this point in the history
…n pnp

This change addresses an issue encountered when running external schematics from
a yarn pnp workspace.  The function used to resolve a collection json using node
used recursion in a way that it effectively walked itself into an exception. Then
if the exception is the type it expected, it would keep going.  This was flawed
in that yarn with pnp throws a different type of error when it failed to load
the mis-constructed collection path (e.g. `/node_modules/@schematics/angular/collection.json/package.json`).  `ENOTDIR` instead of `MODULE_NOT_FOUND`.

This process of intentionally / knowingly walking into an exception seems problematic in
general.  So, I addressed it by removing the recursion that was used mainly because
there's a similar need to construct the collection path from a relative path in the
package.json as there is to construct the collection path from a relative path that's
passed in.  Rather than leaning on the recursion to do this, I added the logic
at the time we pull the schematics path from the package, and move on.

Since the recursion was removed, the infinite recursion safety check at the start wasn't
needed anymore.

I've tested this in both yarn pnp and non-pnp environments.

(cherry picked from commit 081111f)
  • Loading branch information
michaelfaith authored and alan-agius4 committed Oct 31, 2023
1 parent 75b7491 commit 5f4ca4e
Showing 1 changed file with 13 additions and 14 deletions.
27 changes: 13 additions & 14 deletions packages/angular_devkit/schematics/tools/node-module-engine-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,7 @@ export class NodeModulesEngineHost extends FileSystemEngineHostBase {
super();
}

private resolve(name: string, requester?: string, references = new Set<string>()): string {
if (requester) {
if (references.has(requester)) {
references.add(requester);
throw new Error(
'Circular schematic reference detected: ' + JSON.stringify(Array.from(references)),
);
} else {
references.add(requester);
}
}

private resolve(name: string, requester?: string): string {
const relativeBase = requester ? dirname(requester) : process.cwd();
let collectionPath: string | undefined = undefined;

Expand All @@ -57,6 +46,7 @@ export class NodeModulesEngineHost extends FileSystemEngineHostBase {
};

// Try to resolve as a package
let possibleCollectionPath = name;
try {
const packageJsonPath = require.resolve(join(name, 'package.json'), resolveOptions);
const { schematics } = require(packageJsonPath);
Expand All @@ -65,7 +55,16 @@ export class NodeModulesEngineHost extends FileSystemEngineHostBase {
throw new NodePackageDoesNotSupportSchematics(name);
}

collectionPath = this.resolve(schematics, packageJsonPath, references);
// If this is a relative path to the collection, then create the collection
// path in relation to the package path
if (schematics.startsWith('.')) {
const packageDirectory = dirname(packageJsonPath);
collectionPath = resolve(packageDirectory, schematics);
}
// Otherwise use the path as-is to attempt resolution
else {
possibleCollectionPath = schematics;
}
} catch (e) {
if ((e as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') {
throw e;
Expand All @@ -75,7 +74,7 @@ export class NodeModulesEngineHost extends FileSystemEngineHostBase {
// If not a package, try to resolve as a file
if (!collectionPath) {
try {
collectionPath = require.resolve(name, resolveOptions);
collectionPath = require.resolve(possibleCollectionPath, resolveOptions);
} catch (e) {
if ((e as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') {
throw e;
Expand Down

0 comments on commit 5f4ca4e

Please sign in to comment.