diff --git a/.eslintrc b/.eslintrc index 2445c0c7288..675654b0fa6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,5 +10,10 @@ "no-extra-semi": "warn", "semi": "warn" }, - "extends": "eslint:recommended" + "extends": "eslint:recommended", + "parserOptions": { + "ecmaFeatures": { + "experimentalObjectRestSpread": true + } + } } \ No newline at end of file diff --git a/build/dependencies.js b/build/dependencies.js new file mode 100644 index 00000000000..e34efac7920 --- /dev/null +++ b/build/dependencies.js @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const path = require('path'); +const semver = require('semver'); +const cp = require('child_process'); + +// { name, version, path }[] +function flattenDependencies(node_modules, tree) { + const result = []; + const name = tree.name.replace(/@[^@]+$/, ''); + + if (tree.name !== 'root' && !/@[\^~]/.test(tree.name)) { + const dependencyPath = path.join(node_modules, name); + const version = tree.name.replace(/^[^@]+@/, ''); + + if (semver.valid(version)) { + result.push({ name, version, path: dependencyPath }); + } + } + + for (const child of (tree.children || [])) { + const subNodeModulesPath = name === 'root' + ? node_modules + : path.join(node_modules, name, 'node_modules'); + + result.push(...flattenDependencies(subNodeModulesPath, child)); + } + + return result; +} + +function getProductionDependencies(cwd) { + const raw = cp.execSync('yarn list --json', { + cwd, + encoding: 'utf8', + env: { ...process.env, NODE_ENV: 'production' } + }); + + const match = /^{"type":"tree".*$/m.exec(raw); + + if (!match || match.length !== 1) { + throw new Error('Could not parse result of `yarn list --json`'); + } + + const trees = JSON.parse(match[0]).data.trees; + const root = { name: 'root', children: trees }; + const list = flattenDependencies(path.join(cwd, 'node_modules'), root); + + list.sort((a, b) => a.name < b.name ? -1 : 1); + return list; +} + +module.exports.getProductionDependencies = getProductionDependencies; + +if (require.main === module) { + const root = path.dirname(__dirname); + console.log(JSON.stringify(getProductionDependencies(root), null, ' ')); +} diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 5bc6f99869c..14b20f716cd 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -29,17 +29,16 @@ const root = path.dirname(__dirname); const commit = util.getVersion(root); const packageJson = require('../package.json'); const product = require('../product.json'); -const shrinkwrap = require('../npm-shrinkwrap.json'); const crypto = require('crypto'); const i18n = require('./lib/i18n'); const glob = require('glob'); +const deps = require('./dependencies'); -const productDependencies = Object.keys(product.dependencies || {}); -const dependencies = Object.keys(shrinkwrap.dependencies) - .concat(productDependencies); // additional dependencies from our product configuration +const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname)); const baseModules = Object.keys(process.binding('natives')).filter(n => !/^_|\//.test(n)); const nodeModules = ['electron', 'original-fs'] - .concat(dependencies) + .concat(Object.keys(product.dependencies || {})) + .concat(_.uniq(productionDependencies.map(d => d.name))) .concat(baseModules); // Build @@ -286,8 +285,10 @@ function packageTask(platform, arch, opts) { // TODO the API should be copied to `out` during compile, not here const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts')); - const depsSrc = _.flatten(dependencies - .map(function (d) { return ['node_modules/' + d + '/**', '!node_modules/' + d + '/**/{test,tests}/**']; })); + const depsSrc = [ + ..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])), + ..._.flatten(Object.keys(product.dependencies || {}).map(d => [`node_modules/${d}/**`, `!node_modules/${d}/**/{test,tests}/**`])) + ]; const deps = gulp.src(depsSrc, { base: '.', dot: true }) .pipe(filter(['**', '!**/package-lock.json']))