Skip to content

Commit e50a814

Browse files
committed
chore: support checking dependencies consistance across packages
and fix related dependencies
1 parent 06f9786 commit e50a814

File tree

2 files changed

+108
-44
lines changed

2 files changed

+108
-44
lines changed

packages/@ngtools/webpack/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
"source-map": "^0.5.6"
3232
},
3333
"peerDependencies": {
34-
"@angular/compiler": "^2.3.1",
35-
"@angular/compiler-cli": "^2.3.1",
36-
"@angular/core": "^2.3.1",
34+
"@angular/compiler": "~2.3.1",
35+
"@angular/compiler-cli": "~2.3.1",
36+
"@angular/core": "~2.3.1",
3737
"@angular/tsc-wrapped": "^0.5.0",
38-
"typescript": "^2.0.2",
38+
"typescript": "^2.0.3",
3939
"reflect-metadata": "^0.1.8",
4040
"webpack": "2.2.0-rc.3"
4141
}

scripts/publish/validate_dependencies.js

+104-40
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const fs = require('fs');
77
const glob = require('glob');
88
const packages = require('../../lib/packages');
99
const path = require('path');
10+
const _ = require('lodash');
1011

1112

1213
const IMPORT_RE = /(^|\n)\s*import\b(?:.|\n)*?\'[^\']*\'/g;
@@ -28,6 +29,18 @@ const ANGULAR_PACKAGES = [
2829
'@angular/core'
2930
];
3031

32+
let exitCode = 0;
33+
34+
const depsInfo = validateDependenciesPerPackage(packages);
35+
36+
validateRootPackageJson(depsInfo.allSourceDeps);
37+
38+
checkDependenciesConflictAcrossPackages(depsInfo.allDeclaredDepsMap);
39+
40+
process.exit(exitCode);
41+
42+
43+
// utils
3144

