Merge VS Code 1.26.1 (#2394)

* Squash merge commits for 1.26 (#1) (#2323)

* Polish tag search as per feedback (#55269)

* Polish tag search as per feedback

* Updated regex

* Allow users to opt-out of features that send online requests in the background (#55097)

* settings sweep #54690

* Minor css tweaks to enable eoverflow elipsis in more places (#55277)

* fix an issue with titlebarheight when not scaling with zoom

* Settings descriptions update #54690

* fixes #55209

* Settings editor - many padding fixes

* More space above level 2 label

* Fixing Cannot debug npm script using Yarn #55103

* Settings editor - show ellipsis when description overflows

* Settings editor - ... fix measuring around links, relayout

* Setting descriptions

* Settings editor - fix ... for some short lines, fix select container width

* Settings editor - overlay trees so scrollable shadow is full width

* Fix #54133 - missing extension settings after reload

* Settings color token description tweak

* Settings editor - disable overflow indicator temporarily, needs to be faster

* Added command to Run the selected npm script

* fixes #54452

* fixes #54929

* fixes #55248

* prefix command with extension name

* Contribute run selected to the context menu

* node-debug@1.26.6

* Allow terminal rendererType to be swapped out at runtime

Part of #53274
Fixes #55344

* Settings editor - fix not focusing search when restoring editor
setInput must be actually async. Will be fixed naturally when we aren't using winJS promises...

* Settings editor - TOC should only expand the section with a selected item

* Bump node-debug2

* Settings editor - Tree focus outlines

* Settings editor - don't blink the scrollbar when toc selection changes
And hide TOC correctly when the editor is narrow

* Settings editor - header rows should not be selectable

* fixes #54877

* change debug assignee to isi

* Settings sweep (#54690)

* workaround for #55051

* Settings sweep (#54690)

* settings sweep

#54690

* Don't try closing tags when you type > after another >

* Describe what implementation code lens does

Fixes #55370

* fix javadoc formatter setting description

* fixes #55325

* update to officical TS version

* Settings editor - Even more padding, use semibold instead of bold

* Fix #55357 - fix TOC twistie

* fixes #55288

* explorer: refresh on di change file system provider registration

fixes #53256

* Disable push to Linux repo to test standalone publisher

* New env var to notify log level to extensions #54001

* Disable snippets in extension search (when not in suggest dropdown) (#55281)

* Disable snippits in extension search (when not in suggest dropdown)

* Add monaco input contributions

* Fix bug preventing snippetSuggestions from taking effect in sub-editors

* Latest emmet helper to fix #52366

* Fix comment updates for threads within same file

* Allow extensions to log telemetry to log files #54001

* Pull latest css grammar

* files.exclude control - use same style for "add" vs "edit"

* files.exclude control - focus/keyboard behavior

* don't show menubar too early

* files.exclude - better styling

* Place cursor at end of extensions search box on autofill (#55254)

* Place cursor at end of extensions search box on autofill

* Use position instead of selection

* fix linux build issue (empty if block)

* Settings editor - fix extension category prefixes

* Settings editor - add simple ellipsis for first line that overflows, doesn't cover case when first line does not overflow but there is more text, TODO

* File/Text search provider docs

* Fixes #52655

* Include epoch (#55008)

* Fixes #53385

* Fixes #49480

*  VS Code Insiders (Users) not opening Fixes #55353

* Better handling of the case when the extension host fails to start

* Fixes #53966

*  Remove confusing Start from wordPartLeft commands ID

* vscode-xterm@3.6.0-beta12

Fixes #55488

* Initial size is set to infinity!! Fixes #55461

* Polish embeddedEditorBackground

* configuration service misses event

* Fix #55224 - fix duplicate results in multiroot workspace from splitting the diskseach query

* Select all not working in issue reporter on mac, fixes #55424

* Disable fuzzy matching for extensions autosuggest (#55498)

* Fix clipping of extensions search border in some third party themes (#55504)

* fixes #55538

* Fix bug causing an aria alert to not be shown the third time
 (and odd numbers thereafter)

* Settings editor - work around rendering glitch with webkit-line-clamp

* Settings editor - revert earlier '...' changes

* Settings editor - move enumDescription to its own div, because it disturbs -webkit-line-clamp for some reason

* Settings editor - better overflow indicator

* Don't show existing filters in autocomplete (#55495)

* Dont show existing filters in autocomplete

* Simplify

* Settings Editor: Add aria labels for input elements Fixes: #54836 (#55543)

* fixes #55223

* Update vscode-css-languageservice to 3.0.10-next.1

* Fix #55509 - settings navigation

* Fix #55519

* Fix #55520

* FIx #55524

* Fix #55556 - include wordSeparators in all search queries, so findTextInFiles can respect isWordMatch correctly

* oss updates for endgame

* Fix unit tests

* fixes #55522

* Avoid missing manifest error from bubbling up #54757

* Settings format crawl

* Search provider - Fix FileSearchProvider to return array, not progress

* Fix #55598

* Settings editor - fix NPE rendering settings with no description

* dont render inden guides in search box (#55600)

* fixes #55454

* More settings crawl

* Another change for #55598 - maxResults applies to FileSearch and TextSearch but not FileIndex

* Fix FileSearchProvider unit tests for progress change

* fixes #55561

* Settings description update for #54690

* Update setting descriptions for online services

* Minor edits

* fixes #55513

* fixes #55451

* Fix #55612 - fix findTextInFiles cancellation

* fixes #55539

* More setting description tweaks

* Setting to disable online experiments #54354

* fixes #55507

* fixes #55515

* Show online services action only in Insiders for now

* Settings editor - change toc behavior default to 'filter'

* Settings editor - nicer filter count style during search

* Fix #55617 - search viewlet icons

* Settings editor - better styling for element count indicator

* SearchProvider - fix NPE when searching extraFileResources

* Allow extends to work without json suffix

Fixes #16905

* Remove accessability options logic entirely

Follow up on #55451

* use latest version of DAP

* fixes #55490

* fixes #55122

* fixes #52332

* Avoid assumptions about git: URIs (fixes #36236)

* relative path for descriptions

* resourece: get rid of isFile context key

fixes #48275

* Register previous ids for compatibility (#53497)

* more tuning for #48275

* no need to always re-read "files explorer"

fixes #52003

* read out active composites properly

fixes #51967

* Update link colors for hc theme to meet color contrast ratio, fixes #55651

Also updated link color for `textLinkActiveForeground` to be the same as `textLinkForeground` as it wasn't properly updated

* detect 'winpty-agent.exe'; fixes #55672

* node-debug@1.26.7

* reset counter on new label

* Settings editor - fix multiple setting links in one description

* Settings editor - color code blocks in setting descriptions, fix #55532

* Settings editor - hover color in TOC

* Settings editor - fix navigation NPE

* Settings editor - fix text control width

* Settings editor - maybe fix #55684

* Fix bug causing cursor to not move on paste

* fixes #53582

* Use ctrlCmd instead of ctrl for go down from search box

* fixes #55264

* fixes #55456

* filter for spcaes before triggering search (#55611)

* Fix #55698 - don't lose filtered TOC counts when refreshing TOC

* fixes #55421

* fixes #28979

* fixes #55576

* only add check for updates to windows/linux help

* readonly files: append decoration to label

fixes #53022

* debug: do not show toolbar while initialising

fixes #55026

* Opening launch.json should not activate debug extensions

fixes #55029

* fixes #55435

* fixes #55434

* fixes #55439

* trigger menu only on altkey up

* Fix #50555 - fix settings editor memory leak

* Fix #55712 - no need to focus 'a' anymore when restoring control focus after tree render

* fixes #55335

* proper fix for readonly model

fixes #53022

* improve FoldingRangeKind spec (for #55686)

* Use class with static fields (fixes #55494)

* Fixes #53671

* fixes #54630

* [html] should disable ionic suggestions by default. Currently forces deprecated Ionic v1 suggestions in .html files while typing. Fixes #53324

* cleanup deps

* debug issues back to andre

* update electron for smoketest

* Fix #55757 - prevent settings tabs from overflowing

* Fix #53897 - revert setting menu defaults to old editor

* Add enum descriptions to `typescript.preferences.importModuleSpecifier`

* Fix #55767 - leaking style elements from settings editor

* Fix #55521 - prevent flashing when clicking in exclude control

* Update Git modified color for contrast ratio, fixes #53140

* Revert "Merge branch 'master' of github.com:Microsoft/vscode"

This reverts commit bf46b6bfbae0cab99c2863e1244a916181fa9fbc, reversing
changes made to e275a424483dfb4ed33b428c97d5e2c441d6b917.

* Revert "Revert "Merge branch 'master' of github.com:Microsoft/vscode""

This reverts commit 53949d963f39e40757557c6526332354a31d9154.

* don't ask to install an incomplete menu

* Fix NPE in terminal AccessibilityManager

Fixes #55744

* don't display fallback menu unless we've closed the last window

* fixes #55547

* Fix smoke tests for extension search box

* Update OSSREADME.json for Electron 2.0.5

* Update distro

Includes Chromium license changes

* fix #55455

* fix #55865

* fixes #55893

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation (#55805)

* Fix bug causing workspace recommendations to go away upon ignoring a recommendation

* ONly show on @recommended or @recommended:workspace

* Make more consistant

* Fix #55911

* Understand json activity (#55926)

* Understand json file activity

* Refactoring

* adding composer.json

* Distro update for experiments

* use terminal.processId for auto-attach; fixes #55918

* Reject invalid URI with vscode.openFolder (for #55891)

* improve win32 setup system vs user detection

fixes #55840

fixes #55840

delay winreg import

related to #55840

show notification earlier

related to #55840

fix #55840

update inno setup message

related to #55840

* Fix #55593 - this code only operates on local paths, so use fsPath and Uri.file instead

* Bring back the old menu due to electron 2.0 issues (#55913)

* add the old menu back for native menus

* make menu labels match

* `vscode.openFolder`: treat missing URI schema gracefully (for #55891)

* delay EH reattach; fixes #55955

* Mark all json files under appSettingsHome as settings

* Use localized strings for telemetry opt-out

* Exception when saving file editor opened from remote file provider (fixes #55051)

* Remove terminal menu from stable

Fixes 56003

* VSCode Insiders crashes on open with TypeError: Cannot read property 'lastIndexOf' of undefined. Fixes #54933

* improve fix for #55891

* fix #55916

* Improve #55891

* increase EH debugging restart delay; fixes #55955

* Revert "Don't include non-resource entries in history quick pick"

This reverts commit 37209a838e9f7e9abe6dc53ed73cdf1e03b72060.

* Diff editor: horizontal scrollbar height is smaller (fixes #56062)

* improve openFolder uri fix (correctly treat backslashes)

* fixes #56116
repair ipc for native menubar keybindings

* Fix #56240 - Open the JSON settings editor instead of the UI editor

* Fix #55536

* uriDisplay: if no formatter is registered fall back to getPathlabel

fixes #56104

* VSCode hangs when opening python file. Fixes #56377

* VS Code Hangs When Opening Specific PowerShell File. Fixes #56430

* Fix #56433 - search extraFileResources even when no folders open

* Workaround #55649

* Fix in master #56371

* Fix tests #56371

* Fix in master #56317

* increase version to 1.26.1

* Fixes #56387: Handle SIGPIPE in extension host

* fixes #56185

* Fix merge issues (part 1)

* Fix build breaks (part 1)

* Build breaks (part 2)

* Build breaks (part 3)

* More build breaks (part 4)

* Fix build breaks (part 5)

* WIP

* Fix menus

* Render query result and message panels (#2363)

* Put back query editor hot exit changes

* Fix grid changes that broke profiler (#2365)

* Update APIs for saving query editor state

* Fix restore view state for profiler and edit data

* Updating custom default themes to support 4.5:1 contrast ratio

* Test updates

* Fix Extension Manager and Windows Setup

* Update license headers

* Add appveyor and travis files back

* Fix hidden modal dropdown issue
This commit is contained in:
Karl Burtram
2018-09-04 14:55:00 -07:00
committed by GitHub
parent 3763278366
commit 81329fa7fa
2638 changed files with 118456 additions and 64012 deletions
-1
View File
@@ -17,7 +17,6 @@ const ext = require('./extensions');
const util = require('gulp-util');
const root = path.dirname(path.dirname(__dirname));
// @ts-ignore Microsoft/TypeScript#21262 complains about a require of a JSON file
const builtInExtensions = require('../builtInExtensions.json');
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
+22 -18
View File
@@ -18,18 +18,21 @@ var _ = require("underscore");
var monacodts = require("../monaco/api");
var fs = require("fs");
var reporter = reporter_1.createReporter();
var rootDir = path.join(__dirname, '../../src');
var options = require('../../src/tsconfig.json').compilerOptions;
options.verbose = false;
options.sourceMap = true;
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
options.sourceMap = false;
function getTypeScriptCompilerOptions(src) {
var rootDir = path.join(__dirname, "../../" + src);
var options = require("../../" + src + "/tsconfig.json").compilerOptions;
options.verbose = false;
options.sourceMap = true;
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
options.sourceMap = false;
}
options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir);
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
return options;
}
options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir);
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
function createCompile(build, emitError) {
var opts = _.clone(options);
function createCompile(src, build, emitError) {
var opts = _.clone(getTypeScriptCompilerOptions(src));
opts.inlineSources = !!build;
opts.noFilesystemLookup = true;
var ts = tsb.create(opts, null, null, function (err) { return reporter(err.toString()); });
@@ -51,31 +54,31 @@ function createCompile(build, emitError) {
.pipe(sourcemaps.write('.', {
addComment: false,
includeContent: !!build,
sourceRoot: options.sourceRoot
sourceRoot: opts.sourceRoot
}))
.pipe(tsFilter.restore)
.pipe(reporter.end(emitError));
return es.duplex(input, output);
};
}
function compileTask(out, build) {
function compileTask(src, out, build) {
return function () {
var compile = createCompile(build, true);
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
var compile = createCompile(src, build, true);
var srcPipe = es.merge(gulp.src(src + "/**", { base: "" + src }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
// Do not write .d.ts files to disk, as they are not needed there.
var dtsFilter = util.filter(function (data) { return !/\.d\.ts$/.test(data.path); });
return src
return srcPipe
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, false));
.pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
};
}
exports.compileTask = compileTask;
function watchTask(out, build) {
return function () {
var compile = createCompile(build);
var compile = createCompile('src', build);
var src = es.merge(gulp.src('src/**', { base: 'src' }), gulp.src('node_modules/typescript/lib/lib.d.ts'));
var watchSrc = watch('src/**', { base: 'src' });
// Do not write .d.ts files to disk, as they are not needed there.
@@ -122,6 +125,7 @@ function monacodtsTask(out, isWatch) {
fs.writeFileSync(result.filePath, result.content);
}
else {
fs.writeFileSync(result.filePath, result.content);
resultStream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
}
}
+23 -19
View File
@@ -21,19 +21,22 @@ import * as fs from 'fs';
const reporter = createReporter();
const rootDir = path.join(__dirname, '../../src');
const options = require('../../src/tsconfig.json').compilerOptions;
options.verbose = false;
options.sourceMap = true;
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
options.sourceMap = false;
function getTypeScriptCompilerOptions(src: string) {
const rootDir = path.join(__dirname, `../../${src}`);
const options = require(`../../${src}/tsconfig.json`).compilerOptions;
options.verbose = false;
options.sourceMap = true;
if (process.env['VSCODE_NO_SOURCEMAP']) { // To be used by developers in a hurry
options.sourceMap = false;
}
options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir);
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
return options;
}
options.rootDir = rootDir;
options.sourceRoot = util.toFileUri(rootDir);
options.newLine = /\r\n/.test(fs.readFileSync(__filename, 'utf8')) ? 'CRLF' : 'LF';
function createCompile(build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream {
const opts = _.clone(options);
function createCompile(src: string, build: boolean, emitError?: boolean): (token?: util.ICancellationToken) => NodeJS.ReadWriteStream {
const opts = _.clone(getTypeScriptCompilerOptions(src));
opts.inlineSources = !!build;
opts.noFilesystemLookup = true;
@@ -59,7 +62,7 @@ function createCompile(build: boolean, emitError?: boolean): (token?: util.ICanc
.pipe(sourcemaps.write('.', {
addComment: false,
includeContent: !!build,
sourceRoot: options.sourceRoot
sourceRoot: opts.sourceRoot
}))
.pipe(tsFilter.restore)
.pipe(reporter.end(emitError));
@@ -68,32 +71,32 @@ function createCompile(build: boolean, emitError?: boolean): (token?: util.ICanc
};
}
export function compileTask(out: string, build: boolean): () => NodeJS.ReadWriteStream {
export function compileTask(src: string, out: string, build: boolean): () => NodeJS.ReadWriteStream {
return function () {
const compile = createCompile(build, true);
const compile = createCompile(src, build, true);
const src = es.merge(
gulp.src('src/**', { base: 'src' }),
const srcPipe = es.merge(
gulp.src(`${src}/**`, { base: `${src}` }),
gulp.src('node_modules/typescript/lib/lib.d.ts'),
);
// Do not write .d.ts files to disk, as they are not needed there.
const dtsFilter = util.filter(data => !/\.d\.ts$/.test(data.path));
return src
return srcPipe
.pipe(compile())
.pipe(dtsFilter)
.pipe(gulp.dest(out))
.pipe(dtsFilter.restore)
.pipe(monacodtsTask(out, false));
.pipe(src !== 'src' ? es.through() : monacodtsTask(out, false));
};
}
export function watchTask(out: string, build: boolean): () => NodeJS.ReadWriteStream {
return function () {
const compile = createCompile(build);
const compile = createCompile('src', build);
const src = es.merge(
gulp.src('src/**', { base: 'src' }),
@@ -150,6 +153,7 @@ function monacodtsTask(out: string, isWatch: boolean): NodeJS.ReadWriteStream {
if (isWatch) {
fs.writeFileSync(result.filePath, result.content);
} else {
fs.writeFileSync(result.filePath, result.content);
resultStream.emit('error', 'monaco.d.ts is no longer up to date. Please run gulp watch and commit the new file.');
}
}
+1
View File
@@ -44,6 +44,7 @@ function error(err) {
var baseHeaders = {
'X-Market-Client-Id': 'VSCode Build',
'User-Agent': 'VSCode Build',
'X-Market-User-Id': '291C1CD0-051A-4123-9B4B-30D60EF52EE2',
};
function fromMarketplace(extensionName, version) {
var filterType = 7;
+1
View File
@@ -49,6 +49,7 @@ function error(err: any): Stream {
const baseHeaders = {
'X-Market-Client-Id': 'VSCode Build',
'User-Agent': 'VSCode Build',
'X-Market-User-Id': '291C1CD0-051A-4123-9B4B-30D60EF52EE2',
};
export function fromMarketplace(extensionName: string, version: string): Stream {
+17 -1
View File
@@ -34,6 +34,10 @@
"name": "vs/workbench/parts/codeEditor",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/comments",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/debug",
"project": "vscode-workbench"
@@ -74,6 +78,10 @@
"name": "vs/workbench/parts/logs",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/navigation",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/output",
"project": "vscode-workbench"
@@ -146,10 +154,18 @@
"name": "vs/workbench/parts/welcome",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/outline",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/actions",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/bulkEdit",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/services/configuration",
"project": "vscode-workbench"
@@ -219,4 +235,4 @@
"project": "vscode-preferences"
}
]
}
}
+15 -19
View File
@@ -17,7 +17,6 @@ var concat = require("gulp-concat");
var VinylFile = require("vinyl");
var bundle = require("./bundle");
var util = require("./util");
var i18n = require("./i18n");
var gulpUtil = require("gulp-util");
var flatmap = require("gulp-flatmap");
var pump = require("pump");
@@ -40,19 +39,19 @@ function loaderConfig(emptyPaths) {
}
exports.loaderConfig = loaderConfig;
var IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
function loader(bundledFileHeader, bundleLoader) {
function loader(src, bundledFileHeader, bundleLoader) {
var sources = [
'out-build/vs/loader.js'
src + "/vs/loader.js"
];
if (bundleLoader) {
sources = sources.concat([
'out-build/vs/css.js',
'out-build/vs/nls.js'
src + "/vs/css.js",
src + "/vs/nls.js"
]);
}
var isFirst = true;
return (gulp
.src(sources, { base: 'out-build' })
.src(sources, { base: "" + src })
.pipe(es.through(function (data) {
if (isFirst) {
isFirst = false;
@@ -74,7 +73,7 @@ function loader(bundledFileHeader, bundleLoader) {
return f;
})));
}
function toConcatStream(bundledFileHeader, sources, dest) {
function toConcatStream(src, bundledFileHeader, sources, dest) {
var useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
// If a bundle ends up including in any of the sources our copyright, then
// insert a fake source at the beginning of each bundle with our copyright
@@ -94,7 +93,7 @@ function toConcatStream(bundledFileHeader, sources, dest) {
}
var treatedSources = sources.map(function (source) {
var root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
var base = source.path ? root + '/out-build' : '';
var base = source.path ? root + ("/" + src) : '';
return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
base: base,
@@ -105,12 +104,13 @@ function toConcatStream(bundledFileHeader, sources, dest) {
.pipe(useSourcemaps ? util.loadSourcemaps() : es.through())
.pipe(concat(dest));
}
function toBundleStream(bundledFileHeader, bundles) {
function toBundleStream(src, bundledFileHeader, bundles) {
return es.merge(bundles.map(function (bundle) {
return toConcatStream(bundledFileHeader, bundle.sources, bundle.dest);
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
}));
}
function optimizeTask(opts) {
var src = opts.src;
var entryPoints = opts.entryPoints;
var otherSources = opts.otherSources;
var resources = opts.resources;
@@ -126,7 +126,7 @@ function optimizeTask(opts) {
if (err) {
return bundlesStream.emit('error', JSON.stringify(err));
}
toBundleStream(bundledFileHeader, result.files).pipe(bundlesStream);
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
// Remove css inlined resources
var filteredResources = resources.slice();
result.cssInlinedResources.forEach(function (resource) {
@@ -135,7 +135,7 @@ function optimizeTask(opts) {
}
filteredResources.push('!' + resource);
});
gulp.src(filteredResources, { base: 'out-build' }).pipe(resourcesStream);
gulp.src(filteredResources, { base: "" + src }).pipe(resourcesStream);
var bundleInfoArray = [];
if (opts.bundleInfo) {
bundleInfoArray.push(new VinylFile({
@@ -148,9 +148,9 @@ function optimizeTask(opts) {
});
var otherSourcesStream = es.through();
var otherSourcesStreamArr = [];
gulp.src(otherSources, { base: 'out-build' })
gulp.src(otherSources, { base: "" + src })
.pipe(es.through(function (data) {
otherSourcesStreamArr.push(toConcatStream(bundledFileHeader, [data], data.relative));
otherSourcesStreamArr.push(toConcatStream(src, bundledFileHeader, [data], data.relative));
}, function () {
if (!otherSourcesStreamArr.length) {
setTimeout(function () { otherSourcesStream.emit('end'); }, 0);
@@ -159,16 +159,12 @@ function optimizeTask(opts) {
es.merge(otherSourcesStreamArr).pipe(otherSourcesStream);
}
}));
var result = es.merge(loader(bundledFileHeader, bundleLoader), bundlesStream, otherSourcesStream, resourcesStream, bundleInfoStream);
var result = es.merge(loader(src, bundledFileHeader, bundleLoader), bundlesStream, otherSourcesStream, resourcesStream, bundleInfoStream);
return result
.pipe(sourcemaps.write('./', {
sourceRoot: null,
addComment: true,
includeContent: true
}))
.pipe(i18n.processNlsFiles({
fileHeader: bundledFileHeader,
languages: opts.languages
}))
.pipe(gulp.dest(out));
};
+23 -21
View File
@@ -18,11 +18,11 @@ import * as concat from 'gulp-concat';
import * as VinylFile from 'vinyl';
import * as bundle from './bundle';
import * as util from './util';
import * as i18n from './i18n';
import * as gulpUtil from 'gulp-util';
import * as flatmap from 'gulp-flatmap';
import * as pump from 'pump';
import * as sm from 'source-map';
import { Language } from './i18n';
const REPO_ROOT_PATH = path.join(__dirname, '../..');
@@ -52,21 +52,21 @@ declare class FileSourceMap extends VinylFile {
public sourceMap: sm.RawSourceMap;
}
function loader(bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream {
function loader(src: string, bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWriteStream {
let sources = [
'out-build/vs/loader.js'
`${src}/vs/loader.js`
];
if (bundleLoader) {
sources = sources.concat([
'out-build/vs/css.js',
'out-build/vs/nls.js'
`${src}/vs/css.js`,
`${src}/vs/nls.js`
]);
}
let isFirst = true;
return (
gulp
.src(sources, { base: 'out-build' })
.src(sources, { base: `${src}` })
.pipe(es.through(function (data) {
if (isFirst) {
isFirst = false;
@@ -89,7 +89,7 @@ function loader(bundledFileHeader: string, bundleLoader: boolean): NodeJS.ReadWr
);
}
function toConcatStream(bundledFileHeader: string, sources: bundle.IFile[], dest: string): NodeJS.ReadWriteStream {
function toConcatStream(src: string, bundledFileHeader: string, sources: bundle.IFile[], dest: string): NodeJS.ReadWriteStream {
const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
// If a bundle ends up including in any of the sources our copyright, then
@@ -112,7 +112,7 @@ function toConcatStream(bundledFileHeader: string, sources: bundle.IFile[], dest
const treatedSources = sources.map(function (source) {
const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
const base = source.path ? root + '/out-build' : '';
const base = source.path ? root + `/${src}` : '';
return new VinylFile({
path: source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake',
@@ -126,13 +126,17 @@ function toConcatStream(bundledFileHeader: string, sources: bundle.IFile[], dest
.pipe(concat(dest));
}
function toBundleStream(bundledFileHeader: string, bundles: bundle.IConcatFile[]): NodeJS.ReadWriteStream {
function toBundleStream(src:string, bundledFileHeader: string, bundles: bundle.IConcatFile[]): NodeJS.ReadWriteStream {
return es.merge(bundles.map(function (bundle) {
return toConcatStream(bundledFileHeader, bundle.sources, bundle.dest);
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
}));
}
export interface IOptimizeTaskOpts {
/**
* The folder to read files from.
*/
src: string;
/**
* (for AMD files, will get bundled and get Copyright treatment)
*/
@@ -163,11 +167,13 @@ export interface IOptimizeTaskOpts {
*/
out: string;
/**
* (languages to process)
* (out folder name)
*/
languages: i18n.Language[];
languages?: Language[];
}
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
const src = opts.src;
const entryPoints = opts.entryPoints;
const otherSources = opts.otherSources;
const resources = opts.resources;
@@ -184,7 +190,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
bundle.bundle(entryPoints, loaderConfig, function (err, result) {
if (err) { return bundlesStream.emit('error', JSON.stringify(err)); }
toBundleStream(bundledFileHeader, result.files).pipe(bundlesStream);
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
// Remove css inlined resources
const filteredResources = resources.slice();
@@ -194,7 +200,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
}
filteredResources.push('!' + resource);
});
gulp.src(filteredResources, { base: 'out-build' }).pipe(resourcesStream);
gulp.src(filteredResources, { base: `${src}` }).pipe(resourcesStream);
const bundleInfoArray: VinylFile[] = [];
if (opts.bundleInfo) {
@@ -210,9 +216,9 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
const otherSourcesStream = es.through();
const otherSourcesStreamArr: NodeJS.ReadWriteStream[] = [];
gulp.src(otherSources, { base: 'out-build' })
gulp.src(otherSources, { base: `${src}` })
.pipe(es.through(function (data) {
otherSourcesStreamArr.push(toConcatStream(bundledFileHeader, [data], data.relative));
otherSourcesStreamArr.push(toConcatStream(src, bundledFileHeader, [data], data.relative));
}, function () {
if (!otherSourcesStreamArr.length) {
setTimeout(function () { otherSourcesStream.emit('end'); }, 0);
@@ -222,7 +228,7 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
}));
const result = es.merge(
loader(bundledFileHeader, bundleLoader),
loader(src, bundledFileHeader, bundleLoader),
bundlesStream,
otherSourcesStream,
resourcesStream,
@@ -235,10 +241,6 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
addComment: true,
includeContent: true
}))
.pipe(i18n.processNlsFiles({
fileHeader: bundledFileHeader,
languages: opts.languages
}))
.pipe(gulp.dest(out));
};
}
+88 -4
View File
@@ -7,9 +7,93 @@ Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("typescript");
var fs = require("fs");
var path = require("path");
var tss = require("./treeshaking");
var REPO_ROOT = path.join(__dirname, '../../');
var SRC_DIR = path.join(REPO_ROOT, 'src');
var OUT_EDITOR = path.join(REPO_ROOT, 'out-editor');
var dirCache = {};
function writeFile(filePath, contents) {
function ensureDirs(dirPath) {
if (dirCache[dirPath]) {
return;
}
dirCache[dirPath] = true;
ensureDirs(path.dirname(dirPath));
if (fs.existsSync(dirPath)) {
return;
}
fs.mkdirSync(dirPath);
}
ensureDirs(path.dirname(filePath));
fs.writeFileSync(filePath, contents);
}
function extractEditor(options) {
var result = tss.shake(options);
for (var fileName in result) {
if (result.hasOwnProperty(fileName)) {
writeFile(path.join(options.destRoot, fileName), result[fileName]);
}
}
var copied = {};
var copyFile = function (fileName) {
if (copied[fileName]) {
return;
}
copied[fileName] = true;
var srcPath = path.join(options.sourcesRoot, fileName);
var dstPath = path.join(options.destRoot, fileName);
writeFile(dstPath, fs.readFileSync(srcPath));
};
var writeOutputFile = function (fileName, contents) {
writeFile(path.join(options.destRoot, fileName), contents);
};
for (var fileName in result) {
if (result.hasOwnProperty(fileName)) {
var fileContents = result[fileName];
var info = ts.preProcessFile(fileContents);
for (var i = info.importedFiles.length - 1; i >= 0; i--) {
var importedFileName = info.importedFiles[i].fileName;
var importedFilePath = void 0;
if (/^vs\/css!/.test(importedFileName)) {
importedFilePath = importedFileName.substr('vs/css!'.length) + '.css';
}
else {
importedFilePath = importedFileName;
}
if (/(^\.\/)|(^\.\.\/)/.test(importedFilePath)) {
importedFilePath = path.join(path.dirname(fileName), importedFilePath);
}
if (/\.css$/.test(importedFilePath)) {
transportCSS(importedFilePath, copyFile, writeOutputFile);
}
else {
if (fs.existsSync(path.join(options.sourcesRoot, importedFilePath + '.js'))) {
copyFile(importedFilePath + '.js');
}
}
}
}
}
var tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.json')).toString());
tsConfig.compilerOptions.noUnusedLocals = false;
writeOutputFile('tsconfig.json', JSON.stringify(tsConfig, null, '\t'));
[
'vs/css.build.js',
'vs/css.d.ts',
'vs/css.js',
'vs/loader.js',
'vs/monaco.d.ts',
'vs/nls.build.js',
'vs/nls.d.ts',
'vs/nls.js',
'vs/nls.mock.ts',
'typings/lib.ie11_safe_es6.d.ts',
'typings/thenable.d.ts',
'typings/es6-promise.d.ts',
'typings/require.d.ts',
].forEach(copyFile);
}
exports.extractEditor = extractEditor;
function createESMSourcesAndResources(options) {
var OUT_FOLDER = path.join(REPO_ROOT, options.outFolder);
var OUT_RESOURCES_FOLDER = path.join(REPO_ROOT, options.outResourcesFolder);
@@ -94,7 +178,7 @@ function createESMSourcesAndResources(options) {
options.entryPoints.forEach(function (entryPoint) { return enqueue(entryPoint); });
while (queue.length > 0) {
var module_1 = queue.shift();
if (transportCSS(options, module_1, enqueue, write)) {
if (transportCSS(module_1, enqueue, write)) {
continue;
}
if (transportResource(options, module_1, enqueue, write)) {
@@ -171,7 +255,7 @@ function createESMSourcesAndResources(options) {
fs.writeFileSync(path.join(OUT_FOLDER, 'vs/monaco.d.ts'), monacodts);
}
exports.createESMSourcesAndResources = createESMSourcesAndResources;
function transportCSS(options, module, enqueue, write) {
function transportCSS(module, enqueue, write) {
if (!/\.css/.test(module)) {
return false;
}
@@ -179,10 +263,10 @@ function transportCSS(options, module, enqueue, write) {
var fileContents = fs.readFileSync(filename).toString();
var inlineResources = 'base64'; // see https://github.com/Microsoft/monaco-editor/issues/148
var inlineResourcesLimit = 300000; //3000; // see https://github.com/Microsoft/monaco-editor/issues/336
var newContents = _rewriteOrInlineUrls(filename, fileContents, inlineResources === 'base64', inlineResourcesLimit);
var newContents = _rewriteOrInlineUrls(fileContents, inlineResources === 'base64', inlineResourcesLimit);
write(module, newContents);
return true;
function _rewriteOrInlineUrls(originalFileFSPath, contents, forceBase64, inlineByteLimit) {
function _rewriteOrInlineUrls(contents, forceBase64, inlineByteLimit) {
return _replaceURL(contents, function (url) {
var imagePath = path.join(path.dirname(module), url);
var fileContents = fs.readFileSync(path.join(SRC_DIR, imagePath));
+94 -4
View File
@@ -6,11 +6,101 @@
import * as ts from 'typescript';
import * as fs from 'fs';
import * as path from 'path';
import * as tss from './treeshaking';
const REPO_ROOT = path.join(__dirname, '../../');
const SRC_DIR = path.join(REPO_ROOT, 'src');
const OUT_EDITOR = path.join(REPO_ROOT, 'out-editor');
let dirCache: { [dir: string]: boolean; } = {};
function writeFile(filePath: string, contents: Buffer | string): void {
function ensureDirs(dirPath: string): void {
if (dirCache[dirPath]) {
return;
}
dirCache[dirPath] = true;
ensureDirs(path.dirname(dirPath));
if (fs.existsSync(dirPath)) {
return;
}
fs.mkdirSync(dirPath);
}
ensureDirs(path.dirname(filePath));
fs.writeFileSync(filePath, contents);
}
export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: string }): void {
let result = tss.shake(options);
for (let fileName in result) {
if (result.hasOwnProperty(fileName)) {
writeFile(path.join(options.destRoot, fileName), result[fileName]);
}
}
let copied: { [fileName:string]: boolean; } = {};
const copyFile = (fileName: string) => {
if (copied[fileName]) {
return;
}
copied[fileName] = true;
const srcPath = path.join(options.sourcesRoot, fileName);
const dstPath = path.join(options.destRoot, fileName);
writeFile(dstPath, fs.readFileSync(srcPath));
};
const writeOutputFile = (fileName: string, contents: string) => {
writeFile(path.join(options.destRoot, fileName), contents);
};
for (let fileName in result) {
if (result.hasOwnProperty(fileName)) {
const fileContents = result[fileName];
const info = ts.preProcessFile(fileContents);
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
const importedFileName = info.importedFiles[i].fileName;
let importedFilePath: string;
if (/^vs\/css!/.test(importedFileName)) {
importedFilePath = importedFileName.substr('vs/css!'.length) + '.css';
} else {
importedFilePath = importedFileName;
}
if (/(^\.\/)|(^\.\.\/)/.test(importedFilePath)) {
importedFilePath = path.join(path.dirname(fileName), importedFilePath);
}
if (/\.css$/.test(importedFilePath)) {
transportCSS(importedFilePath, copyFile, writeOutputFile);
} else {
if (fs.existsSync(path.join(options.sourcesRoot, importedFilePath + '.js'))) {
copyFile(importedFilePath + '.js');
}
}
}
}
}
const tsConfig = JSON.parse(fs.readFileSync(path.join(options.sourcesRoot, 'tsconfig.json')).toString());
tsConfig.compilerOptions.noUnusedLocals = false;
writeOutputFile('tsconfig.json', JSON.stringify(tsConfig, null, '\t'));
[
'vs/css.build.js',
'vs/css.d.ts',
'vs/css.js',
'vs/loader.js',
'vs/monaco.d.ts',
'vs/nls.build.js',
'vs/nls.d.ts',
'vs/nls.js',
'vs/nls.mock.ts',
'typings/lib.ie11_safe_es6.d.ts',
'typings/thenable.d.ts',
'typings/es6-promise.d.ts',
'typings/require.d.ts',
].forEach(copyFile);
}
export interface IOptions {
entryPoints: string[];
outFolder: string;
@@ -111,7 +201,7 @@ export function createESMSourcesAndResources(options: IOptions): void {
while (queue.length > 0) {
const module = queue.shift();
if (transportCSS(options, module, enqueue, write)) {
if (transportCSS(module, enqueue, write)) {
continue;
}
if (transportResource(options, module, enqueue, write)) {
@@ -198,7 +288,7 @@ export function createESMSourcesAndResources(options: IOptions): void {
}
function transportCSS(options: IOptions, module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
function transportCSS(module: string, enqueue: (module: string) => void, write: (path: string, contents: string | Buffer) => void): boolean {
if (!/\.css/.test(module)) {
return false;
@@ -209,11 +299,11 @@ function transportCSS(options: IOptions, module: string, enqueue: (module: strin
const inlineResources = 'base64'; // see https://github.com/Microsoft/monaco-editor/issues/148
const inlineResourcesLimit = 300000;//3000; // see https://github.com/Microsoft/monaco-editor/issues/336
const newContents = _rewriteOrInlineUrls(filename, fileContents, inlineResources === 'base64', inlineResourcesLimit);
const newContents = _rewriteOrInlineUrls(fileContents, inlineResources === 'base64', inlineResourcesLimit);
write(module, newContents);
return true;
function _rewriteOrInlineUrls(originalFileFSPath: string, contents: string, forceBase64: boolean, inlineByteLimit: number): string {
function _rewriteOrInlineUrls(contents: string, forceBase64: boolean, inlineByteLimit: number): string {
return _replaceURL(contents, (url) => {
let imagePath = path.join(path.dirname(module), url);
let fileContents = fs.readFileSync(path.join(SRC_DIR, imagePath));
-56
View File
@@ -1,56 +0,0 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
var assert = require("assert");
var util = require("../util");
function getMockTagExists(tags) {
return function (tag) { return tags.indexOf(tag) >= 0; };
}
suite('util tests', function () {
test('getPreviousVersion - patch', function () {
assert.equal(util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])), '1.2.2');
});
test('getPreviousVersion - patch invalid', function () {
try {
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
}
catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
test('getPreviousVersion - minor', function () {
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])), '1.1.3');
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])), '1.1.0');
});
test('getPreviousVersion - minor gap', function () {
assert.equal(util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])), '1.1.1');
});
test('getPreviousVersion - minor invalid', function () {
try {
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
}
catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
test('getPreviousVersion - major', function () {
assert.equal(util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])), '1.2.2');
});
test('getPreviousVersion - major invalid', function () {
try {
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
}
catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
});
-79
View File
@@ -1,79 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import assert = require('assert');
import util = require('../util');
function getMockTagExists(tags: string[]) {
return (tag: string) => tags.indexOf(tag) >= 0;
}
suite('util tests', () => {
test('getPreviousVersion - patch', () => {
assert.equal(
util.getPreviousVersion('1.2.3', getMockTagExists(['1.2.2', '1.2.1', '1.2.0', '1.1.0'])),
'1.2.2'
);
});
test('getPreviousVersion - patch invalid', () => {
try {
util.getPreviousVersion('1.2.2', getMockTagExists(['1.2.0', '1.1.0']));
} catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
test('getPreviousVersion - minor', () => {
assert.equal(
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.2', '1.1.3'])),
'1.1.3'
);
assert.equal(
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.0.0'])),
'1.1.0'
);
});
test('getPreviousVersion - minor gap', () => {
assert.equal(
util.getPreviousVersion('1.2.0', getMockTagExists(['1.1.0', '1.1.1', '1.1.3'])),
'1.1.1'
);
});
test('getPreviousVersion - minor invalid', () => {
try {
util.getPreviousVersion('1.2.0', getMockTagExists(['1.0.0']));
} catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
test('getPreviousVersion - major', () => {
assert.equal(
util.getPreviousVersion('2.0.0', getMockTagExists(['1.0.0', '1.1.0', '1.2.0', '1.2.1', '1.2.2'])),
'1.2.2'
);
});
test('getPreviousVersion - major invalid', () => {
try {
util.getPreviousVersion('3.0.0', getMockTagExists(['1.0.0']));
} catch (e) {
// expected
return;
}
throw new Error('Expected an exception');
});
});
+682
View File
@@ -0,0 +1,682 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
var fs = require("fs");
var path = require("path");
var ts = require("typescript");
var TYPESCRIPT_LIB_FOLDER = path.dirname(require.resolve('typescript/lib/lib.d.ts'));
var ShakeLevel;
(function (ShakeLevel) {
ShakeLevel[ShakeLevel["Files"] = 0] = "Files";
ShakeLevel[ShakeLevel["InnerFile"] = 1] = "InnerFile";
ShakeLevel[ShakeLevel["ClassMembers"] = 2] = "ClassMembers";
})(ShakeLevel = exports.ShakeLevel || (exports.ShakeLevel = {}));
function shake(options) {
var languageService = createTypeScriptLanguageService(options);
markNodes(languageService, options);
return generateResult(languageService, options.shakeLevel);
}
exports.shake = shake;
//#region Discovery, LanguageService & Setup
function createTypeScriptLanguageService(options) {
// Discover referenced files
var FILES = discoverAndReadFiles(options);
// Add fake usage files
options.inlineEntryPoints.forEach(function (inlineEntryPoint, index) {
FILES["inlineEntryPoint:" + index + ".ts"] = inlineEntryPoint;
});
// Resolve libs
var RESOLVED_LIBS = {};
options.libs.forEach(function (filename) {
var filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename);
RESOLVED_LIBS["defaultLib:" + filename] = fs.readFileSync(filepath).toString();
});
var host = new TypeScriptLanguageServiceHost(RESOLVED_LIBS, FILES, options.compilerOptions);
return ts.createLanguageService(host);
}
/**
* Read imports and follow them until all files have been handled
*/
function discoverAndReadFiles(options) {
var FILES = {};
var in_queue = Object.create(null);
var queue = [];
var enqueue = function (moduleId) {
if (in_queue[moduleId]) {
return;
}
in_queue[moduleId] = true;
queue.push(moduleId);
};
options.entryPoints.forEach(function (entryPoint) { return enqueue(entryPoint); });
while (queue.length > 0) {
var moduleId = queue.shift();
var dts_filename = path.join(options.sourcesRoot, moduleId + '.d.ts');
if (fs.existsSync(dts_filename)) {
var dts_filecontents = fs.readFileSync(dts_filename).toString();
FILES[moduleId + '.d.ts'] = dts_filecontents;
continue;
}
var ts_filename = void 0;
if (options.redirects[moduleId]) {
ts_filename = path.join(options.sourcesRoot, options.redirects[moduleId] + '.ts');
}
else {
ts_filename = path.join(options.sourcesRoot, moduleId + '.ts');
}
var ts_filecontents = fs.readFileSync(ts_filename).toString();
var info = ts.preProcessFile(ts_filecontents);
for (var i = info.importedFiles.length - 1; i >= 0; i--) {
var importedFileName = info.importedFiles[i].fileName;
if (options.importIgnorePattern.test(importedFileName)) {
// Ignore vs/css! imports
continue;
}
var importedModuleId = importedFileName;
if (/(^\.\/)|(^\.\.\/)/.test(importedModuleId)) {
importedModuleId = path.join(path.dirname(moduleId), importedModuleId);
}
enqueue(importedModuleId);
}
FILES[moduleId + '.ts'] = ts_filecontents;
}
return FILES;
}
/**
* A TypeScript language service host
*/
var TypeScriptLanguageServiceHost = /** @class */ (function () {
function TypeScriptLanguageServiceHost(libs, files, compilerOptions) {
this._libs = libs;
this._files = files;
this._compilerOptions = compilerOptions;
}
// --- language service host ---------------
TypeScriptLanguageServiceHost.prototype.getCompilationSettings = function () {
return this._compilerOptions;
};
TypeScriptLanguageServiceHost.prototype.getScriptFileNames = function () {
return ([]
.concat(Object.keys(this._libs))
.concat(Object.keys(this._files)));
};
TypeScriptLanguageServiceHost.prototype.getScriptVersion = function (fileName) {
return '1';
};
TypeScriptLanguageServiceHost.prototype.getProjectVersion = function () {
return '1';
};
TypeScriptLanguageServiceHost.prototype.getScriptSnapshot = function (fileName) {
if (this._files.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._files[fileName]);
}
else if (this._libs.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._libs[fileName]);
}
else {
return ts.ScriptSnapshot.fromString('');
}
};
TypeScriptLanguageServiceHost.prototype.getScriptKind = function (fileName) {
return ts.ScriptKind.TS;
};
TypeScriptLanguageServiceHost.prototype.getCurrentDirectory = function () {
return '';
};
TypeScriptLanguageServiceHost.prototype.getDefaultLibFileName = function (options) {
return 'defaultLib:lib.d.ts';
};
TypeScriptLanguageServiceHost.prototype.isDefaultLibFileName = function (fileName) {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
};
return TypeScriptLanguageServiceHost;
}());
//#endregion
//#region Tree Shaking
var NodeColor;
(function (NodeColor) {
NodeColor[NodeColor["White"] = 0] = "White";
NodeColor[NodeColor["Gray"] = 1] = "Gray";
NodeColor[NodeColor["Black"] = 2] = "Black";
})(NodeColor || (NodeColor = {}));
function getColor(node) {
return node.$$$color || 0 /* White */;
}
function setColor(node, color) {
node.$$$color = color;
}
function nodeOrParentIsBlack(node) {
while (node) {
var color = getColor(node);
if (color === 2 /* Black */) {
return true;
}
node = node.parent;
}
return false;
}
function nodeOrChildIsBlack(node) {
if (getColor(node) === 2 /* Black */) {
return true;
}
for (var _i = 0, _a = node.getChildren(); _i < _a.length; _i++) {
var child = _a[_i];
if (nodeOrChildIsBlack(child)) {
return true;
}
}
return false;
}
function markNodes(languageService, options) {
var program = languageService.getProgram();
if (options.shakeLevel === 0 /* Files */) {
// Mark all source files Black
program.getSourceFiles().forEach(function (sourceFile) {
setColor(sourceFile, 2 /* Black */);
});
return;
}
var black_queue = [];
var gray_queue = [];
var sourceFilesLoaded = {};
function enqueueTopLevelModuleStatements(sourceFile) {
sourceFile.forEachChild(function (node) {
if (ts.isImportDeclaration(node)) {
if (!node.importClause && ts.isStringLiteral(node.moduleSpecifier)) {
setColor(node, 2 /* Black */);
enqueueImport(node, node.moduleSpecifier.text);
}
return;
}
if (ts.isExportDeclaration(node)) {
if (ts.isStringLiteral(node.moduleSpecifier)) {
setColor(node, 2 /* Black */);
enqueueImport(node, node.moduleSpecifier.text);
}
return;
}
if (ts.isExpressionStatement(node)
|| ts.isIfStatement(node)
|| ts.isIterationStatement(node, true)
|| ts.isExportAssignment(node)) {
enqueue_black(node);
}
if (ts.isImportEqualsDeclaration(node)) {
if (/export/.test(node.getFullText(sourceFile))) {
// e.g. "export import Severity = BaseSeverity;"
enqueue_black(node);
}
}
});
}
function enqueue_gray(node) {
if (nodeOrParentIsBlack(node) || getColor(node) === 1 /* Gray */) {
return;
}
setColor(node, 1 /* Gray */);
gray_queue.push(node);
}
function enqueue_black(node) {
var previousColor = getColor(node);
if (previousColor === 2 /* Black */) {
return;
}
if (previousColor === 1 /* Gray */) {
// remove from gray queue
gray_queue.splice(gray_queue.indexOf(node), 1);
setColor(node, 0 /* White */);
// add to black queue
enqueue_black(node);
// // move from one queue to the other
// black_queue.push(node);
// setColor(node, NodeColor.Black);
return;
}
if (nodeOrParentIsBlack(node)) {
return;
}
var fileName = node.getSourceFile().fileName;
if (/^defaultLib:/.test(fileName) || /\.d\.ts$/.test(fileName)) {
setColor(node, 2 /* Black */);
return;
}
var sourceFile = node.getSourceFile();
if (!sourceFilesLoaded[sourceFile.fileName]) {
sourceFilesLoaded[sourceFile.fileName] = true;
enqueueTopLevelModuleStatements(sourceFile);
}
if (ts.isSourceFile(node)) {
return;
}
setColor(node, 2 /* Black */);
black_queue.push(node);
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
var references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth());
if (references) {
for (var i = 0, len = references.length; i < len; i++) {
var reference = references[i];
var referenceSourceFile = program.getSourceFile(reference.fileName);
var referenceNode = getTokenAtPosition(referenceSourceFile, reference.textSpan.start, false, false);
if (ts.isMethodDeclaration(referenceNode.parent)
|| ts.isPropertyDeclaration(referenceNode.parent)
|| ts.isGetAccessor(referenceNode.parent)
|| ts.isSetAccessor(referenceNode.parent)) {
enqueue_gray(referenceNode.parent);
}
}
}
}
}
function enqueueFile(filename) {
var sourceFile = program.getSourceFile(filename);
if (!sourceFile) {
console.warn("Cannot find source file " + filename);
return;
}
enqueue_black(sourceFile);
}
function enqueueImport(node, importText) {
if (options.importIgnorePattern.test(importText)) {
// this import should be ignored
return;
}
var nodeSourceFile = node.getSourceFile();
var fullPath;
if (/(^\.\/)|(^\.\.\/)/.test(importText)) {
fullPath = path.join(path.dirname(nodeSourceFile.fileName), importText) + '.ts';
}
else {
fullPath = importText + '.ts';
}
enqueueFile(fullPath);
}
options.entryPoints.forEach(function (moduleId) { return enqueueFile(moduleId + '.ts'); });
// Add fake usage files
options.inlineEntryPoints.forEach(function (_, index) { return enqueueFile("inlineEntryPoint:" + index + ".ts"); });
var step = 0;
var checker = program.getTypeChecker();
var _loop_1 = function () {
++step;
var node = void 0;
if (step % 100 === 0) {
console.log(step + "/" + (step + black_queue.length + gray_queue.length) + " (" + black_queue.length + ", " + gray_queue.length + ")");
}
if (black_queue.length === 0) {
for (var i = 0; i < gray_queue.length; i++) {
var node_1 = gray_queue[i];
var nodeParent = node_1.parent;
if ((ts.isClassDeclaration(nodeParent) || ts.isInterfaceDeclaration(nodeParent)) && nodeOrChildIsBlack(nodeParent)) {
gray_queue.splice(i, 1);
black_queue.push(node_1);
setColor(node_1, 2 /* Black */);
i--;
}
}
}
if (black_queue.length > 0) {
node = black_queue.shift();
}
else {
return "break";
}
var nodeSourceFile = node.getSourceFile();
var loop = function (node) {
var _a = getRealNodeSymbol(checker, node), symbol = _a[0], symbolImportNode = _a[1];
if (symbolImportNode) {
setColor(symbolImportNode, 2 /* Black */);
}
if (symbol && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) {
for (var i = 0, len = symbol.declarations.length; i < len; i++) {
var declaration = symbol.declarations[i];
if (ts.isSourceFile(declaration)) {
// Do not enqueue full source files
// (they can be the declaration of a module import)
continue;
}
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration))) {
enqueue_black(declaration.name);
for (var j = 0; j < declaration.members.length; j++) {
var member = declaration.members[j];
var memberName = member.name ? member.name.getText() : null;
if (ts.isConstructorDeclaration(member)
|| ts.isConstructSignatureDeclaration(member)
|| ts.isIndexSignatureDeclaration(member)
|| ts.isCallSignatureDeclaration(member)
|| memberName === 'toJSON'
|| memberName === 'toString'
|| memberName === 'dispose' // TODO: keeping all `dispose` methods
) {
enqueue_black(member);
}
}
// queue the heritage clauses
if (declaration.heritageClauses) {
for (var _i = 0, _b = declaration.heritageClauses; _i < _b.length; _i++) {
var heritageClause = _b[_i];
enqueue_black(heritageClause);
}
}
}
else {
enqueue_black(declaration);
}
}
}
node.forEachChild(loop);
};
node.forEachChild(loop);
};
while (black_queue.length > 0 || gray_queue.length > 0) {
var state_1 = _loop_1();
if (state_1 === "break")
break;
}
}
function nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol) {
for (var i = 0, len = symbol.declarations.length; i < len; i++) {
var declaration = symbol.declarations[i];
var declarationSourceFile = declaration.getSourceFile();
if (nodeSourceFile === declarationSourceFile) {
if (declaration.pos <= node.pos && node.end <= declaration.end) {
return true;
}
}
}
return false;
}
function generateResult(languageService, shakeLevel) {
var program = languageService.getProgram();
var result = {};
var writeFile = function (filePath, contents) {
result[filePath] = contents;
};
program.getSourceFiles().forEach(function (sourceFile) {
var fileName = sourceFile.fileName;
if (/^defaultLib:/.test(fileName)) {
return;
}
var destination = fileName;
if (/\.d\.ts$/.test(fileName)) {
if (nodeOrChildIsBlack(sourceFile)) {
writeFile(destination, sourceFile.text);
}
return;
}
var text = sourceFile.text;
var result = '';
function keep(node) {
result += text.substring(node.pos, node.end);
}
function write(data) {
result += data;
}
function writeMarkedNodes(node) {
if (getColor(node) === 2 /* Black */) {
return keep(node);
}
// Always keep certain top-level statements
if (ts.isSourceFile(node.parent)) {
if (ts.isExpressionStatement(node) && ts.isStringLiteral(node.expression) && node.expression.text === 'use strict') {
return keep(node);
}
if (ts.isVariableStatement(node) && nodeOrChildIsBlack(node)) {
return keep(node);
}
}
// Keep the entire import in import * as X cases
if (ts.isImportDeclaration(node)) {
if (node.importClause && node.importClause.namedBindings) {
if (ts.isNamespaceImport(node.importClause.namedBindings)) {
if (getColor(node.importClause.namedBindings) === 2 /* Black */) {
return keep(node);
}
}
else {
var survivingImports = [];
for (var i = 0; i < node.importClause.namedBindings.elements.length; i++) {
var importNode = node.importClause.namedBindings.elements[i];
if (getColor(importNode) === 2 /* Black */) {
survivingImports.push(importNode.getFullText(sourceFile));
}
}
var leadingTriviaWidth = node.getLeadingTriviaWidth();
var leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth);
if (survivingImports.length > 0) {
if (node.importClause && getColor(node.importClause) === 2 /* Black */) {
return write(leadingTrivia + "import " + node.importClause.name.text + ", {" + survivingImports.join(',') + " } from" + node.moduleSpecifier.getFullText(sourceFile) + ";");
}
return write(leadingTrivia + "import {" + survivingImports.join(',') + " } from" + node.moduleSpecifier.getFullText(sourceFile) + ";");
}
else {
if (node.importClause && getColor(node.importClause) === 2 /* Black */) {
return write(leadingTrivia + "import " + node.importClause.name.text + " from" + node.moduleSpecifier.getFullText(sourceFile) + ";");
}
}
}
}
else {
if (node.importClause && getColor(node.importClause) === 2 /* Black */) {
return keep(node);
}
}
}
if (shakeLevel === 2 /* ClassMembers */ && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) {
var toWrite = node.getFullText();
for (var i = node.members.length - 1; i >= 0; i--) {
var member = node.members[i];
if (getColor(member) === 2 /* Black */) {
// keep method
continue;
}
if (/^_(.*)Brand$/.test(member.name.getText())) {
// TODO: keep all members ending with `Brand`...
continue;
}
var pos = member.pos - node.pos;
var end = member.end - node.pos;
toWrite = toWrite.substring(0, pos) + toWrite.substring(end);
}
return write(toWrite);
}
if (ts.isFunctionDeclaration(node)) {
// Do not go inside functions if they haven't been marked
return;
}
node.forEachChild(writeMarkedNodes);
}
if (getColor(sourceFile) !== 2 /* Black */) {
if (!nodeOrChildIsBlack(sourceFile)) {
// none of the elements are reachable => don't write this file at all!
return;
}
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
}
else {
result = text;
}
writeFile(destination, result);
});
return result;
}
//#endregion
//#region Utils
/**
* Returns the node's symbol and the `import` node (if the symbol resolved from a different module)
*/
function getRealNodeSymbol(checker, node) {
/**
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
*/
/* @internal */
function getContainingObjectLiteralElement(node) {
switch (node.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NumericLiteral:
if (node.parent.kind === ts.SyntaxKind.ComputedPropertyName) {
return ts.isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
}
// falls through
case ts.SyntaxKind.Identifier:
return ts.isObjectLiteralElement(node.parent) &&
(node.parent.parent.kind === ts.SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === ts.SyntaxKind.JsxAttributes) &&
node.parent.name === node ? node.parent : undefined;
}
return undefined;
}
function getPropertySymbolsFromType(type, propName) {
function getTextOfPropertyName(name) {
function isStringOrNumericLiteral(node) {
var kind = node.kind;
return kind === ts.SyntaxKind.StringLiteral
|| kind === ts.SyntaxKind.NumericLiteral;
}
switch (name.kind) {
case ts.SyntaxKind.Identifier:
return name.text;
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NumericLiteral:
return name.text;
case ts.SyntaxKind.ComputedPropertyName:
return isStringOrNumericLiteral(name.expression) ? name.expression.text : undefined;
}
}
var name = getTextOfPropertyName(propName);
if (name && type) {
var result = [];
var symbol_1 = type.getProperty(name);
if (type.flags & ts.TypeFlags.Union) {
for (var _i = 0, _a = type.types; _i < _a.length; _i++) {
var t = _a[_i];
var symbol_2 = t.getProperty(name);
if (symbol_2) {
result.push(symbol_2);
}
}
return result;
}
if (symbol_1) {
result.push(symbol_1);
return result;
}
}
return undefined;
}
function getPropertySymbolsFromContextualType(typeChecker, node) {
var objectLiteral = node.parent;
var contextualType = typeChecker.getContextualType(objectLiteral);
return getPropertySymbolsFromType(contextualType, node.name);
}
// Go to the original declaration for cases:
//
// (1) when the aliased symbol was declared in the location(parent).
// (2) when the aliased symbol is originating from an import.
//
function shouldSkipAlias(node, declaration) {
if (node.kind !== ts.SyntaxKind.Identifier) {
return false;
}
if (node.parent === declaration) {
return true;
}
switch (declaration.kind) {
case ts.SyntaxKind.ImportClause:
case ts.SyntaxKind.ImportEqualsDeclaration:
return true;
case ts.SyntaxKind.ImportSpecifier:
return declaration.parent.kind === ts.SyntaxKind.NamedImports;
default:
return false;
}
}
if (!ts.isShorthandPropertyAssignment(node)) {
if (node.getChildCount() !== 0) {
return [null, null];
}
}
var symbol = checker.getSymbolAtLocation(node);
var importNode = null;
if (symbol && symbol.flags & ts.SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) {
var aliased = checker.getAliasedSymbol(symbol);
if (aliased.declarations) {
// We should mark the import as visited
importNode = symbol.declarations[0];
symbol = aliased;
}
}
if (symbol) {
// Because name in short-hand property assignment has two different meanings: property name and property value,
// using go-to-definition at such position should go to the variable declaration of the property value rather than
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === ts.SyntaxKind.ShorthandPropertyAssignment) {
symbol = checker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
}
// If the node is the name of a BindingElement within an ObjectBindingPattern instead of just returning the
// declaration the symbol (which is itself), we should try to get to the original type of the ObjectBindingPattern
// and return the property declaration for the referenced property.
// For example:
// import('./foo').then(({ b/*goto*/ar }) => undefined); => should get use to the declaration in file "./foo"
//
// function bar<T>(onfulfilled: (value: T) => void) { //....}
// interface Test {
// pr/*destination*/op1: number
// }
// bar<Test>(({pr/*goto*/op1})=>{});
if (ts.isPropertyName(node) && ts.isBindingElement(node.parent) && ts.isObjectBindingPattern(node.parent.parent) &&
(node === (node.parent.propertyName || node.parent.name))) {
var type = checker.getTypeAtLocation(node.parent.parent);
if (type) {
var propSymbols = getPropertySymbolsFromType(type, node);
if (propSymbols) {
symbol = propSymbols[0];
}
}
}
// If the current location we want to find its definition is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this for goto-definition.
// For example
// interface Props{
// /*first*/prop1: number
// prop2: boolean
// }
// function Foo(arg: Props) {}
// Foo( { pr/*1*/op1: 10, prop2: false })
var element = getContainingObjectLiteralElement(node);
if (element && checker.getContextualType(element.parent)) {
var propertySymbols = getPropertySymbolsFromContextualType(checker, element);
if (propertySymbols) {
symbol = propertySymbols[0];
}
}
}
if (symbol && symbol.declarations) {
return [symbol, importNode];
}
return [null, null];
}
/** Get the token whose text contains the position */
function getTokenAtPosition(sourceFile, position, allowPositionInLeadingTrivia, includeEndPosition) {
var current = sourceFile;
outer: while (true) {
// find the child that contains 'position'
for (var _i = 0, _a = current.getChildren(); _i < _a.length; _i++) {
var child = _a[_i];
var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, /*includeJsDoc*/ true);
if (start > position) {
// If this child begins after position, then all subsequent children will as well.
break;
}
var end = child.getEnd();
if (position < end || (position === end && (child.kind === ts.SyntaxKind.EndOfFileToken || includeEndPosition))) {
current = child;
continue outer;
}
}
return current;
}
}
+817
View File
@@ -0,0 +1,817 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
const TYPESCRIPT_LIB_FOLDER = path.dirname(require.resolve('typescript/lib/lib.d.ts'));
export const enum ShakeLevel {
Files = 0,
InnerFile = 1,
ClassMembers = 2
}
export interface ITreeShakingOptions {
/**
* The full path to the root where sources are.
*/
sourcesRoot: string;
/**
* Module ids.
* e.g. `vs/editor/editor.main` or `index`
*/
entryPoints: string[];
/**
* Inline usages.
*/
inlineEntryPoints: string[];
/**
* TypeScript libs.
* e.g. `lib.d.ts`, `lib.es2015.collection.d.ts`
*/
libs: string[];
/**
* TypeScript compiler options.
*/
compilerOptions: ts.CompilerOptions;
/**
* The shake level to perform.
*/
shakeLevel: ShakeLevel;
/**
* regex pattern to ignore certain imports e.g. `vs/css!` imports
*/
importIgnorePattern: RegExp;
redirects: { [module: string]: string; };
}
export interface ITreeShakingResult {
[file: string]: string;
}
export function shake(options: ITreeShakingOptions): ITreeShakingResult {
const languageService = createTypeScriptLanguageService(options);
markNodes(languageService, options);
return generateResult(languageService, options.shakeLevel);
}
//#region Discovery, LanguageService & Setup
function createTypeScriptLanguageService(options: ITreeShakingOptions): ts.LanguageService {
// Discover referenced files
const FILES = discoverAndReadFiles(options);
// Add fake usage files
options.inlineEntryPoints.forEach((inlineEntryPoint, index) => {
FILES[`inlineEntryPoint:${index}.ts`] = inlineEntryPoint;
});
// Resolve libs
const RESOLVED_LIBS: ILibMap = {};
options.libs.forEach((filename) => {
const filepath = path.join(TYPESCRIPT_LIB_FOLDER, filename);
RESOLVED_LIBS[`defaultLib:${filename}`] = fs.readFileSync(filepath).toString();
});
const host = new TypeScriptLanguageServiceHost(RESOLVED_LIBS, FILES, options.compilerOptions);
return ts.createLanguageService(host);
}
/**
* Read imports and follow them until all files have been handled
*/
function discoverAndReadFiles(options: ITreeShakingOptions): IFileMap {
const FILES: IFileMap = {};
const in_queue: { [module: string]: boolean; } = Object.create(null);
const queue: string[] = [];
const enqueue = (moduleId: string) => {
if (in_queue[moduleId]) {
return;
}
in_queue[moduleId] = true;
queue.push(moduleId);
};
options.entryPoints.forEach((entryPoint) => enqueue(entryPoint));
while (queue.length > 0) {
const moduleId = queue.shift();
const dts_filename = path.join(options.sourcesRoot, moduleId + '.d.ts');
if (fs.existsSync(dts_filename)) {
const dts_filecontents = fs.readFileSync(dts_filename).toString();
FILES[moduleId + '.d.ts'] = dts_filecontents;
continue;
}
let ts_filename: string;
if (options.redirects[moduleId]) {
ts_filename = path.join(options.sourcesRoot, options.redirects[moduleId] + '.ts');
} else {
ts_filename = path.join(options.sourcesRoot, moduleId + '.ts');
}
const ts_filecontents = fs.readFileSync(ts_filename).toString();
const info = ts.preProcessFile(ts_filecontents);
for (let i = info.importedFiles.length - 1; i >= 0; i--) {
const importedFileName = info.importedFiles[i].fileName;
if (options.importIgnorePattern.test(importedFileName)) {
// Ignore vs/css! imports
continue;
}
let importedModuleId = importedFileName;
if (/(^\.\/)|(^\.\.\/)/.test(importedModuleId)) {
importedModuleId = path.join(path.dirname(moduleId), importedModuleId);
}
enqueue(importedModuleId);
}
FILES[moduleId + '.ts'] = ts_filecontents;
}
return FILES;
}
interface ILibMap { [libName: string]: string; }
interface IFileMap { [fileName: string]: string; }
/**
* A TypeScript language service host
*/
class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost {
private readonly _libs: ILibMap;
private readonly _files: IFileMap;
private readonly _compilerOptions: ts.CompilerOptions;
constructor(libs: ILibMap, files: IFileMap, compilerOptions: ts.CompilerOptions) {
this._libs = libs;
this._files = files;
this._compilerOptions = compilerOptions;
}
// --- language service host ---------------
getCompilationSettings(): ts.CompilerOptions {
return this._compilerOptions;
}
getScriptFileNames(): string[] {
return (
[]
.concat(Object.keys(this._libs))
.concat(Object.keys(this._files))
);
}
getScriptVersion(fileName: string): string {
return '1';
}
getProjectVersion(): string {
return '1';
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
if (this._files.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._files[fileName]);
} else if (this._libs.hasOwnProperty(fileName)) {
return ts.ScriptSnapshot.fromString(this._libs[fileName]);
} else {
return ts.ScriptSnapshot.fromString('');
}
}
getScriptKind(fileName: string): ts.ScriptKind {
return ts.ScriptKind.TS;
}
getCurrentDirectory(): string {
return '';
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
return 'defaultLib:lib.d.ts';
}
isDefaultLibFileName(fileName: string): boolean {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
}
//#endregion
//#region Tree Shaking
const enum NodeColor {
White = 0,
Gray = 1,
Black = 2
}
function getColor(node: ts.Node): NodeColor {
return (<any>node).$$$color || NodeColor.White;
}
function setColor(node: ts.Node, color: NodeColor): void {
(<any>node).$$$color = color;
}
function nodeOrParentIsBlack(node: ts.Node): boolean {
while (node) {
const color = getColor(node);
if (color === NodeColor.Black) {
return true;
}
node = node.parent;
}
return false;
}
function nodeOrChildIsBlack(node: ts.Node): boolean {
if (getColor(node) === NodeColor.Black) {
return true;
}
for (const child of node.getChildren()) {
if (nodeOrChildIsBlack(child)) {
return true;
}
}
return false;
}
function markNodes(languageService: ts.LanguageService, options: ITreeShakingOptions) {
const program = languageService.getProgram();
if (options.shakeLevel === ShakeLevel.Files) {
// Mark all source files Black
program.getSourceFiles().forEach((sourceFile) => {
setColor(sourceFile, NodeColor.Black);
});
return;
}
const black_queue: ts.Node[] = [];
const gray_queue: ts.Node[] = [];
const sourceFilesLoaded: { [fileName: string]: boolean } = {};
function enqueueTopLevelModuleStatements(sourceFile: ts.SourceFile): void {
sourceFile.forEachChild((node: ts.Node) => {
if (ts.isImportDeclaration(node)) {
if (!node.importClause && ts.isStringLiteral(node.moduleSpecifier)) {
setColor(node, NodeColor.Black);
enqueueImport(node, node.moduleSpecifier.text);
}
return;
}
if (ts.isExportDeclaration(node)) {
if (ts.isStringLiteral(node.moduleSpecifier)) {
setColor(node, NodeColor.Black);
enqueueImport(node, node.moduleSpecifier.text);
}
return;
}
if (
ts.isExpressionStatement(node)
|| ts.isIfStatement(node)
|| ts.isIterationStatement(node, true)
|| ts.isExportAssignment(node)
) {
enqueue_black(node);
}
if (ts.isImportEqualsDeclaration(node)) {
if (/export/.test(node.getFullText(sourceFile))) {
// e.g. "export import Severity = BaseSeverity;"
enqueue_black(node);
}
}
});
}
function enqueue_gray(node: ts.Node): void {
if (nodeOrParentIsBlack(node) || getColor(node) === NodeColor.Gray) {
return;
}
setColor(node, NodeColor.Gray);
gray_queue.push(node);
}
function enqueue_black(node: ts.Node): void {
const previousColor = getColor(node);
if (previousColor === NodeColor.Black) {
return;
}
if (previousColor === NodeColor.Gray) {
// remove from gray queue
gray_queue.splice(gray_queue.indexOf(node), 1);
setColor(node, NodeColor.White);
// add to black queue
enqueue_black(node);
// // move from one queue to the other
// black_queue.push(node);
// setColor(node, NodeColor.Black);
return;
}
if (nodeOrParentIsBlack(node)) {
return;
}
const fileName = node.getSourceFile().fileName;
if (/^defaultLib:/.test(fileName) || /\.d\.ts$/.test(fileName)) {
setColor(node, NodeColor.Black);
return;
}
const sourceFile = node.getSourceFile();
if (!sourceFilesLoaded[sourceFile.fileName]) {
sourceFilesLoaded[sourceFile.fileName] = true;
enqueueTopLevelModuleStatements(sourceFile);
}
if (ts.isSourceFile(node)) {
return;
}
setColor(node, NodeColor.Black);
black_queue.push(node);
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
const references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth());
if (references) {
for (let i = 0, len = references.length; i < len; i++) {
const reference = references[i];
const referenceSourceFile = program.getSourceFile(reference.fileName);
const referenceNode = getTokenAtPosition(referenceSourceFile, reference.textSpan.start, false, false);
if (
ts.isMethodDeclaration(referenceNode.parent)
|| ts.isPropertyDeclaration(referenceNode.parent)
|| ts.isGetAccessor(referenceNode.parent)
|| ts.isSetAccessor(referenceNode.parent)
) {
enqueue_gray(referenceNode.parent);
}
}
}
}
}
function enqueueFile(filename: string): void {
const sourceFile = program.getSourceFile(filename);
if (!sourceFile) {
console.warn(`Cannot find source file ${filename}`);
return;
}
enqueue_black(sourceFile);
}
function enqueueImport(node: ts.Node, importText: string): void {
if (options.importIgnorePattern.test(importText)) {
// this import should be ignored
return;
}
const nodeSourceFile = node.getSourceFile();
let fullPath: string;
if (/(^\.\/)|(^\.\.\/)/.test(importText)) {
fullPath = path.join(path.dirname(nodeSourceFile.fileName), importText) + '.ts';
} else {
fullPath = importText + '.ts';
}
enqueueFile(fullPath);
}
options.entryPoints.forEach(moduleId => enqueueFile(moduleId + '.ts'));
// Add fake usage files
options.inlineEntryPoints.forEach((_, index) => enqueueFile(`inlineEntryPoint:${index}.ts`));
let step = 0;
const checker = program.getTypeChecker();
while (black_queue.length > 0 || gray_queue.length > 0) {
++step;
let node: ts.Node;
if (step % 100 === 0) {
console.log(`${step}/${step+black_queue.length+gray_queue.length} (${black_queue.length}, ${gray_queue.length})`);
}
if (black_queue.length === 0) {
for (let i = 0; i < gray_queue.length; i++) {
const node = gray_queue[i];
const nodeParent = node.parent;
if ((ts.isClassDeclaration(nodeParent) || ts.isInterfaceDeclaration(nodeParent)) && nodeOrChildIsBlack(nodeParent)) {
gray_queue.splice(i, 1);
black_queue.push(node);
setColor(node, NodeColor.Black);
i--;
}
}
}
if (black_queue.length > 0) {
node = black_queue.shift();
} else {
// only gray nodes remaining...
break;
}
const nodeSourceFile = node.getSourceFile();
const loop = (node: ts.Node) => {
const [symbol, symbolImportNode] = getRealNodeSymbol(checker, node);
if (symbolImportNode) {
setColor(symbolImportNode, NodeColor.Black);
}
if (symbol && !nodeIsInItsOwnDeclaration(nodeSourceFile, node, symbol)) {
for (let i = 0, len = symbol.declarations.length; i < len; i++) {
const declaration = symbol.declarations[i];
if (ts.isSourceFile(declaration)) {
// Do not enqueue full source files
// (they can be the declaration of a module import)
continue;
}
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(declaration) || ts.isInterfaceDeclaration(declaration))) {
enqueue_black(declaration.name);
for (let j = 0; j < declaration.members.length; j++) {
const member = declaration.members[j];
const memberName = member.name ? member.name.getText() : null;
if (
ts.isConstructorDeclaration(member)
|| ts.isConstructSignatureDeclaration(member)
|| ts.isIndexSignatureDeclaration(member)
|| ts.isCallSignatureDeclaration(member)
|| memberName === 'toJSON'
|| memberName === 'toString'
|| memberName === 'dispose'// TODO: keeping all `dispose` methods
) {
enqueue_black(member);
}
}
// queue the heritage clauses
if (declaration.heritageClauses) {
for (let heritageClause of declaration.heritageClauses) {
enqueue_black(heritageClause);
}
}
} else {
enqueue_black(declaration);
}
}
}
node.forEachChild(loop);
};
node.forEachChild(loop);
}
}
function nodeIsInItsOwnDeclaration(nodeSourceFile: ts.SourceFile, node: ts.Node, symbol: ts.Symbol): boolean {
for (let i = 0, len = symbol.declarations.length; i < len; i++) {
const declaration = symbol.declarations[i];
const declarationSourceFile = declaration.getSourceFile();
if (nodeSourceFile === declarationSourceFile) {
if (declaration.pos <= node.pos && node.end <= declaration.end) {
return true;
}
}
}
return false;
}
function generateResult(languageService: ts.LanguageService, shakeLevel: ShakeLevel): ITreeShakingResult {
const program = languageService.getProgram();
let result: ITreeShakingResult = {};
const writeFile = (filePath: string, contents: string): void => {
result[filePath] = contents;
};
program.getSourceFiles().forEach((sourceFile) => {
const fileName = sourceFile.fileName;
if (/^defaultLib:/.test(fileName)) {
return;
}
const destination = fileName;
if (/\.d\.ts$/.test(fileName)) {
if (nodeOrChildIsBlack(sourceFile)) {
writeFile(destination, sourceFile.text);
}
return;
}
let text = sourceFile.text;
let result = '';
function keep(node: ts.Node): void {
result += text.substring(node.pos, node.end);
}
function write(data: string): void {
result += data;
}
function writeMarkedNodes(node: ts.Node): void {
if (getColor(node) === NodeColor.Black) {
return keep(node);
}
// Always keep certain top-level statements
if (ts.isSourceFile(node.parent)) {
if (ts.isExpressionStatement(node) && ts.isStringLiteral(node.expression) && node.expression.text === 'use strict') {
return keep(node);
}
if (ts.isVariableStatement(node) && nodeOrChildIsBlack(node)) {
return keep(node);
}
}
// Keep the entire import in import * as X cases
if (ts.isImportDeclaration(node)) {
if (node.importClause && node.importClause.namedBindings) {
if (ts.isNamespaceImport(node.importClause.namedBindings)) {
if (getColor(node.importClause.namedBindings) === NodeColor.Black) {
return keep(node);
}
} else {
let survivingImports: string[] = [];
for (let i = 0; i < node.importClause.namedBindings.elements.length; i++) {
const importNode = node.importClause.namedBindings.elements[i];
if (getColor(importNode) === NodeColor.Black) {
survivingImports.push(importNode.getFullText(sourceFile));
}
}
const leadingTriviaWidth = node.getLeadingTriviaWidth();
const leadingTrivia = sourceFile.text.substr(node.pos, leadingTriviaWidth);
if (survivingImports.length > 0) {
if (node.importClause && getColor(node.importClause) === NodeColor.Black) {
return write(`${leadingTrivia}import ${node.importClause.name.text}, {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`);
}
return write(`${leadingTrivia}import {${survivingImports.join(',')} } from${node.moduleSpecifier.getFullText(sourceFile)};`);
} else {
if (node.importClause && getColor(node.importClause) === NodeColor.Black) {
return write(`${leadingTrivia}import ${node.importClause.name.text} from${node.moduleSpecifier.getFullText(sourceFile)};`);
}
}
}
} else {
if (node.importClause && getColor(node.importClause) === NodeColor.Black) {
return keep(node);
}
}
}
if (shakeLevel === ShakeLevel.ClassMembers && (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) && nodeOrChildIsBlack(node)) {
let toWrite = node.getFullText();
for (let i = node.members.length - 1; i >= 0; i--) {
const member = node.members[i];
if (getColor(member) === NodeColor.Black) {
// keep method
continue;
}
if (/^_(.*)Brand$/.test(member.name.getText())) {
// TODO: keep all members ending with `Brand`...
continue;
}
let pos = member.pos - node.pos;
let end = member.end - node.pos;
toWrite = toWrite.substring(0, pos) + toWrite.substring(end);
}
return write(toWrite);
}
if (ts.isFunctionDeclaration(node)) {
// Do not go inside functions if they haven't been marked
return;
}
node.forEachChild(writeMarkedNodes);
}
if (getColor(sourceFile) !== NodeColor.Black) {
if (!nodeOrChildIsBlack(sourceFile)) {
// none of the elements are reachable => don't write this file at all!
return;
}
sourceFile.forEachChild(writeMarkedNodes);
result += sourceFile.endOfFileToken.getFullText(sourceFile);
} else {
result = text;
}
writeFile(destination, result);
});
return result;
}
//#endregion
//#region Utils
/**
* Returns the node's symbol and the `import` node (if the symbol resolved from a different module)
*/
function getRealNodeSymbol(checker: ts.TypeChecker, node: ts.Node): [ts.Symbol, ts.Declaration] {
/**
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
*/
/* @internal */
function getContainingObjectLiteralElement(node: ts.Node): ts.ObjectLiteralElement | undefined {
switch (node.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NumericLiteral:
if (node.parent.kind === ts.SyntaxKind.ComputedPropertyName) {
return ts.isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
}
// falls through
case ts.SyntaxKind.Identifier:
return ts.isObjectLiteralElement(node.parent) &&
(node.parent.parent.kind === ts.SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === ts.SyntaxKind.JsxAttributes) &&
node.parent.name === node ? node.parent : undefined;
}
return undefined;
}
function getPropertySymbolsFromType(type: ts.Type, propName: ts.PropertyName) {
function getTextOfPropertyName(name: ts.PropertyName): string {
function isStringOrNumericLiteral(node: ts.Node): node is ts.StringLiteral | ts.NumericLiteral {
const kind = node.kind;
return kind === ts.SyntaxKind.StringLiteral
|| kind === ts.SyntaxKind.NumericLiteral;
}
switch (name.kind) {
case ts.SyntaxKind.Identifier:
return name.text;
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NumericLiteral:
return name.text;
case ts.SyntaxKind.ComputedPropertyName:
return isStringOrNumericLiteral(name.expression) ? name.expression.text : undefined!;
}
}
const name = getTextOfPropertyName(propName);
if (name && type) {
const result: ts.Symbol[] = [];
const symbol = type.getProperty(name);
if (type.flags & ts.TypeFlags.Union) {
for (const t of (<ts.UnionType>type).types) {
const symbol = t.getProperty(name);
if (symbol) {
result.push(symbol);
}
}
return result;
}
if (symbol) {
result.push(symbol);
return result;
}
}
return undefined;
}
function getPropertySymbolsFromContextualType(typeChecker: ts.TypeChecker, node: ts.ObjectLiteralElement): ts.Symbol[] {
const objectLiteral = <ts.ObjectLiteralExpression | ts.JsxAttributes>node.parent;
const contextualType = typeChecker.getContextualType(objectLiteral)!;
return getPropertySymbolsFromType(contextualType, node.name!)!;
}
// Go to the original declaration for cases:
//
// (1) when the aliased symbol was declared in the location(parent).
// (2) when the aliased symbol is originating from an import.
//
function shouldSkipAlias(node: ts.Node, declaration: ts.Node): boolean {
if (node.kind !== ts.SyntaxKind.Identifier) {
return false;
}
if (node.parent === declaration) {
return true;
}
switch (declaration.kind) {
case ts.SyntaxKind.ImportClause:
case ts.SyntaxKind.ImportEqualsDeclaration:
return true;
case ts.SyntaxKind.ImportSpecifier:
return declaration.parent.kind === ts.SyntaxKind.NamedImports;
default:
return false;
}
}
if (!ts.isShorthandPropertyAssignment(node)) {
if (node.getChildCount() !== 0) {
return [null, null];
}
}
let symbol = checker.getSymbolAtLocation(node);
let importNode: ts.Declaration = null;
if (symbol && symbol.flags & ts.SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) {
const aliased = checker.getAliasedSymbol(symbol);
if (aliased.declarations) {
// We should mark the import as visited
importNode = symbol.declarations[0];
symbol = aliased;
}
}
if (symbol) {
// Because name in short-hand property assignment has two different meanings: property name and property value,
// using go-to-definition at such position should go to the variable declaration of the property value rather than
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === ts.SyntaxKind.ShorthandPropertyAssignment) {
symbol = checker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
}
// If the node is the name of a BindingElement within an ObjectBindingPattern instead of just returning the
// declaration the symbol (which is itself), we should try to get to the original type of the ObjectBindingPattern
// and return the property declaration for the referenced property.
// For example:
// import('./foo').then(({ b/*goto*/ar }) => undefined); => should get use to the declaration in file "./foo"
//
// function bar<T>(onfulfilled: (value: T) => void) { //....}
// interface Test {
// pr/*destination*/op1: number
// }
// bar<Test>(({pr/*goto*/op1})=>{});
if (ts.isPropertyName(node) && ts.isBindingElement(node.parent) && ts.isObjectBindingPattern(node.parent.parent) &&
(node === (node.parent.propertyName || node.parent.name))) {
const type = checker.getTypeAtLocation(node.parent.parent);
if (type) {
const propSymbols = getPropertySymbolsFromType(type, node);
if (propSymbols) {
symbol = propSymbols[0];
}
}
}
// If the current location we want to find its definition is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this for goto-definition.
// For example
// interface Props{
// /*first*/prop1: number
// prop2: boolean
// }
// function Foo(arg: Props) {}
// Foo( { pr/*1*/op1: 10, prop2: false })
const element = getContainingObjectLiteralElement(node);
if (element && checker.getContextualType(element.parent as ts.Expression)) {
const propertySymbols = getPropertySymbolsFromContextualType(checker, element);
if (propertySymbols) {
symbol = propertySymbols[0];
}
}
}
if (symbol && symbol.declarations) {
return [symbol, importNode];
}
return [null, null];
}
/** Get the token whose text contains the position */
function getTokenAtPosition(sourceFile: ts.SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeEndPosition: boolean): ts.Node {
let current: ts.Node = sourceFile;
outer: while (true) {
// find the child that contains 'position'
for (const child of current.getChildren()) {
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, /*includeJsDoc*/ true);
if (start > position) {
// If this child begins after position, then all subsequent children will as well.
break;
}
const end = child.getEnd();
if (position < end || (position === end && (child.kind === ts.SyntaxKind.EndOfFileToken || includeEndPosition))) {
current = child;
continue outer;
}
}
return current;
}
}
//#endregion
@@ -0,0 +1,73 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("typescript");
var Lint = require("tslint");
var path_1 = require("path");
var Rule = /** @class */ (function (_super) {
__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.apply = function (sourceFile) {
if (/vs(\/|\\)editor/.test(sourceFile.fileName)) {
// the vs/editor folder is allowed to use the standalone editor
return [];
}
return this.applyWithWalker(new NoStandaloneEditorRuleWalker(sourceFile, this.getOptions()));
};
return Rule;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
var NoStandaloneEditorRuleWalker = /** @class */ (function (_super) {
__extends(NoStandaloneEditorRuleWalker, _super);
function NoStandaloneEditorRuleWalker(file, opts) {
return _super.call(this, file, opts) || this;
}
NoStandaloneEditorRuleWalker.prototype.visitImportEqualsDeclaration = function (node) {
if (node.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) {
this._validateImport(node.moduleReference.expression.getText(), node);
}
};
NoStandaloneEditorRuleWalker.prototype.visitImportDeclaration = function (node) {
this._validateImport(node.moduleSpecifier.getText(), node);
};
NoStandaloneEditorRuleWalker.prototype.visitCallExpression = function (node) {
_super.prototype.visitCallExpression.call(this, node);
// import('foo') statements inside the code
if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {
var path = node.arguments[0];
this._validateImport(path.getText(), node);
}
};
NoStandaloneEditorRuleWalker.prototype._validateImport = function (path, node) {
// remove quotes
path = path.slice(1, -1);
// resolve relative paths
if (path[0] === '.') {
path = path_1.join(this.getSourceFile().fileName, path);
}
if (/vs(\/|\\)editor(\/|\\)standalone/.test(path)
|| /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.api/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.main/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.worker/.test(path)) {
// {{SQL CARBON EDIT}}
//this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Not allowed to import standalone editor modules. See https://github.com/Microsoft/vscode/wiki/Code-Organization`));
}
};
return NoStandaloneEditorRuleWalker;
}(Lint.RuleWalker));
@@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as ts from 'typescript';
import * as Lint from 'tslint';
import { join } from 'path';
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
if (/vs(\/|\\)editor/.test(sourceFile.fileName)) {
// the vs/editor folder is allowed to use the standalone editor
return [];
}
return this.applyWithWalker(new NoStandaloneEditorRuleWalker(sourceFile, this.getOptions()));
}
}
class NoStandaloneEditorRuleWalker extends Lint.RuleWalker {
constructor(file: ts.SourceFile, opts: Lint.IOptions) {
super(file, opts);
}
protected visitImportEqualsDeclaration(node: ts.ImportEqualsDeclaration): void {
if (node.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) {
this._validateImport(node.moduleReference.expression.getText(), node);
}
}
protected visitImportDeclaration(node: ts.ImportDeclaration): void {
this._validateImport(node.moduleSpecifier.getText(), node);
}
protected visitCallExpression(node: ts.CallExpression): void {
super.visitCallExpression(node);
// import('foo') statements inside the code
if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {
const [path] = node.arguments;
this._validateImport(path.getText(), node);
}
}
private _validateImport(path: string, node: ts.Node): void {
// remove quotes
path = path.slice(1, -1);
// resolve relative paths
if (path[0] === '.') {
path = join(this.getSourceFile().fileName, path);
}
if (
/vs(\/|\\)editor(\/|\\)standalone/.test(path)
|| /vs(\/|\\)editor(\/|\\)common(\/|\\)standalone/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.api/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.main/.test(path)
|| /vs(\/|\\)editor(\/|\\)editor.worker/.test(path)
) {
// {{SQL CARBON EDIT}}
//this.addFailure(this.createFailure(node.getStart(), node.getWidth(), `Not allowed to import standalone editor modules. See https://github.com/Microsoft/vscode/wiki/Code-Organization`));
}
}
}
-57
View File
@@ -14,7 +14,6 @@ var fs = require("fs");
var _rimraf = require("rimraf");
var git = require("./git");
var VinylFile = require("vinyl");
var cp = require("child_process");
var NoCancellationToken = { isCancellationRequested: function () { return false; } };
function incremental(streamProvider, initial, supportsCancellation) {
var input = es.through();
@@ -211,62 +210,6 @@ function filter(fn) {
return result;
}
exports.filter = filter;
function tagExists(tagName) {
try {
cp.execSync("git rev-parse " + tagName, { stdio: 'ignore' });
return true;
}
catch (e) {
return false;
}
}
/**
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
* Given 1.17.2, return 1.17.1
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
* 2.0.0 => 1.18.0 (or the highest 1.x)
*/
function getPreviousVersion(versionStr, _tagExists) {
if (_tagExists === void 0) { _tagExists = tagExists; }
function getLatestTagFromBase(semverArr, componentToTest) {
var baseVersion = semverArr.join('.');
if (!_tagExists(baseVersion)) {
throw new Error('Failed to find git tag for base version, ' + baseVersion);
}
var goodTag;
do {
goodTag = semverArr.join('.');
semverArr[componentToTest]++;
} while (_tagExists(semverArr.join('.')));
return goodTag;
}
var semverArr = versionStringToNumberArray(versionStr);
if (semverArr[2] > 0) {
semverArr[2]--;
var previous = semverArr.join('.');
if (!_tagExists(previous)) {
throw new Error('Failed to find git tag for previous version, ' + previous);
}
return previous;
}
else if (semverArr[1] > 0) {
semverArr[1]--;
return getLatestTagFromBase(semverArr, 2);
}
else {
semverArr[0]--;
// Find 1.x.0 for latest x
var latestMinorVersion = getLatestTagFromBase(semverArr, 1);
// Find 1.x.y for latest y
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
}
}
exports.getPreviousVersion = getPreviousVersion;
function versionStringToNumberArray(versionStr) {
return versionStr
.split('.')
.map(function (s) { return parseInt(s); });
}
function versionStringToNumber(versionStr) {
var semverRegex = /(\d+)\.(\d+)\.(\d+)/;
var match = versionStr.match(semverRegex);
-61
View File
@@ -17,7 +17,6 @@ import * as git from './git';
import * as VinylFile from 'vinyl';
import { ThroughStream } from 'through';
import * as sm from 'source-map';
import * as cp from 'child_process';
export interface ICancellationToken {
isCancellationRequested(): boolean;
@@ -271,66 +270,6 @@ export function filter(fn: (data: any) => boolean): FilterStream {
return result;
}
function tagExists(tagName: string): boolean {
try {
cp.execSync(`git rev-parse ${tagName}`, { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
/**
* Returns the version previous to the given version. Throws if a git tag for that version doesn't exist.
* Given 1.17.2, return 1.17.1
* 1.18.0 => 1.17.2. (or the highest 1.17.x)
* 2.0.0 => 1.18.0 (or the highest 1.x)
*/
export function getPreviousVersion(versionStr: string, _tagExists = tagExists) {
function getLatestTagFromBase(semverArr: number[], componentToTest: number): string {
const baseVersion = semverArr.join('.');
if (!_tagExists(baseVersion)) {
throw new Error('Failed to find git tag for base version, ' + baseVersion);
}
let goodTag;
do {
goodTag = semverArr.join('.');
semverArr[componentToTest]++;
} while (_tagExists(semverArr.join('.')));
return goodTag;
}
const semverArr = versionStringToNumberArray(versionStr);
if (semverArr[2] > 0) {
semverArr[2]--;
const previous = semverArr.join('.');
if (!_tagExists(previous)) {
throw new Error('Failed to find git tag for previous version, ' + previous);
}
return previous;
} else if (semverArr[1] > 0) {
semverArr[1]--;
return getLatestTagFromBase(semverArr, 2);
} else {
semverArr[0]--;
// Find 1.x.0 for latest x
const latestMinorVersion = getLatestTagFromBase(semverArr, 1);
// Find 1.x.y for latest y
return getLatestTagFromBase(versionStringToNumberArray(latestMinorVersion), 2);
}
}
function versionStringToNumberArray(versionStr: string): number[] {
return versionStr
.split('.')
.map(s => parseInt(s));
}
export function versionStringToNumber(versionStr: string) {
const semverRegex = /(\d+)\.(\d+)\.(\d+)/;
const match = versionStr.match(semverRegex);