Skip to content

Commit d470dd2

Browse files
committed
fix(@angular-devkit/schematics): filters out non-NPM dependencies
Fixes angular#13059. Non-NPM dependencies in package.json are now filtered out of `ng update`. Dependencies which are linked as tarball or Git references will now be skipped during the update process.
1 parent bf2e58c commit d470dd2

File tree

1 file changed

+34
-6
lines changed
  • packages/schematics/update/update

1 file changed

+34
-6
lines changed

packages/schematics/update/update/index.ts

+34-6
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,29 @@ function _formatVersion(version: string | undefined) {
826826
return version;
827827
}
828828

829+
/**
830+
* @param depString Dependency from `package.json`. Could be a semver, local tarball reference,
831+
* link to a GitHub repo, etc.
832+
* @return Whether or not the given string is a simple semantic version, and thus represents a
833+
* package hosted on NPM, either as a public or private package.
834+
*/
835+
function isSimpleSemVer(depString: string): boolean {
836+
// Any tarball is clearly not a simple semantic version. We need to manually exclude this
837+
// case because semver.coerce() has special logic to extract the version number from the name
838+
// of a tarball generated with `npm pack`. By NPM specification, the name *must* end in ".tar",
839+
// ".tar.gz", or ".tgz", so we can simply exclude these extensions.
840+
// See: https://docs.npmjs.com/cli/install.
841+
if (depString.endsWith('.tar') || depString.endsWith('.tar.gz') || depString.endsWith('.tgz')) {
842+
return false;
843+
}
844+
845+
const version = semver.coerce(depString);
846+
if (!version) {
847+
return false;
848+
}
849+
850+
return !!semver.valid(version);
851+
}
829852

830853
export default function(options: UpdateSchema): Rule {
831854
if (!options.packages) {
@@ -850,11 +873,16 @@ export default function(options: UpdateSchema): Rule {
850873

851874
return (tree: Tree, context: SchematicContext) => {
852875
const logger = context.logger;
853-
const allDependencies = _getAllDependencies(tree);
854-
const packages = _buildPackageList(options, allDependencies, logger);
876+
const allDeps = _getAllDependencies(tree);
877+
878+
// Filter out non-NPM dependencies by checking if they link to a semver.
879+
const npmDeps = new Map(Array.from(allDeps.entries())
880+
.filter(([_, source]) => isSimpleSemVer(source)));
881+
882+
const packages = _buildPackageList(options, npmDeps, logger);
855883
const usingYarn = options.packageManager === 'yarn';
856884

857-
return observableFrom([...allDependencies.keys()]).pipe(
885+
return observableFrom([...npmDeps.keys()]).pipe(
858886
// Grab all package.json from the npm repository. This requires a lot of HTTP calls so we
859887
// try to parallelize as many as possible.
860888
mergeMap(depName => getNpmPackageJson(
@@ -899,8 +927,8 @@ export default function(options: UpdateSchema): Rule {
899927
do {
900928
lastPackagesSize = packages.size;
901929
npmPackageJsonMap.forEach((npmPackageJson) => {
902-
_addPackageGroup(tree, packages, allDependencies, npmPackageJson, logger);
903-
_addPeerDependencies(tree, packages, allDependencies, npmPackageJson, npmPackageJsonMap, logger);
930+
_addPackageGroup(tree, packages, npmDeps, npmPackageJson, logger);
931+
_addPeerDependencies(tree, packages, npmDeps, npmPackageJson, npmPackageJsonMap, logger);
904932
});
905933
} while (packages.size > lastPackagesSize);
906934

@@ -909,7 +937,7 @@ export default function(options: UpdateSchema): Rule {
909937
npmPackageJsonMap.forEach((npmPackageJson) => {
910938
packageInfoMap.set(
911939
npmPackageJson.name,
912-
_buildPackageInfo(tree, packages, allDependencies, npmPackageJson, logger),
940+
_buildPackageInfo(tree, packages, npmDeps, npmPackageJson, logger),
913941
);
914942
});
915943

0 commit comments

Comments
 (0)