3245
function listImportedModules(source) {
3346
const imports = source.match(IMPORT_RE);
@@ -40,7 +53,7 @@ function listImportedModules(source) {
4053
.filter(x => !!x)
4154
.filter(modulePath => modulePath[0] != '.')
4255
.map(fullImportPath => {
43-
if (fullImportPath[0] == '@') {
56+
if (fullImportPath[0] === '@') {
4457
// Need to get the scope as well.
4558
return fullImportPath.split('/').slice(0, 2).join('/');
4659
} else {
@@ -60,7 +73,7 @@ function listRequiredModules(source) {
6073
.filter(x => !!x)
6174
.filter(modulePath => modulePath[0] != '.')
6275
.map(fullImportPath => {
63-
if (fullImportPath[0] == '@') {
76+
if (fullImportPath[0] === '@') {
6477
// Need to get the scope as well.
6578
return fullImportPath.split('/').slice(0, 2).join('/');
6679
} else {
@@ -70,7 +83,7 @@ function listRequiredModules(source) {
7083
}
7184

7285
function reportMissingDependencies(missingDeps) {
73-
if (missingDeps.length == 0) {
86+
if (missingDeps.length === 0) {
7487
console.log(chalk.green(' no dependency missing from package.json.'));
7588
} else {
7689
console.log(chalk.yellow(` ${missingDeps.length} missing from package.json:`));
@@ -80,7 +93,7 @@ function reportMissingDependencies(missingDeps) {
8093
}
8194

8295
function reportExcessiveDependencies(overDeps) {
83-
if (overDeps.length == 0) {
96+
if (overDeps.length === 0) {
8497
console.log(chalk.green(' no excessive dependencies in package.json.'));
8598
} else {
8699
console.log(chalk.yellow(` ${overDeps.length} excessive dependencies in package.json:`));
@@ -89,63 +102,114 @@ function reportExcessiveDependencies(overDeps) {
89102
}
90103
}
91104

92-
let exitCode = 0;
93-
const overallDeps = [];
94-
for (const packageName of Object.keys(packages)) {
95-
console.log(chalk.green(`Reading dependencies of "${packageName}".`));
105+
function reportInconsistentDepsDependencies(inconsistentDeps) {
106+
if (inconsistentDeps.length === 0) {
107+
console.log(chalk.green(' no inconsistentDeps dependencies across packages.'));
108+
} else {
109+
console.log(chalk.yellow(` ${inconsistentDeps.length} inconsistent dependencies found:`));
110+
inconsistentDeps.forEach(arr => console.log(` ${arr.join(' vs ')}`));
111+
exitCode = 0;
112+
}
113+
}
96114

115+
function retrieveDependencyMapFromPackageSource(packageName) {
97116
const allSources = glob.sync(path.join(__dirname, '../../packages/', packageName, '**/*'))
98117
.filter(p => p.match(/\.(js|ts)$/))
99118
.filter(p => !p.match(/\.spec\./))
100119
.filter(p => !p.match(/\/blueprints\//));
101120

102-
const importMap = {};
103-
allSources.forEach(function(filePath) {
121+
return allSources.reduce(function (importMap, filePath) {
104122
const source = fs.readFileSync(filePath, 'utf8');
105123

106124
listImportedModules(source)
107125
.forEach(modulePath => importMap[modulePath] = true);
108126
listRequiredModules(source)
109127
.forEach(modulePath => importMap[modulePath] = true);
110-
});
111128

112-
const dependencies = Object.keys(importMap)
113-
// Filter out the node packages that should not be depended on.
114-
.filter(x => NODE_PACKAGES.indexOf(x) == -1);
115-
overallDeps.push(...dependencies);
129+
return importMap;
130+
}, {});
131+
}
132+
133+
function validateDependenciesPerPackage(packages) {
134+
const allSourceDeps = [];
135+
const allDeclaredDepsMap = {};
136+
137+
for (const packageName of Object.keys(packages)) {
138+
console.log(chalk.blue(`Reading dependencies of "${packageName}".`));
116139

117-
console.log(chalk.green(` found ${dependencies.length} dependencies...`));
118-
const packageJson = JSON.parse(fs.readFileSync(packages[packageName].packageJson, 'utf8'));
119-
const allDeps = []
120-
.concat(Object.keys(packageJson['dependencies'] || {}))
121-
.concat(Object.keys(packageJson['devDependencies'] || {}))
122-
.concat(Object.keys(packageJson['peerDependencies'] || {}));
140+
const importMap = retrieveDependencyMapFromPackageSource(packageName)
123141

124-
const missingDeps = dependencies.filter(d => allDeps.indexOf(d) == -1);
125-
reportMissingDependencies(missingDeps);
142+
const dependencies = Object.keys(importMap)
143+
// Filter out the node packages that should not be depended on.
144+
.filter(x => NODE_PACKAGES.indexOf(x) == -1);
145+
allSourceDeps.push(...dependencies);
126146

127-
const overDeps = allDeps.filter(d => dependencies.indexOf(d) == -1)
128-
.filter(x => ANGULAR_PACKAGES.indexOf(x) == -1);
129-
reportExcessiveDependencies(overDeps);
147+
console.log(chalk.green(` found ${dependencies.length} dependencies...`));
130148

131-
console.log('');
149+
const packageJson = JSON.parse(fs.readFileSync(packages[packageName].packageJson, 'utf8'));
150+
151+
const DeclaredDepsMap = Object.assign(
152+
{},
153+
packageJson['dependencies'] || {},
154+
packageJson['devDependencies'] || {},
155+
packageJson['peerDependencies'] || {}
156+
);
157+
allDeclaredDepsMap[packageName] = DeclaredDepsMap;
158+
const declaredDeps = Object.keys(DeclaredDepsMap);
159+
160+
const missingDeps = dependencies.filter(d => declaredDeps.indexOf(d) === -1);
161+
reportMissingDependencies(missingDeps);
162+
163+
const excessiveDeps = declaredDeps.filter(d => dependencies.indexOf(d) === -1)
164+
.filter(x => ANGULAR_PACKAGES.indexOf(x) === -1);
165+
reportExcessiveDependencies(excessiveDeps);
166+
}
167+
168+
return {
169+
allDeclaredDepsMap,
170+
allSourceDeps
171+
};
132172
}
133173

134-
console.log(chalk.green('Validating root package. [devDependencies ignored]'));
135-
const rootPackagePath = path.join(__dirname, '../../package.json');
136-
const rootPackageJson = JSON.parse(fs.readFileSync(rootPackagePath, 'utf8'));
137-
// devDependencies are ignored
138-
const allRootDeps = []
174+
function validateRootPackageJson(overallDeps) {
175+
console.log(chalk.blue('Validating root package. [devDependencies ignored]'));
176+
177+
const rootPackagePath = path.join(__dirname, '../../package.json');
178+
const rootPackageJson = JSON.parse(fs.readFileSync(rootPackagePath, 'utf8'));
179+
180+
// devDependencies are ignored
181+
const allRootDeps = []
139182
.concat(Object.keys(rootPackageJson['dependencies'] || {}))
140183
.concat(Object.keys(rootPackageJson['peerDependencies'] || {}));
141184

142-
const internalPackages = Object.keys(packages);
143-
const missingRootDeps = overallDeps.filter(d => allRootDeps.indexOf(d) == -1)
144-
.filter(d => internalPackages.indexOf(d) == -1);
145-
reportMissingDependencies(missingRootDeps);
185+
const internalPackages = Object.keys(packages);
186+
const missingRootDeps = overallDeps.filter(d => allRootDeps.indexOf(d) === -1)
187+
.filter(d => internalPackages.indexOf(d) === -1);
188+
reportMissingDependencies(missingRootDeps);
146189

147-
const overRootDeps = allRootDeps.filter(d => overallDeps.indexOf(d) == -1)
148-
.filter(x => ANGULAR_PACKAGES.indexOf(x) == -1);
149-
reportExcessiveDependencies(overRootDeps);
190+
const overRootDeps = allRootDeps.filter(d => overallDeps.indexOf(d) === -1)
191+
.filter(x => ANGULAR_PACKAGES.indexOf(x) === -1);
192+
reportExcessiveDependencies(overRootDeps);
193+
}
150194

151-
process.exit(exitCode);
195+
function checkDependenciesConflictAcrossPackages(allDeclaredDepsMap) {
196+
console.log(chalk.blue('Validating packages\' dependencies conflict.'));
197+
198+
const allDeclaredDeps = Object.keys(allDeclaredDepsMap)
199+
.reduce((collect, packageName) => collect.concat(Object.keys(allDeclaredDepsMap[packageName])), []);
200+
201+
const inconsistentDeps = _.uniq(allDeclaredDeps).reduce(function (collect, dep) {
202+
const test = _(allDeclaredDepsMap)
203+
.map((map, name) => map[dep] ? [name, `${dep}@${map[dep]}`] : null)
204+
.compact()
205+
.uniqBy(1)
206+
.value();
207+
if (test.length > 1) {
208+
collect.push(test.map(pair =>`[${pair[0]}]: ${pair[1]}`));
209+
}
210+
211+
return collect;
212+
}, []);
213+
214+
reportInconsistentDepsDependencies(inconsistentDeps);
215+
}

0 commit comments

Comments
 (0)