mirror of
https://github.com/kennethreitz/bake.git
synced 2026-06-05 23:00:17 +00:00
cleanup
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# vsce
|
||||
> *The Visual Studio Code Extension Manager*
|
||||
|
||||
[](https://dev.azure.com/vscode/VSCE/_build/latest?definitionId=16&branchName=master) [](https://badge.fury.io/js/vsce)
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Node.js](https://nodejs.org/en/) at least `8.x.x`
|
||||
|
||||
## Development
|
||||
|
||||
First clone this repository, then:
|
||||
|
||||
```sh
|
||||
yarn
|
||||
yarn watch # or `watch-test` to also run tests
|
||||
```
|
||||
|
||||
Once the watcher is up and running, you can run out of sources with:
|
||||
|
||||
```sh
|
||||
yarn vsce
|
||||
```
|
||||
|
||||
### Publish to NPM
|
||||
|
||||
Simply push a new tag and the CI will automatically publish to NPM. The usual flow is:
|
||||
|
||||
```sh
|
||||
npm version [minor|patch]
|
||||
git push --follow-tags
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
This tool assists in packaging and publishing Visual Studio Code extensions.
|
||||
|
||||
Read the [**Documentation**](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code website.
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
microsoft-vscode-vsce
|
||||
|
||||
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
|
||||
Do Not Translate or Localize
|
||||
|
||||
This project incorporates components from the projects listed below. The original copyright notices and the licenses
|
||||
under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted
|
||||
herein, whether by implication, estoppel or otherwise.
|
||||
|
||||
1. commander version 2.8.1 (https://github.com/tj/commander.js)
|
||||
2. denodeify version 1.2.1 (https://github.com/matthew-andrews/denodeify)
|
||||
3. glob version 5.0.14 (https://github.com/isaacs/node-glob)
|
||||
4. lodash version 3.10.1 (https://github.com/lodash/lodash)
|
||||
5. mime version 1.3.4 (https://github.com/broofa/node-mime)
|
||||
6. minimatch version 2.0.10 (https://github.com/isaacs/minimatch)
|
||||
7. osenv version 0.1.3 (https://github.com/npm/osenv)
|
||||
8. read version 1.0.7 (https://github.com/isaacs/read)
|
||||
9. semver version 5.1.0 (https://github.com/npm/node-semver)
|
||||
10. tmp version 0.0.27 (https://github.com/raszi/node-tmp)
|
||||
11. url-join version 0.0.1 (https://github.com/jfromaniello/url-join)
|
||||
12. vso-node-api version 0.5.0 (https://github.com/Microsoft/vso-node-api)
|
||||
13. yauzl version 2.3.1 (https://github.com/thejoshwolfe/yauzl)
|
||||
14. yazl version 2.2.2 (https://github.com/thejoshwolfe/yazl)
|
||||
|
||||
%% commander NOTICES AND INFORMATION BEGIN HERE
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
END OF commander NOTICES AND INFORMATION
|
||||
|
||||
%% denodeify NOTICES AND INFORMATION BEGIN HERE
|
||||
Credits and collaboration
|
||||
|
||||
The lead developer of denodeify is Matt Andrews at FT Labs with much help and support from Kornel Lesiński. All open source code released by FT Labs is licenced under the MIT licence. We welcome comments, feedback and suggestions. Please feel free to raise an issue or pull request.
|
||||
END OF denodeify NOTICES AND INFORMATION
|
||||
|
||||
%% glob NOTICES AND INFORMATION BEGIN HERE
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
END OF glob NOTICES AND INFORMATION
|
||||
|
||||
%% lodash NOTICES AND INFORMATION BEGIN HERE
|
||||
Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
|
||||
Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas,
|
||||
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
END OF lodash NOTICES AND INFORMATION
|
||||
|
||||
%% mime NOTICES AND INFORMATION BEGIN HERE
|
||||
Copyright (c) 2010 Benjamin Thomas, Robert Kieffer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
END OF mime NOTICES AND INFORMATION
|
||||
|
||||
%% minimatch NOTICES AND INFORMATION BEGIN HERE
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
END OF minimatch NOTICES AND INFORMATION
|
||||
|
||||
%% osenv NOTICES AND INFORMATION BEGIN HERE
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
END OF osenv NOTICES AND INFORMATION
|
||||
|
||||
%% read NOTICES AND INFORMATION BEGIN HERE
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
END OF read NOTICES AND INFORMATION
|
||||
|
||||
%% semver NOTICES AND INFORMATION BEGIN HERE
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
END OF semver NOTICES AND INFORMATION
|
||||
|
||||
%% tmp NOTICES AND INFORMATION BEGIN HERE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 KARASZI István
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
END OF tmp NOTICES AND INFORMATION
|
||||
|
||||
%% url-join NOTICES AND INFORMATION BEGIN HERE
|
||||
License
|
||||
MIT
|
||||
END OF url-join NOTICES AND INFORMATION
|
||||
|
||||
%% vso-node-api NOTICES AND INFORMATION BEGIN HERE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Microsoft
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
END OF vso-node-api NOTICES AND INFORMATION
|
||||
|
||||
%% yauzl NOTICES AND INFORMATION BEGIN HERE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Josh Wolfe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
END OF yauzl NOTICES AND INFORMATION
|
||||
|
||||
%% yazl NOTICES AND INFORMATION BEGIN HERE
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Josh Wolfe
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
END OF yazl NOTICES AND INFORMATION
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
trigger:
|
||||
branches:
|
||||
include: ['*']
|
||||
tags:
|
||||
include: ['*']
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSpec: "8.x"
|
||||
|
||||
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
|
||||
inputs:
|
||||
versionSpec: "1.x"
|
||||
|
||||
- script: yarn
|
||||
displayName: Install Dependencies
|
||||
|
||||
- script: yarn compile
|
||||
displayName: Compile
|
||||
|
||||
- script: yarn test
|
||||
displayName: Run Tests
|
||||
|
||||
- task: Npm@1
|
||||
displayName: 'Publish to NPM'
|
||||
inputs:
|
||||
command: publish
|
||||
verbose: false
|
||||
publishEndpoint: 'NPM'
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../markdown-it/bin/markdown-it.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../mime/cli.js
|
||||
+1
@@ -0,0 +1 @@
|
||||
../../../semver/bin/semver
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
export interface ICreateVSIXOptions {
|
||||
/**
|
||||
* The location of the extension in the file system.
|
||||
*
|
||||
* Defaults to `process.cwd()`.
|
||||
*/
|
||||
cwd?: string;
|
||||
/**
|
||||
* The destination of the packaged the VSIX.
|
||||
*
|
||||
* Defaults to `NAME-VERSION.vsix`.
|
||||
*/
|
||||
packagePath?: string;
|
||||
/**
|
||||
* The base URL for links detected in Markdown files.
|
||||
*/
|
||||
baseContentUrl?: string;
|
||||
/**
|
||||
* The base URL for images detected in Markdown files.
|
||||
*/
|
||||
baseImagesUrl?: string;
|
||||
/**
|
||||
* Should use Yarn instead of NPM.
|
||||
*/
|
||||
useYarn?: boolean;
|
||||
}
|
||||
export interface IPublishOptions {
|
||||
/**
|
||||
* The location of the extension in the file system.
|
||||
*
|
||||
* Defaults to `process.cwd()`.
|
||||
*/
|
||||
cwd?: string;
|
||||
/**
|
||||
* The Personal Access Token to use.
|
||||
*
|
||||
* Defaults to the stored one.
|
||||
*/
|
||||
pat?: string;
|
||||
/**
|
||||
* The base URL for links detected in Markdown files.
|
||||
*/
|
||||
baseContentUrl?: string;
|
||||
/**
|
||||
* The base URL for images detected in Markdown files.
|
||||
*/
|
||||
baseImagesUrl?: string;
|
||||
/**
|
||||
* Should use Yarn instead of NPM.
|
||||
*/
|
||||
useYarn?: boolean;
|
||||
}
|
||||
/**
|
||||
* The supported list of package managers.
|
||||
*/
|
||||
export declare enum PackageManager {
|
||||
Npm = 0,
|
||||
Yarn = 1
|
||||
}
|
||||
export interface IListFilesOptions {
|
||||
/**
|
||||
* The working directory of the extension. Defaults to `process.cwd()`.
|
||||
*/
|
||||
cwd?: string;
|
||||
/**
|
||||
* The package manager to use. Defaults to `PackageManager.Npm`.
|
||||
*/
|
||||
packageManager?: PackageManager;
|
||||
/**
|
||||
* A subset of the top level dependencies which should be included. The
|
||||
* default is `undefined` which include all dependencies, an empty array means
|
||||
* no dependencies will be included.
|
||||
*/
|
||||
packagedDependencies?: string[];
|
||||
}
|
||||
export interface IPublishVSIXOptions {
|
||||
/**
|
||||
* The Personal Access Token to use.
|
||||
*
|
||||
* Defaults to the stored one.
|
||||
*/
|
||||
pat?: string;
|
||||
/**
|
||||
* The base URL for links detected in Markdown files.
|
||||
*/
|
||||
baseContentUrl?: string;
|
||||
/**
|
||||
* The base URL for images detected in Markdown files.
|
||||
*/
|
||||
baseImagesUrl?: string;
|
||||
/**
|
||||
* Should use Yarn instead of NPM.
|
||||
*/
|
||||
useYarn?: boolean;
|
||||
}
|
||||
/**
|
||||
* Creates a VSIX from the extension in the current working directory.
|
||||
*/
|
||||
export declare function createVSIX(options?: ICreateVSIXOptions): Promise<any>;
|
||||
/**
|
||||
* Publishes the extension in the current working directory.
|
||||
*/
|
||||
export declare function publish(options?: IPublishOptions): Promise<any>;
|
||||
/**
|
||||
* Lists the files included in the extension's package.
|
||||
*/
|
||||
export declare function listFiles(options?: IListFilesOptions): Promise<string[]>;
|
||||
/**
|
||||
* Publishes a pre-build VSIX.
|
||||
*/
|
||||
export declare function publishVSIX(packagePath: string, options?: IPublishVSIXOptions): Promise<any>;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const publish_1 = require("./publish");
|
||||
const package_1 = require("./package");
|
||||
/**
|
||||
* The supported list of package managers.
|
||||
*/
|
||||
var PackageManager;
|
||||
(function (PackageManager) {
|
||||
PackageManager[PackageManager["Npm"] = 0] = "Npm";
|
||||
PackageManager[PackageManager["Yarn"] = 1] = "Yarn";
|
||||
})(PackageManager = exports.PackageManager || (exports.PackageManager = {}));
|
||||
/**
|
||||
* Creates a VSIX from the extension in the current working directory.
|
||||
*/
|
||||
function createVSIX(options = {}) {
|
||||
return package_1.packageCommand(options);
|
||||
}
|
||||
exports.createVSIX = createVSIX;
|
||||
/**
|
||||
* Publishes the extension in the current working directory.
|
||||
*/
|
||||
function publish(options = {}) {
|
||||
return publish_1.publish(options);
|
||||
}
|
||||
exports.publish = publish;
|
||||
/**
|
||||
* Lists the files included in the extension's package.
|
||||
*/
|
||||
function listFiles(options = {}) {
|
||||
return package_1.listFiles(options.cwd, options.packageManager === PackageManager.Yarn, options.packagedDependencies);
|
||||
}
|
||||
exports.listFiles = listFiles;
|
||||
/**
|
||||
* Publishes a pre-build VSIX.
|
||||
*/
|
||||
function publishVSIX(packagePath, options = {}) {
|
||||
return publish_1.publish(Object.assign({ packagePath }, options));
|
||||
}
|
||||
exports.publishVSIX = publishVSIX;
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const program = require("commander");
|
||||
const didYouMean = require("didyoumean");
|
||||
const package_1 = require("./package");
|
||||
const publish_1 = require("./publish");
|
||||
const show_1 = require("./show");
|
||||
const search_1 = require("./search");
|
||||
const store_1 = require("./store");
|
||||
const npm_1 = require("./npm");
|
||||
const util_1 = require("./util");
|
||||
const semver = require("semver");
|
||||
const tty_1 = require("tty");
|
||||
const pkg = require('../package.json');
|
||||
function fatal(message, ...args) {
|
||||
if (message instanceof Error) {
|
||||
message = message.message;
|
||||
if (/^cancell?ed$/i.test(message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
util_1.log.error(message, ...args);
|
||||
if (/Unauthorized\(401\)/.test(message)) {
|
||||
util_1.log.error(`Be sure to use a Personal Access Token which has access to **all accessible accounts**.
|
||||
See https://code.visualstudio.com/api/working-with-extensions/publishing-extension#publishing-extensions for more information.`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
function main(task) {
|
||||
let latestVersion = null;
|
||||
const token = new util_1.CancellationToken();
|
||||
if (tty_1.isatty(1)) {
|
||||
npm_1.getLatestVersion(pkg.name, token)
|
||||
.then(version => latestVersion = version)
|
||||
.catch(_ => { });
|
||||
}
|
||||
task
|
||||
.catch(fatal)
|
||||
.then(() => {
|
||||
if (latestVersion && semver.gt(latestVersion, pkg.version)) {
|
||||
util_1.log.info(`\nThe latest version of ${pkg.name} is ${latestVersion} and you have ${pkg.version}.\nUpdate it now: npm install -g ${pkg.name}`);
|
||||
}
|
||||
else {
|
||||
token.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
module.exports = function (argv) {
|
||||
program
|
||||
.version(pkg.version)
|
||||
.usage('<command> [options]');
|
||||
program
|
||||
.command('ls')
|
||||
.description('Lists all the files that will be published')
|
||||
.option('--yarn', 'Use yarn instead of npm')
|
||||
.option('--packagedDependencies <path>', 'Select packages that should be published only (includes dependencies)', (val, all) => all ? all.concat(val) : [val], undefined)
|
||||
.action(({ yarn, packagedDependencies }) => main(package_1.ls(undefined, yarn, packagedDependencies)));
|
||||
program
|
||||
.command('package')
|
||||
.description('Packages an extension')
|
||||
.option('-o, --out [path]', 'Output .vsix extension file to [path] location')
|
||||
.option('--baseContentUrl [url]', 'Prepend all relative links in README.md with this url.')
|
||||
.option('--baseImagesUrl [url]', 'Prepend all relative image links in README.md with this url.')
|
||||
.option('--yarn', 'Use yarn instead of npm')
|
||||
.action(({ out, baseContentUrl, baseImagesUrl, yarn }) => main(package_1.packageCommand({ packagePath: out, baseContentUrl, baseImagesUrl, useYarn: yarn })));
|
||||
program
|
||||
.command('publish [<version>]')
|
||||
.description('Publishes an extension')
|
||||
.option('-p, --pat <token>', 'Personal Access Token')
|
||||
.option('-m, --message <commit message>', 'Commit message used when calling `npm version`.')
|
||||
.option('--packagePath [path]', 'Publish the VSIX package located at the specified path.')
|
||||
.option('--baseContentUrl [url]', 'Prepend all relative links in README.md with this url.')
|
||||
.option('--baseImagesUrl [url]', 'Prepend all relative image links in README.md with this url.')
|
||||
.option('--yarn', 'Use yarn instead of npm while packing extension files')
|
||||
.option('--noVerify')
|
||||
.action((version, { pat, message, packagePath, baseContentUrl, baseImagesUrl, yarn, noVerify }) => main(publish_1.publish({ pat, commitMessage: message, version, packagePath, baseContentUrl, baseImagesUrl, useYarn: yarn, noVerify })));
|
||||
program
|
||||
.command('unpublish [<extensionid>]')
|
||||
.description('Unpublishes an extension. Example extension id: microsoft.csharp.')
|
||||
.option('-p, --pat <token>', 'Personal Access Token')
|
||||
.action((id, { pat }) => main(publish_1.unpublish({ id, pat })));
|
||||
program
|
||||
.command('ls-publishers')
|
||||
.description('List all known publishers')
|
||||
.action(() => main(store_1.listPublishers()));
|
||||
program
|
||||
.command('create-publisher <publisher>')
|
||||
.description('Creates a new publisher')
|
||||
.action(publisher => main(store_1.createPublisher(publisher)));
|
||||
program
|
||||
.command('delete-publisher <publisher>')
|
||||
.description('Deletes a publisher')
|
||||
.action(publisher => main(store_1.deletePublisher(publisher)));
|
||||
program
|
||||
.command('login <publisher>')
|
||||
.description('Add a publisher to the known publishers list')
|
||||
.action(name => main(store_1.loginPublisher(name)));
|
||||
program
|
||||
.command('logout <publisher>')
|
||||
.description('Remove a publisher from the known publishers list')
|
||||
.action(name => main(store_1.logoutPublisher(name)));
|
||||
program
|
||||
.command('show <extensionid>')
|
||||
.option('--json', 'Output data in json format', false)
|
||||
.description('Show extension metadata')
|
||||
.action((extensionid, { json }) => main(show_1.show(extensionid, json)));
|
||||
program
|
||||
.command('search <text>')
|
||||
.option('--json', 'Output result in json format', false)
|
||||
.description('search extension gallery')
|
||||
.action((text, { json }) => main(search_1.search(text, json)));
|
||||
program
|
||||
.command('*', '', { noHelp: true })
|
||||
.action((cmd) => {
|
||||
program.help(help => {
|
||||
const suggestion = didYouMean(cmd, program.commands.map(c => c._name));
|
||||
help = `${help}
|
||||
Unknown command '${cmd}'`;
|
||||
return suggestion ? `${help}, did you mean '${suggestion}'?\n` : `${help}.\n`;
|
||||
});
|
||||
});
|
||||
program.parse(argv);
|
||||
if (process.argv.length <= 2) {
|
||||
program.help();
|
||||
}
|
||||
};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const lodash_1 = require("lodash");
|
||||
const regex = /^%([\w\d.]+)%$/i;
|
||||
function patcher(translations) {
|
||||
return value => {
|
||||
if (typeof value !== 'string') {
|
||||
return;
|
||||
}
|
||||
const match = regex.exec(value);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
return translations[match[1]] || value;
|
||||
};
|
||||
}
|
||||
function patchNLS(manifest, translations) {
|
||||
return lodash_1.cloneDeepWith(manifest, patcher(translations));
|
||||
}
|
||||
exports.patchNLS = patchNLS;
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const cp = require("child_process");
|
||||
const parseSemver = require("parse-semver");
|
||||
const _ = require("lodash");
|
||||
function parseStdout({ stdout }) {
|
||||
return stdout.split(/[\r\n]/).filter(line => !!line)[0];
|
||||
}
|
||||
function exec(command, options = {}, cancellationToken) {
|
||||
return new Promise((c, e) => {
|
||||
let disposeCancellationListener = null;
|
||||
const child = cp.exec(command, Object.assign({}, options, { encoding: 'utf8' }), (err, stdout, stderr) => {
|
||||
if (disposeCancellationListener) {
|
||||
disposeCancellationListener();
|
||||
disposeCancellationListener = null;
|
||||
}
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
c({ stdout, stderr });
|
||||
});
|
||||
if (cancellationToken) {
|
||||
disposeCancellationListener = cancellationToken.subscribe(err => {
|
||||
child.kill();
|
||||
e(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function checkNPM(cancellationToken) {
|
||||
return exec('npm -v', {}, cancellationToken).then(({ stdout }) => {
|
||||
const version = stdout.trim();
|
||||
if (/^3\.7\.[0123]$/.test(version)) {
|
||||
return Promise.reject(`npm@${version} doesn't work with vsce. Please update npm: npm install -g npm`);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getNpmDependencies(cwd) {
|
||||
return checkNPM()
|
||||
.then(() => exec('npm list --production --parseable --depth=99999', { cwd, maxBuffer: 5000 * 1024 }))
|
||||
.then(({ stdout }) => stdout
|
||||
.split(/[\r\n]/)
|
||||
.filter(dir => path.isAbsolute(dir)));
|
||||
}
|
||||
function asYarnDependency(prefix, tree, prune) {
|
||||
if (prune && /@[\^~]/.test(tree.name)) {
|
||||
return null;
|
||||
}
|
||||
let name;
|
||||
try {
|
||||
const parseResult = parseSemver(tree.name);
|
||||
name = parseResult.name;
|
||||
}
|
||||
catch (err) {
|
||||
name = tree.name.replace(/^([^@+])@.*$/, '$1');
|
||||
}
|
||||
const dependencyPath = path.join(prefix, name);
|
||||
const children = [];
|
||||
for (const child of (tree.children || [])) {
|
||||
const dep = asYarnDependency(path.join(prefix, name, 'node_modules'), child, prune);
|
||||
if (dep) {
|
||||
children.push(dep);
|
||||
}
|
||||
}
|
||||
return { name, path: dependencyPath, children };
|
||||
}
|
||||
function selectYarnDependencies(deps, packagedDependencies) {
|
||||
const index = new class {
|
||||
constructor() {
|
||||
this.data = Object.create(null);
|
||||
for (const dep of deps) {
|
||||
if (this.data[dep.name]) {
|
||||
throw Error(`Dependency seen more than once: ${dep.name}`);
|
||||
}
|
||||
this.data[dep.name] = dep;
|
||||
}
|
||||
}
|
||||
find(name) {
|
||||
let result = this.data[name];
|
||||
if (!result) {
|
||||
throw new Error(`Could not find dependency: ${name}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
const reached = new class {
|
||||
constructor() {
|
||||
this.values = [];
|
||||
}
|
||||
add(dep) {
|
||||
if (this.values.indexOf(dep) < 0) {
|
||||
this.values.push(dep);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const visit = (name) => {
|
||||
let dep = index.find(name);
|
||||
if (!reached.add(dep)) {
|
||||
// already seen -> done
|
||||
return;
|
||||
}
|
||||
for (const child of dep.children) {
|
||||
visit(child.name);
|
||||
}
|
||||
};
|
||||
packagedDependencies.forEach(visit);
|
||||
return reached.values;
|
||||
}
|
||||
function getYarnProductionDependencies(cwd, packagedDependencies) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const raw = yield new Promise((c, e) => cp.exec('yarn list --prod --json', { cwd, encoding: 'utf8', env: Object.assign({}, process.env), maxBuffer: 5000 * 1024 }, (err, stdout) => err ? e(err) : c(stdout)));
|
||||
const match = /^{"type":"tree".*$/m.exec(raw);
|
||||
if (!match || match.length !== 1) {
|
||||
throw new Error('Could not parse result of `yarn list --json`');
|
||||
}
|
||||
const usingPackagedDependencies = Array.isArray(packagedDependencies);
|
||||
const trees = JSON.parse(match[0]).data.trees;
|
||||
let result = trees
|
||||
.map(tree => asYarnDependency(path.join(cwd, 'node_modules'), tree, !usingPackagedDependencies))
|
||||
.filter(dep => !!dep);
|
||||
if (usingPackagedDependencies) {
|
||||
result = selectYarnDependencies(result, packagedDependencies);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
function getYarnDependencies(cwd, packagedDependencies) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = [cwd];
|
||||
if (yield new Promise(c => fs.exists(path.join(cwd, 'yarn.lock'), c))) {
|
||||
const deps = yield getYarnProductionDependencies(cwd, packagedDependencies);
|
||||
const flatten = (dep) => { result.push(dep.path); dep.children.forEach(flatten); };
|
||||
deps.forEach(flatten);
|
||||
}
|
||||
return _.uniq(result);
|
||||
});
|
||||
}
|
||||
function getDependencies(cwd, useYarn = false, packagedDependencies) {
|
||||
return useYarn ? getYarnDependencies(cwd, packagedDependencies) : getNpmDependencies(cwd);
|
||||
}
|
||||
exports.getDependencies = getDependencies;
|
||||
function getLatestVersion(name, cancellationToken) {
|
||||
return checkNPM(cancellationToken)
|
||||
.then(() => exec(`npm show ${name} version`, {}, cancellationToken))
|
||||
.then(parseStdout);
|
||||
}
|
||||
exports.getLatestVersion = getLatestVersion;
|
||||
+752
@@ -0,0 +1,752 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const cp = require("child_process");
|
||||
const _ = require("lodash");
|
||||
const yazl = require("yazl");
|
||||
const nls_1 = require("./nls");
|
||||
const util = require("./util");
|
||||
const _glob = require("glob");
|
||||
const minimatch = require("minimatch");
|
||||
const denodeify = require("denodeify");
|
||||
const markdownit = require("markdown-it");
|
||||
const cheerio = require("cheerio");
|
||||
const url = require("url");
|
||||
const mime_1 = require("mime");
|
||||
const urljoin = require("url-join");
|
||||
const validation_1 = require("./validation");
|
||||
const npm_1 = require("./npm");
|
||||
const readFile = denodeify(fs.readFile);
|
||||
const unlink = denodeify(fs.unlink);
|
||||
const stat = denodeify(fs.stat);
|
||||
const exec = denodeify(cp.exec, (err, stdout, stderr) => [err, { stdout, stderr }]);
|
||||
const glob = denodeify(_glob);
|
||||
const resourcesPath = path.join(path.dirname(__dirname), 'resources');
|
||||
const vsixManifestTemplatePath = path.join(resourcesPath, 'extension.vsixmanifest');
|
||||
const contentTypesTemplatePath = path.join(resourcesPath, '[Content_Types].xml');
|
||||
const MinimatchOptions = { dot: true };
|
||||
function read(file) {
|
||||
if (file.contents) {
|
||||
return Promise.resolve(file.contents).then(b => typeof b === 'string' ? b : b.toString('utf8'));
|
||||
}
|
||||
else {
|
||||
return readFile(file.localPath, 'utf8');
|
||||
}
|
||||
}
|
||||
exports.read = read;
|
||||
class BaseProcessor {
|
||||
constructor(manifest) {
|
||||
this.manifest = manifest;
|
||||
this.assets = [];
|
||||
this.vsix = Object.create(null);
|
||||
}
|
||||
onFile(file) { return Promise.resolve(file); }
|
||||
onEnd() { return Promise.resolve(null); }
|
||||
}
|
||||
exports.BaseProcessor = BaseProcessor;
|
||||
function getUrl(url) {
|
||||
if (!url) {
|
||||
return null;
|
||||
}
|
||||
if (typeof url === 'string') {
|
||||
return url;
|
||||
}
|
||||
return url.url;
|
||||
}
|
||||
function getRepositoryUrl(url) {
|
||||
const result = getUrl(url);
|
||||
if (/^[^\/]+\/[^\/]+$/.test(result)) {
|
||||
return `https://github.com/${result}.git`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Contributed by Mozilla develpoer authors
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
||||
}
|
||||
function toExtensionTags(extensions) {
|
||||
return extensions
|
||||
.map(s => s.replace(/\W/g, ''))
|
||||
.filter(s => !!s)
|
||||
.map(s => `__ext_${s}`);
|
||||
}
|
||||
function toLanguagePackTags(translations, languageId) {
|
||||
return (translations || [])
|
||||
.map(({ id }) => [`__lp_${id}`, `__lp-${languageId}_${id}`])
|
||||
.reduce((r, t) => [...r, ...t], []);
|
||||
}
|
||||
/* This list is also maintained by the Marketplace team.
|
||||
* Remember to reach out to them when adding new domains.
|
||||
*/
|
||||
const TrustedSVGSources = [
|
||||
'api.bintray.com',
|
||||
'api.travis-ci.com',
|
||||
'api.travis-ci.org',
|
||||
'app.fossa.io',
|
||||
'badge.buildkite.com',
|
||||
'badge.fury.io',
|
||||
'badge.waffle.io',
|
||||
'badgen.net',
|
||||
'badges.frapsoft.com',
|
||||
'badges.gitter.im',
|
||||
'badges.greenkeeper.io',
|
||||
'cdn.travis-ci.com',
|
||||
'cdn.travis-ci.org',
|
||||
'ci.appveyor.com',
|
||||
'circleci.com',
|
||||
'cla.opensource.microsoft.com',
|
||||
'codacy.com',
|
||||
'codeclimate.com',
|
||||
'codecov.io',
|
||||
'coveralls.io',
|
||||
'david-dm.org',
|
||||
'deepscan.io',
|
||||
'dev.azure.com',
|
||||
'docs.rs',
|
||||
'flat.badgen.net',
|
||||
'gemnasium.com',
|
||||
'githost.io',
|
||||
'gitlab.com',
|
||||
'godoc.org',
|
||||
'goreportcard.com',
|
||||
'img.shields.io',
|
||||
'isitmaintained.com',
|
||||
'marketplace.visualstudio.com',
|
||||
'nodesecurity.io',
|
||||
'opencollective.com',
|
||||
'snyk.io',
|
||||
'travis-ci.com',
|
||||
'travis-ci.org',
|
||||
'visualstudio.com',
|
||||
'vsmarketplacebadge.apphb.com',
|
||||
'www.bithound.io',
|
||||
'www.versioneye.com'
|
||||
];
|
||||
function isHostTrusted(host) {
|
||||
return TrustedSVGSources.indexOf(host.toLowerCase()) > -1;
|
||||
}
|
||||
function isGitHubRepository(repository) {
|
||||
return /^https:\/\/github\.com\/|^git@github\.com:/.test(repository || '');
|
||||
}
|
||||
class ManifestProcessor extends BaseProcessor {
|
||||
constructor(manifest) {
|
||||
super(manifest);
|
||||
const flags = ['Public'];
|
||||
if (manifest.preview) {
|
||||
flags.push('Preview');
|
||||
}
|
||||
const repository = getRepositoryUrl(manifest.repository);
|
||||
const isGitHub = isGitHubRepository(repository);
|
||||
let enableMarketplaceQnA;
|
||||
let customerQnALink;
|
||||
if (manifest.qna === 'marketplace') {
|
||||
enableMarketplaceQnA = true;
|
||||
}
|
||||
else if (typeof manifest.qna === 'string') {
|
||||
customerQnALink = manifest.qna;
|
||||
}
|
||||
else if (manifest.qna === false) {
|
||||
enableMarketplaceQnA = false;
|
||||
}
|
||||
this.vsix = Object.assign({}, this.vsix, { id: manifest.name, displayName: manifest.displayName || manifest.name, version: manifest.version, publisher: manifest.publisher, engine: manifest.engines['vscode'], description: manifest.description || '', categories: (manifest.categories || []).join(','), flags: flags.join(' '), links: {
|
||||
repository,
|
||||
bugs: getUrl(manifest.bugs),
|
||||
homepage: manifest.homepage
|
||||
}, galleryBanner: manifest.galleryBanner || {}, badges: manifest.badges, githubMarkdown: manifest.markdown !== 'standard', enableMarketplaceQnA,
|
||||
customerQnALink, extensionDependencies: _(manifest.extensionDependencies || []).uniq().join(','), extensionPack: _(manifest.extensionPack || []).uniq().join(','), localizedLanguages: (manifest.contributes && manifest.contributes.localizations) ?
|
||||
manifest.contributes.localizations.map(loc => loc.localizedLanguageName || loc.languageName || loc.languageId).join(',') : '' });
|
||||
if (isGitHub) {
|
||||
this.vsix.links.github = repository;
|
||||
}
|
||||
}
|
||||
onEnd() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (this.manifest.publisher === 'vscode-samples') {
|
||||
throw new Error('It\'s not allowed to use the \'vscode-samples\' publisher. Learn more at: https://code.visualstudio.com/api/working-with-extensions/publishing-extension.');
|
||||
}
|
||||
if (!this.manifest.repository) {
|
||||
util.log.warn(`A 'repository' field is missing from the 'package.json' manifest file.`);
|
||||
if (!/^y$/i.test(yield util.read('Do you want to continue? [y/N] '))) {
|
||||
throw new Error('Aborted');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
class TagsProcessor extends BaseProcessor {
|
||||
onEnd() {
|
||||
const keywords = this.manifest.keywords || [];
|
||||
const contributes = this.manifest.contributes;
|
||||
const activationEvents = this.manifest.activationEvents || [];
|
||||
const doesContribute = name => contributes && contributes[name] && contributes[name].length > 0;
|
||||
const colorThemes = doesContribute('themes') ? ['theme', 'color-theme'] : [];
|
||||
const iconThemes = doesContribute('iconThemes') ? ['theme', 'icon-theme'] : [];
|
||||
const snippets = doesContribute('snippets') ? ['snippet'] : [];
|
||||
const keybindings = doesContribute('keybindings') ? ['keybindings'] : [];
|
||||
const debuggers = doesContribute('debuggers') ? ['debuggers'] : [];
|
||||
const json = doesContribute('jsonValidation') ? ['json'] : [];
|
||||
const localizationContributions = ((contributes && contributes['localizations']) || [])
|
||||
.reduce((r, l) => [...r, `lp-${l.languageId}`, ...toLanguagePackTags(l.translations, l.languageId)], []);
|
||||
const languageContributions = ((contributes && contributes['languages']) || [])
|
||||
.reduce((r, l) => [...r, l.id, ...(l.aliases || []), ...toExtensionTags(l.extensions || [])], []);
|
||||
const languageActivations = activationEvents
|
||||
.map(e => /^onLanguage:(.*)$/.exec(e))
|
||||
.filter(r => !!r)
|
||||
.map(r => r[1]);
|
||||
const grammars = ((contributes && contributes['grammars']) || [])
|
||||
.map(g => g.language);
|
||||
const description = this.manifest.description || '';
|
||||
const descriptionKeywords = Object.keys(TagsProcessor.Keywords)
|
||||
.reduce((r, k) => r.concat(new RegExp('\\b(?:' + escapeRegExp(k) + ')(?!\\w)', 'gi').test(description) ? TagsProcessor.Keywords[k] : []), []);
|
||||
const tags = [
|
||||
...keywords,
|
||||
...colorThemes,
|
||||
...iconThemes,
|
||||
...snippets,
|
||||
...keybindings,
|
||||
...debuggers,
|
||||
...json,
|
||||
...localizationContributions,
|
||||
...languageContributions,
|
||||
...languageActivations,
|
||||
...grammars,
|
||||
...descriptionKeywords
|
||||
];
|
||||
this.vsix.tags = _(tags)
|
||||
.uniq() // deduplicate
|
||||
.compact() // remove falsey values
|
||||
.join(',');
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
TagsProcessor.Keywords = {
|
||||
'git': ['git'],
|
||||
'npm': ['node'],
|
||||
'spell': ['markdown'],
|
||||
'bootstrap': ['bootstrap'],
|
||||
'lint': ['linters'],
|
||||
'linting': ['linters'],
|
||||
'react': ['javascript'],
|
||||
'js': ['javascript'],
|
||||
'node': ['javascript', 'node'],
|
||||
'c++': ['c++'],
|
||||
'Cplusplus': ['c++'],
|
||||
'xml': ['xml'],
|
||||
'angular': ['javascript'],
|
||||
'jquery': ['javascript'],
|
||||
'php': ['php'],
|
||||
'python': ['python'],
|
||||
'latex': ['latex'],
|
||||
'ruby': ['ruby'],
|
||||
'java': ['java'],
|
||||
'erlang': ['erlang'],
|
||||
'sql': ['sql'],
|
||||
'nodejs': ['node'],
|
||||
'c#': ['c#'],
|
||||
'css': ['css'],
|
||||
'javascript': ['javascript'],
|
||||
'ftp': ['ftp'],
|
||||
'haskell': ['haskell'],
|
||||
'unity': ['unity'],
|
||||
'terminal': ['terminal'],
|
||||
'powershell': ['powershell'],
|
||||
'laravel': ['laravel'],
|
||||
'meteor': ['meteor'],
|
||||
'emmet': ['emmet'],
|
||||
'eslint': ['linters'],
|
||||
'tfs': ['tfs'],
|
||||
'rust': ['rust']
|
||||
};
|
||||
exports.TagsProcessor = TagsProcessor;
|
||||
class MarkdownProcessor extends BaseProcessor {
|
||||
constructor(manifest, name, regexp, assetType, options = {}) {
|
||||
super(manifest);
|
||||
this.name = name;
|
||||
this.regexp = regexp;
|
||||
this.assetType = assetType;
|
||||
const guess = this.guessBaseUrls();
|
||||
this.baseContentUrl = options.baseContentUrl || (guess && guess.content);
|
||||
this.baseImagesUrl = options.baseImagesUrl || options.baseContentUrl || (guess && guess.images);
|
||||
this.repositoryUrl = (guess && guess.repository);
|
||||
this.isGitHub = isGitHubRepository(this.repositoryUrl);
|
||||
}
|
||||
onFile(file) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const path = util.normalize(file.path);
|
||||
if (!this.regexp.test(path)) {
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
this.assets.push({ type: this.assetType, path });
|
||||
let contents = yield read(file);
|
||||
if (/This is the README for your extension /.test(contents)) {
|
||||
throw new Error(`Make sure to edit the README.md file before you publish your extension.`);
|
||||
}
|
||||
const markdownPathRegex = /(!?)\[([^\]\[]*|!\[[^\]\[]*]\([^\)]+\))\]\(([^\)]+)\)/g;
|
||||
const urlReplace = (all, isImage, title, link) => {
|
||||
const isLinkRelative = !/^\w+:\/\//.test(link) && link[0] !== '#';
|
||||
if (!this.baseContentUrl && !this.baseImagesUrl) {
|
||||
const asset = isImage ? 'image' : 'link';
|
||||
if (isLinkRelative) {
|
||||
throw new Error(`Couldn't detect the repository where this extension is published. The ${asset} '${link}' will be broken in ${this.name}. Please provide the repository URL in package.json or use the --baseContentUrl and --baseImagesUrl options.`);
|
||||
}
|
||||
}
|
||||
title = title.replace(markdownPathRegex, urlReplace);
|
||||
const prefix = isImage ? this.baseImagesUrl : this.baseContentUrl;
|
||||
if (!prefix || !isLinkRelative) {
|
||||
return `${isImage}[${title}](${link})`;
|
||||
}
|
||||
return `${isImage}[${title}](${urljoin(prefix, link)})`;
|
||||
};
|
||||
// Replace Markdown links with urls
|
||||
contents = contents.replace(markdownPathRegex, urlReplace);
|
||||
const markdownIssueRegex = /(\s|\n)([\w\d_-]+\/[\w\d_-]+)?#(\d+)\b/g;
|
||||
const issueReplace = (all, prefix, ownerAndRepositoryName, issueNumber) => {
|
||||
let result = all;
|
||||
let owner;
|
||||
let repositoryName;
|
||||
if (ownerAndRepositoryName) {
|
||||
[owner, repositoryName] = ownerAndRepositoryName.split('/', 2);
|
||||
}
|
||||
if (this.isGitHub) {
|
||||
if (owner && repositoryName && issueNumber) {
|
||||
// Issue in external repository
|
||||
const issueUrl = urljoin('https://github.com', owner, repositoryName, 'issues', issueNumber);
|
||||
result = prefix + `[${owner}/${repositoryName}#${issueNumber}](${issueUrl})`;
|
||||
}
|
||||
else if (!owner && !repositoryName && issueNumber) {
|
||||
// Issue in own repository
|
||||
result = prefix + `[#${issueNumber}](${urljoin(this.repositoryUrl, 'issues', issueNumber)})`;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// Replace Markdown issue references with urls
|
||||
contents = contents.replace(markdownIssueRegex, issueReplace);
|
||||
const html = markdownit({ html: true }).render(contents);
|
||||
const $ = cheerio.load(html);
|
||||
$('img').each((_, img) => {
|
||||
const src = decodeURI(img.attribs.src);
|
||||
const srcUrl = url.parse(src);
|
||||
if (/^data:$/i.test(srcUrl.protocol) && /^image$/i.test(srcUrl.host) && /\/svg/i.test(srcUrl.path)) {
|
||||
throw new Error(`SVG data URLs are not allowed in ${this.name}: ${src}`);
|
||||
}
|
||||
if (!/^https:$/i.test(srcUrl.protocol)) {
|
||||
throw new Error(`Images in ${this.name} must come from an HTTPS source: ${src}`);
|
||||
}
|
||||
if (/\.svg$/i.test(srcUrl.pathname) && !isHostTrusted(srcUrl.host)) {
|
||||
throw new Error(`SVGs are restricted in ${this.name}; please use other file image formats, such as PNG: ${src}`);
|
||||
}
|
||||
});
|
||||
$('svg').each((_, svg) => {
|
||||
throw new Error(`SVG tags are not allowed in ${this.name}.`);
|
||||
});
|
||||
return {
|
||||
path: file.path,
|
||||
contents: new Buffer(contents)
|
||||
};
|
||||
});
|
||||
}
|
||||
// GitHub heuristics
|
||||
guessBaseUrls() {
|
||||
let repository = null;
|
||||
if (typeof this.manifest.repository === 'string') {
|
||||
repository = this.manifest.repository;
|
||||
}
|
||||
else if (this.manifest.repository && typeof this.manifest.repository['url'] === 'string') {
|
||||
repository = this.manifest.repository['url'];
|
||||
}
|
||||
if (!repository) {
|
||||
return null;
|
||||
}
|
||||
const regex = /github\.com\/([^/]+)\/([^/]+)(\/|$)/;
|
||||
const match = regex.exec(repository);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const account = match[1];
|
||||
const repositoryName = match[2].replace(/\.git$/i, '');
|
||||
return {
|
||||
content: `https://github.com/${account}/${repositoryName}/blob/master`,
|
||||
images: `https://github.com/${account}/${repositoryName}/raw/master`,
|
||||
repository: `https://github.com/${account}/${repositoryName}`
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.MarkdownProcessor = MarkdownProcessor;
|
||||
class ReadmeProcessor extends MarkdownProcessor {
|
||||
constructor(manifest, options = {}) {
|
||||
super(manifest, 'README.md', /^extension\/readme.md$/i, 'Microsoft.VisualStudio.Services.Content.Details', options);
|
||||
}
|
||||
}
|
||||
exports.ReadmeProcessor = ReadmeProcessor;
|
||||
class ChangelogProcessor extends MarkdownProcessor {
|
||||
constructor(manifest, options = {}) {
|
||||
super(manifest, 'CHANGELOG.md', /^extension\/changelog.md$/i, 'Microsoft.VisualStudio.Services.Content.Changelog', options);
|
||||
}
|
||||
}
|
||||
exports.ChangelogProcessor = ChangelogProcessor;
|
||||
class LicenseProcessor extends BaseProcessor {
|
||||
constructor(manifest) {
|
||||
super(manifest);
|
||||
this.didFindLicense = false;
|
||||
const match = /^SEE LICENSE IN (.*)$/.exec(manifest.license || '');
|
||||
if (!match || !match[1]) {
|
||||
this.filter = name => /^extension\/license(\.(md|txt))?$/i.test(name);
|
||||
}
|
||||
else {
|
||||
const regexp = new RegExp('^extension/' + match[1] + '$');
|
||||
this.filter = regexp.test.bind(regexp);
|
||||
}
|
||||
this.vsix.license = null;
|
||||
}
|
||||
onFile(file) {
|
||||
if (!this.didFindLicense) {
|
||||
let normalizedPath = util.normalize(file.path);
|
||||
if (this.filter(normalizedPath)) {
|
||||
if (!path.extname(normalizedPath)) {
|
||||
file.path += '.txt';
|
||||
normalizedPath += '.txt';
|
||||
}
|
||||
this.assets.push({ type: 'Microsoft.VisualStudio.Services.Content.License', path: normalizedPath });
|
||||
this.vsix.license = normalizedPath;
|
||||
this.didFindLicense = true;
|
||||
}
|
||||
}
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
}
|
||||
class IconProcessor extends BaseProcessor {
|
||||
constructor(manifest) {
|
||||
super(manifest);
|
||||
this.didFindIcon = false;
|
||||
this.icon = manifest.icon ? `extension/${manifest.icon}` : null;
|
||||
this.vsix.icon = null;
|
||||
}
|
||||
onFile(file) {
|
||||
const normalizedPath = util.normalize(file.path);
|
||||
if (normalizedPath === this.icon) {
|
||||
this.didFindIcon = true;
|
||||
this.assets.push({ type: 'Microsoft.VisualStudio.Services.Icons.Default', path: normalizedPath });
|
||||
this.vsix.icon = this.icon;
|
||||
}
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
onEnd() {
|
||||
if (this.icon && !this.didFindIcon) {
|
||||
return Promise.reject(new Error(`The specified icon '${this.icon}' wasn't found in the extension.`));
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
class NLSProcessor extends BaseProcessor {
|
||||
constructor(manifest) {
|
||||
super(manifest);
|
||||
this.translations = Object.create(null);
|
||||
if (!manifest.contributes || !manifest.contributes.localizations || manifest.contributes.localizations.length === 0) {
|
||||
return;
|
||||
}
|
||||
const localizations = manifest.contributes.localizations;
|
||||
const translations = Object.create(null);
|
||||
// take last reference in the manifest for any given language
|
||||
for (const localization of localizations) {
|
||||
for (const translation of localization.translations) {
|
||||
if (translation.id === 'vscode' && !!translation.path) {
|
||||
const translationPath = util.normalize(translation.path.replace(/^\.[\/\\]/, ''));
|
||||
translations[localization.languageId.toUpperCase()] = `extension/${translationPath}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
// invert the map for later easier retrieval
|
||||
for (const languageId of Object.keys(translations)) {
|
||||
this.translations[translations[languageId]] = languageId;
|
||||
}
|
||||
}
|
||||
onFile(file) {
|
||||
const normalizedPath = util.normalize(file.path);
|
||||
const language = this.translations[normalizedPath];
|
||||
if (language) {
|
||||
this.assets.push({ type: `Microsoft.VisualStudio.Code.Translation.${language}`, path: normalizedPath });
|
||||
}
|
||||
return Promise.resolve(file);
|
||||
}
|
||||
}
|
||||
exports.NLSProcessor = NLSProcessor;
|
||||
function validateManifest(manifest) {
|
||||
validation_1.validatePublisher(manifest.publisher);
|
||||
validation_1.validateExtensionName(manifest.name);
|
||||
if (!manifest.version) {
|
||||
throw new Error('Manifest missing field: version');
|
||||
}
|
||||
validation_1.validateVersion(manifest.version);
|
||||
if (!manifest.engines) {
|
||||
throw new Error('Manifest missing field: engines');
|
||||
}
|
||||
if (!manifest.engines['vscode']) {
|
||||
throw new Error('Manifest missing field: engines.vscode');
|
||||
}
|
||||
validation_1.validateEngineCompatibility(manifest.engines['vscode']);
|
||||
if (manifest.devDependencies && manifest.devDependencies['@types/vscode']) {
|
||||
validation_1.validateVSCodeTypesCompatibility(manifest.engines['vscode'], manifest.devDependencies['@types/vscode']);
|
||||
}
|
||||
if (/\.svg$/i.test(manifest.icon || '')) {
|
||||
throw new Error(`SVGs can't be used as icons: ${manifest.icon}`);
|
||||
}
|
||||
(manifest.badges || []).forEach(badge => {
|
||||
const decodedUrl = decodeURI(badge.url);
|
||||
const srcUrl = url.parse(decodedUrl);
|
||||
if (!/^https:$/i.test(srcUrl.protocol)) {
|
||||
throw new Error(`Badge URLs must come from an HTTPS source: ${badge.url}`);
|
||||
}
|
||||
if (/\.svg$/i.test(srcUrl.pathname) && !isHostTrusted(srcUrl.host)) {
|
||||
throw new Error(`Badge SVGs are restricted. Please use other file image formats, such as PNG: ${badge.url}`);
|
||||
}
|
||||
});
|
||||
Object.keys((manifest.dependencies || {})).forEach(dep => {
|
||||
if (dep === 'vscode') {
|
||||
throw new Error(`You should not depend on 'vscode' in your 'dependencies'. Did you mean to add it to 'devDependencies'?`);
|
||||
}
|
||||
});
|
||||
return manifest;
|
||||
}
|
||||
exports.validateManifest = validateManifest;
|
||||
function readManifest(cwd = process.cwd(), nls = true) {
|
||||
const manifestPath = path.join(cwd, 'package.json');
|
||||
const manifestNLSPath = path.join(cwd, 'package.nls.json');
|
||||
const manifest = readFile(manifestPath, 'utf8')
|
||||
.catch(() => Promise.reject(`Extension manifest not found: ${manifestPath}`))
|
||||
.then(manifestStr => {
|
||||
try {
|
||||
return Promise.resolve(JSON.parse(manifestStr));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(`Error parsing 'package.json' manifest file: not a valid JSON file.`);
|
||||
}
|
||||
})
|
||||
.then(validateManifest);
|
||||
if (!nls) {
|
||||
return manifest;
|
||||
}
|
||||
const manifestNLS = readFile(manifestNLSPath, 'utf8')
|
||||
.catch(err => err.code !== 'ENOENT' ? Promise.reject(err) : Promise.resolve('{}'))
|
||||
.then(raw => {
|
||||
try {
|
||||
return Promise.resolve(JSON.parse(raw));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(`Error parsing JSON manifest translations file: ${manifestNLSPath}`);
|
||||
}
|
||||
});
|
||||
return Promise.all([manifest, manifestNLS]).then(([manifest, translations]) => {
|
||||
return nls_1.patchNLS(manifest, translations);
|
||||
});
|
||||
}
|
||||
exports.readManifest = readManifest;
|
||||
function toVsixManifest(assets, vsix, options = {}) {
|
||||
return readFile(vsixManifestTemplatePath, 'utf8')
|
||||
.then(vsixManifestTemplateStr => _.template(vsixManifestTemplateStr))
|
||||
.then(vsixManifestTemplate => vsixManifestTemplate(vsix));
|
||||
}
|
||||
exports.toVsixManifest = toVsixManifest;
|
||||
const defaultExtensions = {
|
||||
'.json': 'application/json',
|
||||
'.vsixmanifest': 'text/xml'
|
||||
};
|
||||
function toContentTypes(files) {
|
||||
const extensions = Object.keys(_.keyBy(files, f => path.extname(f.path).toLowerCase()))
|
||||
.filter(e => !!e)
|
||||
.reduce((r, e) => (Object.assign({}, r, { [e]: mime_1.lookup(e) })), {});
|
||||
const allExtensions = Object.assign({}, extensions, defaultExtensions);
|
||||
const contentTypes = Object.keys(allExtensions).map(extension => ({
|
||||
extension,
|
||||
contentType: allExtensions[extension]
|
||||
}));
|
||||
return readFile(contentTypesTemplatePath, 'utf8')
|
||||
.then(contentTypesTemplateStr => _.template(contentTypesTemplateStr))
|
||||
.then(contentTypesTemplate => contentTypesTemplate({ contentTypes }));
|
||||
}
|
||||
exports.toContentTypes = toContentTypes;
|
||||
const defaultIgnore = [
|
||||
'.vscodeignore',
|
||||
'package-lock.json',
|
||||
'yarn.lock',
|
||||
'.editorconfig',
|
||||
'.npmrc',
|
||||
'.yarnrc',
|
||||
'.gitattributes',
|
||||
'*.todo',
|
||||
'tslint.yaml',
|
||||
'.eslintrc*',
|
||||
'.babelrc*',
|
||||
'.prettierrc',
|
||||
'ISSUE_TEMPLATE.md',
|
||||
'CONTRIBUTING.md',
|
||||
'PULL_REQUEST_TEMPLATE.md',
|
||||
'CODE_OF_CONDUCT.md',
|
||||
'.github',
|
||||
'.travis.yml',
|
||||
'appveyor.yml',
|
||||
'**/.git/**',
|
||||
'**/*.vsix',
|
||||
'**/.DS_Store',
|
||||
'**/*.vsixmanifest',
|
||||
'**/.vscode-test/**'
|
||||
];
|
||||
function collectAllFiles(cwd, useYarn = false, dependencyEntryPoints) {
|
||||
return npm_1.getDependencies(cwd, useYarn, dependencyEntryPoints).then(deps => {
|
||||
const promises = deps.map(dep => {
|
||||
return glob('**', { cwd: dep, nodir: true, dot: true, ignore: 'node_modules/**' })
|
||||
.then(files => files
|
||||
.map(f => path.relative(cwd, path.join(dep, f)))
|
||||
.map(f => f.replace(/\\/g, '/')));
|
||||
});
|
||||
return Promise.all(promises).then(util.flatten);
|
||||
});
|
||||
}
|
||||
function collectFiles(cwd, useYarn = false, dependencyEntryPoints) {
|
||||
return collectAllFiles(cwd, useYarn, dependencyEntryPoints).then(files => {
|
||||
files = files.filter(f => !/\r$/m.test(f));
|
||||
return readFile(path.join(cwd, '.vscodeignore'), 'utf8')
|
||||
.catch(err => err.code !== 'ENOENT' ? Promise.reject(err) : Promise.resolve(''))
|
||||
// Parse raw ignore by splitting output into lines and filtering out empty lines and comments
|
||||
.then(rawIgnore => rawIgnore.split(/[\n\r]/).map(s => s.trim()).filter(s => !!s).filter(i => !/^\s*#/.test(i)))
|
||||
// Add '/**' to possible folder names
|
||||
.then(ignore => [...ignore, ...ignore.filter(i => !/(^|\/)[^/]*\*[^/]*$/.test(i)).map(i => /\/$/.test(i) ? `${i}**` : `${i}/**`)])
|
||||
// Combine with default ignore list
|
||||
.then(ignore => [...defaultIgnore, ...ignore, '!package.json'])
|
||||
// Split into ignore and negate list
|
||||
.then(ignore => _.partition(ignore, i => !/^\s*!/.test(i)))
|
||||
.then(r => ({ ignore: r[0], negate: r[1] }))
|
||||
// Filter out files
|
||||
.then(({ ignore, negate }) => files.filter(f => !ignore.some(i => minimatch(f, i, MinimatchOptions)) || negate.some(i => minimatch(f, i.substr(1), MinimatchOptions))));
|
||||
});
|
||||
}
|
||||
function processFiles(processors, files, options = {}) {
|
||||
const processedFiles = files.map(file => util.chain(file, processors, (file, processor) => processor.onFile(file)));
|
||||
return Promise.all(processedFiles).then(files => {
|
||||
return util.sequence(processors.map(p => () => p.onEnd())).then(() => {
|
||||
const assets = _.flatten(processors.map(p => p.assets));
|
||||
const vsix = processors.reduce((r, p) => (Object.assign({}, r, p.vsix)), { assets });
|
||||
return Promise.all([toVsixManifest(assets, vsix, options), toContentTypes(files)]).then(result => {
|
||||
return [
|
||||
{ path: 'extension.vsixmanifest', contents: new Buffer(result[0], 'utf8') },
|
||||
{ path: '[Content_Types].xml', contents: new Buffer(result[1], 'utf8') },
|
||||
...files
|
||||
];
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.processFiles = processFiles;
|
||||
function createDefaultProcessors(manifest, options = {}) {
|
||||
return [
|
||||
new ManifestProcessor(manifest),
|
||||
new TagsProcessor(manifest),
|
||||
new ReadmeProcessor(manifest, options),
|
||||
new ChangelogProcessor(manifest, options),
|
||||
new LicenseProcessor(manifest),
|
||||
new IconProcessor(manifest),
|
||||
new NLSProcessor(manifest)
|
||||
];
|
||||
}
|
||||
exports.createDefaultProcessors = createDefaultProcessors;
|
||||
function collect(manifest, options = {}) {
|
||||
const cwd = options.cwd || process.cwd();
|
||||
const useYarn = options.useYarn || false;
|
||||
const packagedDependencies = options.dependencyEntryPoints || undefined;
|
||||
const processors = createDefaultProcessors(manifest, options);
|
||||
return collectFiles(cwd, useYarn, packagedDependencies).then(fileNames => {
|
||||
const files = fileNames.map(f => ({ path: `extension/${f}`, localPath: path.join(cwd, f) }));
|
||||
return processFiles(processors, files, options);
|
||||
});
|
||||
}
|
||||
exports.collect = collect;
|
||||
function writeVsix(files, packagePath) {
|
||||
return unlink(packagePath)
|
||||
.catch(err => err.code !== 'ENOENT' ? Promise.reject(err) : Promise.resolve(null))
|
||||
.then(() => new Promise((c, e) => {
|
||||
const zip = new yazl.ZipFile();
|
||||
files.forEach(f => f.contents ? zip.addBuffer(typeof f.contents === 'string' ? new Buffer(f.contents, 'utf8') : f.contents, f.path) : zip.addFile(f.localPath, f.path));
|
||||
zip.end();
|
||||
const zipStream = fs.createWriteStream(packagePath);
|
||||
zip.outputStream.pipe(zipStream);
|
||||
zip.outputStream.once('error', e);
|
||||
zipStream.once('error', e);
|
||||
zipStream.once('finish', () => c(packagePath));
|
||||
}));
|
||||
}
|
||||
function defaultPackagePath(cwd, manifest) {
|
||||
return path.join(cwd, `${manifest.name}-${manifest.version}.vsix`);
|
||||
}
|
||||
function prepublish(cwd, manifest, useYarn = false) {
|
||||
if (!manifest.scripts || !manifest.scripts['vscode:prepublish']) {
|
||||
return Promise.resolve(manifest);
|
||||
}
|
||||
console.warn(`Executing prepublish script '${useYarn ? 'yarn' : 'npm'} run vscode:prepublish'...`);
|
||||
return exec(`${useYarn ? 'yarn' : 'npm'} run vscode:prepublish`, { cwd, maxBuffer: 5000 * 1024 })
|
||||
.then(({ stdout, stderr }) => {
|
||||
process.stdout.write(stdout);
|
||||
process.stderr.write(stderr);
|
||||
return Promise.resolve(manifest);
|
||||
})
|
||||
.catch(err => Promise.reject(err.message));
|
||||
}
|
||||
function pack(options = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const cwd = options.cwd || process.cwd();
|
||||
let manifest = yield readManifest(cwd);
|
||||
manifest = yield prepublish(cwd, manifest, options.useYarn);
|
||||
const files = yield collect(manifest, options);
|
||||
if (files.length > 100) {
|
||||
console.log(`This extension consists of ${files.length} separate files. For performance reasons, you should bundle your extension: https://aka.ms/vscode-bundle-extension. You should also exclude unnecessary files by adding them to your .vscodeignore: https://aka.ms/vscode-vscodeignore`);
|
||||
}
|
||||
const packagePath = yield writeVsix(files, path.resolve(options.packagePath || defaultPackagePath(cwd, manifest)));
|
||||
return { manifest, packagePath, files };
|
||||
});
|
||||
}
|
||||
exports.pack = pack;
|
||||
function packageCommand(options = {}) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { packagePath, files } = yield pack(options);
|
||||
const stats = yield stat(packagePath);
|
||||
let size = 0;
|
||||
let unit = '';
|
||||
if (stats.size > 1048576) {
|
||||
size = Math.round(stats.size / 10485.76) / 100;
|
||||
unit = 'MB';
|
||||
}
|
||||
else {
|
||||
size = Math.round(stats.size / 10.24) / 100;
|
||||
unit = 'KB';
|
||||
}
|
||||
util.log.done(`Packaged: ${packagePath} (${files.length} files, ${size}${unit})`);
|
||||
});
|
||||
}
|
||||
exports.packageCommand = packageCommand;
|
||||
/**
|
||||
* Lists the files included in the extension's package. Does not run prepublish.
|
||||
*/
|
||||
function listFiles(cwd = process.cwd(), useYarn = false, packagedDependencies) {
|
||||
return readManifest(cwd)
|
||||
.then(manifest => collectFiles(cwd, useYarn, packagedDependencies));
|
||||
}
|
||||
exports.listFiles = listFiles;
|
||||
/**
|
||||
* Lists the files included in the extension's package. Runs prepublish.
|
||||
*/
|
||||
function ls(cwd = process.cwd(), useYarn = false, packagedDependencies) {
|
||||
return readManifest(cwd)
|
||||
.then(manifest => prepublish(cwd, manifest, useYarn))
|
||||
.then(manifest => collectFiles(cwd, useYarn, packagedDependencies))
|
||||
.then(files => files.forEach(f => console.log(`${f}`)));
|
||||
}
|
||||
exports.ls = ls;
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const HttpClient_1 = require("typed-rest-client/HttpClient");
|
||||
const GalleryInterfaces_1 = require("azure-devops-node-api/interfaces/GalleryInterfaces");
|
||||
const Serialization_1 = require("azure-devops-node-api/Serialization");
|
||||
class PublicGalleryAPI {
|
||||
constructor(baseUrl, apiVersion = '3.0-preview.1') {
|
||||
this.baseUrl = baseUrl;
|
||||
this.apiVersion = apiVersion;
|
||||
this.client = new HttpClient_1.HttpClient('vsce');
|
||||
}
|
||||
post(url, data, additionalHeaders) {
|
||||
return this.client.post(`${this.baseUrl}/_apis/public${url}`, data, additionalHeaders);
|
||||
}
|
||||
extensionQuery({ pageNumber = 1, pageSize = 1, sortBy = GalleryInterfaces_1.SortByType.Relevance, sortOrder = GalleryInterfaces_1.SortOrderType.Default, flags = [], criteria = [], assetTypes = [], }) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const data = JSON.stringify({
|
||||
filters: [{ pageNumber, pageSize, criteria }],
|
||||
assetTypes,
|
||||
flags: flags.reduce((memo, flag) => memo | flag, 0)
|
||||
});
|
||||
const res = yield this.post('/gallery/extensionquery', data, { Accept: `application/json;api-version=${this.apiVersion}`, 'Content-Type': 'application/json', });
|
||||
const raw = JSON.parse(yield res.readBody());
|
||||
return Serialization_1.ContractSerializer.deserialize(raw.results[0].extensions, GalleryInterfaces_1.TypeInfo.PublishedExtension, false, false);
|
||||
});
|
||||
}
|
||||
getExtension(extensionId, flags = []) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const query = { criteria: [{ filterType: GalleryInterfaces_1.ExtensionQueryFilterType.Name, value: extensionId }], flags, };
|
||||
const extensions = yield this.extensionQuery(query);
|
||||
return extensions.filter(({ publisher: { publisherName: publisher }, extensionName: name }) => extensionId.toLowerCase() === `${publisher}.${name}`.toLowerCase())[0];
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.PublicGalleryAPI = PublicGalleryAPI;
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs = require("fs");
|
||||
const GalleryInterfaces_1 = require("azure-devops-node-api/interfaces/GalleryInterfaces");
|
||||
const package_1 = require("./package");
|
||||
const tmp = require("tmp");
|
||||
const store_1 = require("./store");
|
||||
const util_1 = require("./util");
|
||||
const denodeify = require("denodeify");
|
||||
const yauzl = require("yauzl");
|
||||
const semver = require("semver");
|
||||
const cp = require("child_process");
|
||||
const exec = denodeify(cp.exec, (err, stdout, stderr) => [err, { stdout, stderr }]);
|
||||
const tmpName = denodeify(tmp.tmpName);
|
||||
function readManifestFromPackage(packagePath) {
|
||||
return new Promise((c, e) => {
|
||||
yauzl.open(packagePath, (err, zipfile) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
const onEnd = () => e(new Error('Manifest not found'));
|
||||
zipfile.once('end', onEnd);
|
||||
zipfile.on('entry', entry => {
|
||||
if (!/^extension\/package\.json$/i.test(entry.fileName)) {
|
||||
return;
|
||||
}
|
||||
zipfile.removeListener('end', onEnd);
|
||||
zipfile.openReadStream(entry, (err, stream) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
const buffers = [];
|
||||
stream.on('data', buffer => buffers.push(buffer));
|
||||
stream.once('error', e);
|
||||
stream.once('end', () => {
|
||||
try {
|
||||
c(JSON.parse(Buffer.concat(buffers).toString('utf8')));
|
||||
}
|
||||
catch (err) {
|
||||
e(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function _publish(packagePath, pat, manifest) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const api = yield util_1.getGalleryAPI(pat);
|
||||
const packageStream = fs.createReadStream(packagePath);
|
||||
const name = `${manifest.publisher}.${manifest.name}`;
|
||||
const fullName = `${name}@${manifest.version}`;
|
||||
console.log(`Publishing ${fullName}...`);
|
||||
return api.getExtension(null, manifest.publisher, manifest.name, null, GalleryInterfaces_1.ExtensionQueryFlags.IncludeVersions)
|
||||
.catch(err => err.statusCode === 404 ? null : Promise.reject(err))
|
||||
.then(extension => {
|
||||
if (extension && extension.versions.some(v => v.version === manifest.version)) {
|
||||
return Promise.reject(`${fullName} already exists. Version number cannot be the same.`);
|
||||
}
|
||||
var promise = extension
|
||||
? api.updateExtension(undefined, packageStream, manifest.publisher, manifest.name)
|
||||
: api.createExtension(undefined, packageStream);
|
||||
return promise
|
||||
.catch(err => Promise.reject(err.statusCode === 409 ? `${fullName} already exists.` : err))
|
||||
.then(() => util_1.log.done(`Published ${fullName}\nYour extension will live at ${util_1.getPublishedUrl(name)} (might take a few seconds for it to show up).`));
|
||||
})
|
||||
.catch(err => {
|
||||
const message = err && err.message || '';
|
||||
if (/Invalid Resource/.test(message)) {
|
||||
err.message = `${err.message}\n\nYou're likely using an expired Personal Access Token, please get a new PAT.\nMore info: https://aka.ms/vscodepat`;
|
||||
}
|
||||
return Promise.reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
function versionBump(cwd = process.cwd(), version, commitMessage) {
|
||||
if (!version) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
switch (version) {
|
||||
case 'major':
|
||||
case 'minor':
|
||||
case 'patch':
|
||||
break;
|
||||
case 'premajor':
|
||||
case 'preminor':
|
||||
case 'prepatch':
|
||||
case 'prerelease':
|
||||
case 'from-git':
|
||||
return Promise.reject(`Not supported: ${version}`);
|
||||
default:
|
||||
if (!semver.valid(version)) {
|
||||
return Promise.reject(`Invalid version ${version}`);
|
||||
}
|
||||
}
|
||||
let command = `npm version ${version}`;
|
||||
if (commitMessage) {
|
||||
command = `${command} -m "${commitMessage}"`;
|
||||
}
|
||||
// call `npm version` to do our dirty work
|
||||
return exec(command, { cwd })
|
||||
.then(({ stdout, stderr }) => {
|
||||
process.stdout.write(stdout);
|
||||
process.stderr.write(stderr);
|
||||
return Promise.resolve(null);
|
||||
})
|
||||
.catch(err => Promise.reject(err.message));
|
||||
}
|
||||
function publish(options = {}) {
|
||||
let promise;
|
||||
if (options.packagePath) {
|
||||
if (options.version) {
|
||||
return Promise.reject(`Not supported: packagePath and version.`);
|
||||
}
|
||||
promise = readManifestFromPackage(options.packagePath)
|
||||
.then(manifest => ({ manifest, packagePath: options.packagePath }));
|
||||
}
|
||||
else {
|
||||
const cwd = options.cwd;
|
||||
const baseContentUrl = options.baseContentUrl;
|
||||
const baseImagesUrl = options.baseImagesUrl;
|
||||
const useYarn = options.useYarn;
|
||||
promise = versionBump(options.cwd, options.version, options.commitMessage)
|
||||
.then(() => tmpName())
|
||||
.then(packagePath => package_1.pack({ packagePath, cwd, baseContentUrl, baseImagesUrl, useYarn }));
|
||||
}
|
||||
return promise.then(({ manifest, packagePath }) => {
|
||||
if (!options.noVerify && manifest.enableProposedApi) {
|
||||
throw new Error('Extensions using proposed API (enableProposedApi: true) can\'t be published to the Marketplace');
|
||||
}
|
||||
const patPromise = options.pat
|
||||
? Promise.resolve(options.pat)
|
||||
: store_1.getPublisher(manifest.publisher).then(p => p.pat);
|
||||
return patPromise.then(pat => _publish(packagePath, pat, manifest));
|
||||
});
|
||||
}
|
||||
exports.publish = publish;
|
||||
function unpublish(options = {}) {
|
||||
let promise;
|
||||
if (options.id) {
|
||||
const [publisher, name] = options.id.split('.');
|
||||
promise = Promise.resolve(({ publisher, name }));
|
||||
}
|
||||
else {
|
||||
promise = package_1.readManifest(options.cwd);
|
||||
}
|
||||
return promise.then(({ publisher, name }) => {
|
||||
const fullName = `${publisher}.${name}`;
|
||||
const pat = options.pat
|
||||
? Promise.resolve(options.pat)
|
||||
: store_1.getPublisher(publisher).then(p => p.pat);
|
||||
return util_1.read(`This will FOREVER delete '${fullName}'! Are you sure? [y/N] `)
|
||||
.then(answer => /^y$/i.test(answer) ? null : Promise.reject('Aborted'))
|
||||
.then(() => pat)
|
||||
.then(util_1.getGalleryAPI)
|
||||
.then(api => api.deleteExtension(publisher, name))
|
||||
.then(() => util_1.log.done(`Deleted extension: ${fullName}!`));
|
||||
});
|
||||
}
|
||||
exports.unpublish = unpublish;
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const util_1 = require("./util");
|
||||
const GalleryInterfaces_1 = require("azure-devops-node-api/interfaces/GalleryInterfaces");
|
||||
const viewutils_1 = require("./viewutils");
|
||||
const pageSize = 100;
|
||||
function search(searchText, json = false, pageNumber = 1) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const flags = [];
|
||||
const api = util_1.getPublicGalleryAPI();
|
||||
const results = yield api.extensionQuery({
|
||||
pageSize,
|
||||
criteria: [
|
||||
{ filterType: GalleryInterfaces_1.ExtensionQueryFilterType.SearchText, value: searchText },
|
||||
],
|
||||
flags,
|
||||
});
|
||||
if (json) {
|
||||
console.log(JSON.stringify(results, undefined, '\t'));
|
||||
return;
|
||||
}
|
||||
if (!results.length) {
|
||||
console.log('No matching results');
|
||||
return;
|
||||
}
|
||||
console.log([
|
||||
`Search results:`,
|
||||
'',
|
||||
...viewutils_1.tableView([
|
||||
['<ExtensionId>', '<Description>'],
|
||||
...results.map(({ publisher: { publisherName }, extensionName, shortDescription }) => [publisherName + '.' + extensionName, (shortDescription || '').replace(/\n|\r|\t/g, ' ')])
|
||||
]),
|
||||
'',
|
||||
'For more information on an extension use "vsce show <extensionId>"',
|
||||
]
|
||||
.map(line => viewutils_1.wordTrim(line.replace(/\s+$/g, '')))
|
||||
.join('\n'));
|
||||
});
|
||||
}
|
||||
exports.search = search;
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const util_1 = require("./util");
|
||||
const GalleryInterfaces_1 = require("azure-devops-node-api/interfaces/GalleryInterfaces");
|
||||
const viewutils_1 = require("./viewutils");
|
||||
const limitVersions = 6;
|
||||
const isExtensionTag = /^__ext_(.*)$/;
|
||||
function show(extensionId, json = false) {
|
||||
const flags = [
|
||||
GalleryInterfaces_1.ExtensionQueryFlags.IncludeCategoryAndTags,
|
||||
GalleryInterfaces_1.ExtensionQueryFlags.IncludeMetadata,
|
||||
GalleryInterfaces_1.ExtensionQueryFlags.IncludeStatistics,
|
||||
GalleryInterfaces_1.ExtensionQueryFlags.IncludeVersions,
|
||||
];
|
||||
return util_1.getPublicGalleryAPI()
|
||||
.getExtension(extensionId, flags)
|
||||
.then(extension => {
|
||||
if (json) {
|
||||
console.log(JSON.stringify(extension, undefined, '\t'));
|
||||
}
|
||||
else {
|
||||
if (extension === undefined) {
|
||||
util_1.log.error(`Extension "${extensionId}" not found.`);
|
||||
}
|
||||
else {
|
||||
showOverview(extension);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.show = show;
|
||||
function showOverview({ displayName = 'unknown', extensionName = 'unknown', shortDescription = '', versions = [], publisher: { displayName: publisherDisplayName, publisherName }, categories = [], tags = [], statistics = [], publishedDate, lastUpdated, }) {
|
||||
const [{ version = 'unknown' } = {}] = versions;
|
||||
// Create formatted table list of versions
|
||||
const versionList = versions
|
||||
.slice(0, limitVersions)
|
||||
.map(({ version, lastUpdated }) => [version, viewutils_1.formatDate(lastUpdated)]);
|
||||
const { install: installs = 0, averagerating = 0, ratingcount = 0, } = statistics
|
||||
.reduce((map, { statisticName, value }) => (Object.assign({}, map, { [statisticName]: value })), {});
|
||||
// Render
|
||||
console.log([
|
||||
`${displayName}`,
|
||||
`${publisherDisplayName} | ${viewutils_1.icons.download} ` +
|
||||
`${Number(installs).toLocaleString()} installs |` +
|
||||
` ${viewutils_1.ratingStars(averagerating)} (${ratingcount})`,
|
||||
'',
|
||||
`${shortDescription}`,
|
||||
'',
|
||||
'Recent versions:',
|
||||
...(versionList.length ? viewutils_1.tableView(versionList).map(viewutils_1.indentRow) : ['no versions found']),
|
||||
'',
|
||||
'Categories:',
|
||||
` ${categories.join(', ')}`,
|
||||
'',
|
||||
'Tags:',
|
||||
` ${tags.filter(tag => !isExtensionTag.test(tag)).join(', ')}`,
|
||||
'',
|
||||
'More info:',
|
||||
...viewutils_1.tableView([
|
||||
['Unique identifier:', `${publisherName}.${extensionName}`],
|
||||
['Version:', version],
|
||||
['Last updated:', viewutils_1.formatDateTime(lastUpdated)],
|
||||
['Publisher:', publisherDisplayName],
|
||||
['Published at:', viewutils_1.formatDate(publishedDate)],
|
||||
])
|
||||
.map(viewutils_1.indentRow),
|
||||
'',
|
||||
'Statistics:',
|
||||
...viewutils_1.tableView(statistics.map(({ statisticName, value }) => [statisticName, Number(value).toFixed(2)]))
|
||||
.map(viewutils_1.indentRow),
|
||||
]
|
||||
.map(line => viewutils_1.wordWrap(line))
|
||||
.join('\n'));
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const osenv_1 = require("osenv");
|
||||
const util_1 = require("./util");
|
||||
const validation_1 = require("./validation");
|
||||
const denodeify = require("denodeify");
|
||||
const readFile = denodeify(fs.readFile);
|
||||
const writeFile = denodeify(fs.writeFile);
|
||||
const storePath = path.join(osenv_1.home(), '.vsce');
|
||||
function load() {
|
||||
return readFile(storePath, 'utf8')
|
||||
.catch(err => err.code !== 'ENOENT' ? Promise.reject(err) : Promise.resolve('{}'))
|
||||
.then(rawStore => {
|
||||
try {
|
||||
return Promise.resolve(JSON.parse(rawStore));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(`Error parsing store: ${storePath}`);
|
||||
}
|
||||
})
|
||||
.then(store => {
|
||||
store.publishers = store.publishers || [];
|
||||
return Promise.resolve(store);
|
||||
});
|
||||
}
|
||||
function save(store) {
|
||||
return writeFile(storePath, JSON.stringify(store))
|
||||
.then(() => store);
|
||||
}
|
||||
function addPublisherToStore(store, publisher) {
|
||||
store.publishers = [...store.publishers.filter(p => p.name !== publisher.name), publisher];
|
||||
return save(store).then(() => publisher);
|
||||
}
|
||||
function removePublisherFromStore(store, publisherName) {
|
||||
store.publishers = store.publishers.filter(p => p.name !== publisherName);
|
||||
return save(store);
|
||||
}
|
||||
function requestPAT(store, publisherName) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const pat = yield util_1.read(`Personal Access Token for publisher '${publisherName}':`, { silent: true, replace: '*' });
|
||||
// If the caller of the `getRoleAssignments` API has any of the roles
|
||||
// (Creator, Owner, Contributor, Reader) on the publisher, we get a 200,
|
||||
// otherwise we get a 403.
|
||||
const api = yield util_1.getSecurityRolesAPI(pat);
|
||||
yield api.getRoleAssignments('gallery.publisher', publisherName);
|
||||
return yield addPublisherToStore(store, { name: publisherName, pat });
|
||||
});
|
||||
}
|
||||
function getPublisher(publisherName) {
|
||||
validation_1.validatePublisher(publisherName);
|
||||
return load().then(store => {
|
||||
const publisher = store.publishers.filter(p => p.name === publisherName)[0];
|
||||
return publisher ? Promise.resolve(publisher) : requestPAT(store, publisherName);
|
||||
});
|
||||
}
|
||||
exports.getPublisher = getPublisher;
|
||||
function loginPublisher(publisherName) {
|
||||
validation_1.validatePublisher(publisherName);
|
||||
return load()
|
||||
.then(store => {
|
||||
const publisher = store.publishers.filter(p => p.name === publisherName)[0];
|
||||
if (publisher) {
|
||||
console.log(`Publisher '${publisherName}' is already known`);
|
||||
return util_1.read('Do you want to overwrite its PAT? [y/N] ')
|
||||
.then(answer => /^y$/i.test(answer) ? store : Promise.reject('Aborted'));
|
||||
}
|
||||
return Promise.resolve(store);
|
||||
})
|
||||
.then(store => requestPAT(store, publisherName));
|
||||
}
|
||||
exports.loginPublisher = loginPublisher;
|
||||
function logoutPublisher(publisherName) {
|
||||
validation_1.validatePublisher(publisherName);
|
||||
return load().then(store => {
|
||||
const publisher = store.publishers.filter(p => p.name === publisherName)[0];
|
||||
if (!publisher) {
|
||||
return Promise.reject(`Unknown publisher '${publisherName}'`);
|
||||
}
|
||||
return removePublisherFromStore(store, publisherName);
|
||||
});
|
||||
}
|
||||
exports.logoutPublisher = logoutPublisher;
|
||||
function createPublisher(publisherName) {
|
||||
validation_1.validatePublisher(publisherName);
|
||||
return util_1.read(`Publisher human-friendly name: `, { default: publisherName }).then(displayName => {
|
||||
return util_1.read(`E-mail: `).then(email => {
|
||||
return util_1.read(`Personal Access Token:`, { silent: true, replace: '*' })
|
||||
.then((pat) => __awaiter(this, void 0, void 0, function* () {
|
||||
const api = yield util_1.getGalleryAPI(pat);
|
||||
const raw = {
|
||||
publisherName,
|
||||
displayName,
|
||||
extensions: [],
|
||||
flags: null,
|
||||
lastUpdated: null,
|
||||
longDescription: '',
|
||||
publisherId: null,
|
||||
shortDescription: '',
|
||||
emailAddress: [email]
|
||||
};
|
||||
yield api.createPublisher(raw);
|
||||
return { name: publisherName, pat };
|
||||
}))
|
||||
.then(publisher => load().then(store => addPublisherToStore(store, publisher)));
|
||||
});
|
||||
})
|
||||
.then(() => util_1.log.done(`Created publisher '${publisherName}'.`));
|
||||
}
|
||||
exports.createPublisher = createPublisher;
|
||||
function deletePublisher(publisherName) {
|
||||
return getPublisher(publisherName).then(({ pat }) => {
|
||||
return util_1.read(`This will FOREVER delete '${publisherName}'! Are you sure? [y/N] `)
|
||||
.then(answer => /^y$/i.test(answer) ? null : Promise.reject('Aborted'))
|
||||
.then(() => util_1.getGalleryAPI(pat))
|
||||
.then(api => api.deletePublisher(publisherName))
|
||||
.then(() => load().then(store => removePublisherFromStore(store, publisherName)))
|
||||
.then(() => util_1.log.done(`Deleted publisher '${publisherName}'.`));
|
||||
});
|
||||
}
|
||||
exports.deletePublisher = deletePublisher;
|
||||
function listPublishers() {
|
||||
return load()
|
||||
.then(store => store.publishers)
|
||||
.then(publishers => publishers.forEach(p => console.log(p.name)));
|
||||
}
|
||||
exports.listPublishers = listPublishers;
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
"use strict";
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const _read = require("read");
|
||||
const WebApi_1 = require("azure-devops-node-api/WebApi");
|
||||
const GalleryApi_1 = require("azure-devops-node-api/GalleryApi");
|
||||
const denodeify = require("denodeify");
|
||||
const chalk_1 = require("chalk");
|
||||
const publicgalleryapi_1 = require("./publicgalleryapi");
|
||||
const __read = denodeify(_read);
|
||||
function read(prompt, options = {}) {
|
||||
if (process.env['VSCE_TESTS'] || !process.stdout.isTTY) {
|
||||
return Promise.resolve('y');
|
||||
}
|
||||
return __read(Object.assign({ prompt }, options));
|
||||
}
|
||||
exports.read = read;
|
||||
const marketplaceUrl = process.env['VSCE_MARKETPLACE_URL'] || 'https://marketplace.visualstudio.com';
|
||||
function getPublishedUrl(extension) {
|
||||
return `${marketplaceUrl}/items?itemName=${extension}`;
|
||||
}
|
||||
exports.getPublishedUrl = getPublishedUrl;
|
||||
function getGalleryAPI(pat) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// from https://github.com/Microsoft/tfs-cli/blob/master/app/exec/extension/default.ts#L287-L292
|
||||
const authHandler = WebApi_1.getBasicHandler('OAuth', pat);
|
||||
return new GalleryApi_1.GalleryApi(marketplaceUrl, [authHandler]);
|
||||
// const vsoapi = new WebApi(marketplaceUrl, authHandler);
|
||||
// return await vsoapi.getGalleryApi();
|
||||
});
|
||||
}
|
||||
exports.getGalleryAPI = getGalleryAPI;
|
||||
function getSecurityRolesAPI(pat) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const authHandler = WebApi_1.getBasicHandler('OAuth', pat);
|
||||
const vsoapi = new WebApi_1.WebApi(marketplaceUrl, authHandler);
|
||||
return yield vsoapi.getSecurityRolesApi();
|
||||
});
|
||||
}
|
||||
exports.getSecurityRolesAPI = getSecurityRolesAPI;
|
||||
function getPublicGalleryAPI() {
|
||||
return new publicgalleryapi_1.PublicGalleryAPI(marketplaceUrl, '3.0-preview.1');
|
||||
}
|
||||
exports.getPublicGalleryAPI = getPublicGalleryAPI;
|
||||
function normalize(path) {
|
||||
return path.replace(/\\/g, '/');
|
||||
}
|
||||
exports.normalize = normalize;
|
||||
function chain2(a, b, fn, index = 0) {
|
||||
if (index >= b.length) {
|
||||
return Promise.resolve(a);
|
||||
}
|
||||
return fn(a, b[index]).then(a => chain2(a, b, fn, index + 1));
|
||||
}
|
||||
function chain(initial, processors, process) {
|
||||
return chain2(initial, processors, process);
|
||||
}
|
||||
exports.chain = chain;
|
||||
function flatten(arr) {
|
||||
return [].concat.apply([], arr);
|
||||
}
|
||||
exports.flatten = flatten;
|
||||
const CancelledError = 'Cancelled';
|
||||
function isCancelledError(error) {
|
||||
return error === CancelledError;
|
||||
}
|
||||
exports.isCancelledError = isCancelledError;
|
||||
class CancellationToken {
|
||||
constructor() {
|
||||
this.listeners = [];
|
||||
this._cancelled = false;
|
||||
}
|
||||
get isCancelled() { return this._cancelled; }
|
||||
subscribe(fn) {
|
||||
this.listeners.push(fn);
|
||||
return () => {
|
||||
const index = this.listeners.indexOf(fn);
|
||||
if (index > -1) {
|
||||
this.listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
cancel() {
|
||||
const emit = !this._cancelled;
|
||||
this._cancelled = true;
|
||||
if (emit) {
|
||||
this.listeners.forEach(l => l(CancelledError));
|
||||
this.listeners = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.CancellationToken = CancellationToken;
|
||||
function sequence(promiseFactories) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
for (const factory of promiseFactories) {
|
||||
yield factory();
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.sequence = sequence;
|
||||
var LogMessageType;
|
||||
(function (LogMessageType) {
|
||||
LogMessageType[LogMessageType["DONE"] = 0] = "DONE";
|
||||
LogMessageType[LogMessageType["INFO"] = 1] = "INFO";
|
||||
LogMessageType[LogMessageType["WARNING"] = 2] = "WARNING";
|
||||
LogMessageType[LogMessageType["ERROR"] = 3] = "ERROR";
|
||||
})(LogMessageType || (LogMessageType = {}));
|
||||
const LogPrefix = {
|
||||
[LogMessageType.DONE]: chalk_1.default.bgGreen.black(' DONE '),
|
||||
[LogMessageType.INFO]: chalk_1.default.bgBlueBright.black(' INFO '),
|
||||
[LogMessageType.WARNING]: chalk_1.default.bgYellow.black(' WARNING '),
|
||||
[LogMessageType.ERROR]: chalk_1.default.bgRed.black(' ERROR '),
|
||||
};
|
||||
function _log(type, msg, ...args) {
|
||||
args = [LogPrefix[type], msg, ...args];
|
||||
if (type === LogMessageType.WARNING) {
|
||||
console.warn(...args);
|
||||
}
|
||||
else if (type === LogMessageType.ERROR) {
|
||||
console.error(...args);
|
||||
}
|
||||
else {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
exports.log = {
|
||||
done: _log.bind(null, LogMessageType.DONE),
|
||||
info: _log.bind(null, LogMessageType.INFO),
|
||||
warn: _log.bind(null, LogMessageType.WARNING),
|
||||
error: _log.bind(null, LogMessageType.ERROR)
|
||||
};
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const semver = require("semver");
|
||||
const parseSemver = require("parse-semver");
|
||||
const nameRegex = /^[a-z0-9][a-z0-9\-]*$/i;
|
||||
function validatePublisher(publisher) {
|
||||
if (!publisher) {
|
||||
throw new Error(`Missing publisher name. Learn more: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#publishing-extensions`);
|
||||
}
|
||||
if (!nameRegex.test(publisher)) {
|
||||
throw new Error(`Invalid publisher name '${publisher}'. Expected the identifier of a publisher, not its human-friendly name. Learn more: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#publishing-extensions`);
|
||||
}
|
||||
}
|
||||
exports.validatePublisher = validatePublisher;
|
||||
function validateExtensionName(name) {
|
||||
if (!name) {
|
||||
throw new Error(`Missing extension name`);
|
||||
}
|
||||
if (!nameRegex.test(name)) {
|
||||
throw new Error(`Invalid extension name '${name}'`);
|
||||
}
|
||||
}
|
||||
exports.validateExtensionName = validateExtensionName;
|
||||
function validateVersion(version) {
|
||||
if (!version) {
|
||||
throw new Error(`Missing extension version`);
|
||||
}
|
||||
if (!semver.valid(version)) {
|
||||
throw new Error(`Invalid extension version '${version}'`);
|
||||
}
|
||||
}
|
||||
exports.validateVersion = validateVersion;
|
||||
function validateEngineCompatibility(version) {
|
||||
if (!version) {
|
||||
throw new Error(`Missing vscode engine compatibility version`);
|
||||
}
|
||||
if (!/^\*$|^(\^|>=)?((\d+)|x)\.((\d+)|x)\.((\d+)|x)(\-.*)?$/.test(version)) {
|
||||
throw new Error(`Invalid vscode engine compatibility version '${version}'`);
|
||||
}
|
||||
}
|
||||
exports.validateEngineCompatibility = validateEngineCompatibility;
|
||||
/**
|
||||
* User shouldn't use a newer version of @types/vscode than the one specified in engines.vscode
|
||||
*/
|
||||
function validateVSCodeTypesCompatibility(engineVersion, typeVersion) {
|
||||
if (engineVersion === '*') {
|
||||
return;
|
||||
}
|
||||
if (!typeVersion) {
|
||||
throw new Error(`Missing @types/vscode version`);
|
||||
}
|
||||
let plainEngineVersion, plainTypeVersion;
|
||||
try {
|
||||
const engineSemver = parseSemver(`vscode@${engineVersion}`);
|
||||
plainEngineVersion = engineSemver.version;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error('Failed to parse semver of engines.vscode');
|
||||
}
|
||||
try {
|
||||
const typeSemver = parseSemver(`@types/vscode@${typeVersion}`);
|
||||
plainTypeVersion = typeSemver.version;
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error('Failed to parse semver of @types/vscode');
|
||||
}
|
||||
// For all `x`, use smallest version for comparison
|
||||
plainEngineVersion = plainEngineVersion.replace(/x/g, '0');
|
||||
const [typeMajor, typeMinor, typePatch] = plainTypeVersion.split('.').map(x => {
|
||||
try {
|
||||
return parseInt(x);
|
||||
}
|
||||
catch (err) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
const [engineMajor, engineMinor, enginePatch] = plainEngineVersion.split('.').map(x => {
|
||||
try {
|
||||
return parseInt(x);
|
||||
}
|
||||
catch (err) {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
const error = new Error(`@types/vscode ${typeVersion} greater than engines.vscode ${engineVersion}. Consider upgrade engines.vscode or use an older @types/vscode version`);
|
||||
if (typeof typeMajor === 'number' && typeof engineMajor === 'number' && typeMajor > engineMajor) {
|
||||
throw error;
|
||||
}
|
||||
if (typeof typeMinor === 'number' && typeof engineMinor === 'number' && typeMinor > engineMinor) {
|
||||
throw error;
|
||||
}
|
||||
if (typeof typePatch === 'number' && typeof enginePatch === 'number' && typePatch > enginePatch) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
exports.validateVSCodeTypesCompatibility = validateVSCodeTypesCompatibility;
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fixedLocale = 'en-us';
|
||||
const format = {
|
||||
date: { month: 'long', day: 'numeric', year: 'numeric' },
|
||||
time: { hour: 'numeric', minute: 'numeric', second: 'numeric' },
|
||||
};
|
||||
const columns = process.stdout.columns ? process.stdout.columns : 80;
|
||||
// xxx: Windows cmd + powershell standard fonts currently don't support the full
|
||||
// unicode charset. For now we use fallback icons when on windows.
|
||||
const useFallbackIcons = process.platform === 'win32';
|
||||
exports.icons = useFallbackIcons ?
|
||||
{
|
||||
download: '\u{2193}',
|
||||
star: '\u{2665}',
|
||||
emptyStar: '\u{2022}',
|
||||
} : {
|
||||
download: '\u{2913}',
|
||||
star: '\u{2605}',
|
||||
emptyStar: '\u{2606}',
|
||||
};
|
||||
function formatDate(date) { return date.toLocaleString(fixedLocale, format.date); }
|
||||
exports.formatDate = formatDate;
|
||||
function formatTime(date) { return date.toLocaleString(fixedLocale, format.time); }
|
||||
exports.formatTime = formatTime;
|
||||
function formatDateTime(date) { return date.toLocaleString(fixedLocale, Object.assign({}, format.date, format.time)); }
|
||||
exports.formatDateTime = formatDateTime;
|
||||
function repeatString(text, count) {
|
||||
let result = '';
|
||||
for (let i = 0; i < count; i++) {
|
||||
result += text;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
exports.repeatString = repeatString;
|
||||
function ratingStars(rating, total = 5) {
|
||||
const c = Math.min(Math.round(rating), total);
|
||||
return `${repeatString(exports.icons.star + ' ', c)}${repeatString(exports.icons.emptyStar + ' ', total - c)}`;
|
||||
}
|
||||
exports.ratingStars = ratingStars;
|
||||
function tableView(table, spacing = 2) {
|
||||
const maxLen = {};
|
||||
table.forEach(row => row.forEach((cell, i) => maxLen[i] = Math.max(maxLen[i] || 0, cell.length)));
|
||||
return table.map(row => row.map((cell, i) => `${cell}${repeatString(' ', maxLen[i] - cell.length + spacing)}`).join(''));
|
||||
}
|
||||
exports.tableView = tableView;
|
||||
function wordWrap(text, width = columns) {
|
||||
const [indent = ''] = text.match(/^\s+/) || [];
|
||||
const maxWidth = width - indent.length;
|
||||
return text
|
||||
.replace(/^\s+/, '')
|
||||
.split('')
|
||||
.reduce(([out, buffer, pos], ch, i) => {
|
||||
const nl = pos === maxWidth ? `\n${indent}` : '';
|
||||
const newPos = nl ? 0 : +pos + 1;
|
||||
return / |-|,|\./.test(ch) ?
|
||||
[`${out}${buffer}${ch}${nl}`, '', newPos] : [`${out}${nl}`, buffer + ch, newPos];
|
||||
}, [indent, '', 0])
|
||||
.slice(0, 2)
|
||||
.join('');
|
||||
}
|
||||
exports.wordWrap = wordWrap;
|
||||
;
|
||||
function indentRow(row) { return ` ${row}`; }
|
||||
exports.indentRow = indentRow;
|
||||
;
|
||||
function wordTrim(text, width = columns, indicator = '...') {
|
||||
if (text.length > width) {
|
||||
return text.substr(0, width - indicator.length) + indicator;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
exports.wordTrim = wordTrim;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
require('./main')(process.argv);
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "vsce",
|
||||
"version": "1.66.0",
|
||||
"description": "VSCode Extension Manager",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vsce"
|
||||
},
|
||||
"homepage": "https://code.visualstudio.com",
|
||||
"bugs": "https://github.com/Microsoft/vsce/issues",
|
||||
"keywords": [
|
||||
"vscode",
|
||||
"vsce",
|
||||
"extension"
|
||||
],
|
||||
"contributors": [
|
||||
"Microsoft Corporation"
|
||||
],
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"main": "out/api.js",
|
||||
"typings": "out/api.d.ts",
|
||||
"bin": {
|
||||
"vsce": "out/vsce"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc && cpx src/vsce out",
|
||||
"watch": "concurrently \"tsc --watch\" \"cpx --watch src/vsce out\"",
|
||||
"watch-test": "concurrently \"tsc --watch\" \"cpx --watch src/vsce out\" \"mocha --watch\"",
|
||||
"test": "mocha",
|
||||
"prepublishOnly": "tsc && cpx src/vsce out && mocha",
|
||||
"vsce": "out/vsce"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
},
|
||||
"dependencies": {
|
||||
"azure-devops-node-api": "^7.2.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cheerio": "^1.0.0-rc.1",
|
||||
"commander": "^2.8.1",
|
||||
"denodeify": "^1.2.1",
|
||||
"didyoumean": "^1.2.1",
|
||||
"glob": "^7.0.6",
|
||||
"lodash": "^4.17.10",
|
||||
"markdown-it": "^8.3.1",
|
||||
"mime": "^1.3.4",
|
||||
"minimatch": "^3.0.3",
|
||||
"osenv": "^0.1.3",
|
||||
"parse-semver": "^1.1.1",
|
||||
"read": "^1.0.7",
|
||||
"semver": "^5.1.0",
|
||||
"tmp": "0.0.29",
|
||||
"typed-rest-client": "1.2.0",
|
||||
"url-join": "^1.1.0",
|
||||
"yauzl": "^2.3.1",
|
||||
"yazl": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cheerio": "^0.22.1",
|
||||
"@types/denodeify": "^1.2.31",
|
||||
"@types/didyoumean": "^1.2.0",
|
||||
"@types/glob": "^7.1.1",
|
||||
"@types/lodash": "^4.14.123",
|
||||
"@types/markdown-it": "0.0.2",
|
||||
"@types/mime": "^1",
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@types/node": "^8",
|
||||
"@types/read": "^0.0.28",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/tmp": "^0.1.0",
|
||||
"@types/xml2js": "^0.4.4",
|
||||
"concurrently": "^4.1.0",
|
||||
"cpx": "^1.5.0",
|
||||
"mocha": "^5.2.0",
|
||||
"source-map-support": "^0.4.2",
|
||||
"typescript": "^3.4.3",
|
||||
"xml2js": "^0.4.12"
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
||||
<% _.forEach(contentTypes, function (e) { %><Default Extension="${ e.extension }" ContentType="${ e.contentType }"/><% }); %>
|
||||
</Types>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Language="en-US" Id="<%- id %>" Version="<%- version %>" Publisher="<%- publisher %>"/>
|
||||
<DisplayName><%- displayName %></DisplayName>
|
||||
<Description xml:space="preserve"><%- description %></Description>
|
||||
<Tags><%- tags %></Tags>
|
||||
<Categories><%- categories %></Categories>
|
||||
<GalleryFlags><%- flags %></GalleryFlags>
|
||||
<Badges><% _.forEach(badges, function (badge) { %><Badge Link="<%- badge.href %>" ImgUri="<%- badge.url %>" Description="<%- badge.description %>" /><% }); %></Badges>
|
||||
<Properties>
|
||||
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="<%- engine %>" />
|
||||
<Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="<%- extensionDependencies %>" />
|
||||
<Property Id="Microsoft.VisualStudio.Code.ExtensionPack" Value="<%- extensionPack %>" />
|
||||
<Property Id="Microsoft.VisualStudio.Code.LocalizedLanguages" Value="<%- localizedLanguages %>" />
|
||||
<% if (links.repository) { %>
|
||||
<Property Id="Microsoft.VisualStudio.Services.Links.Source" Value="<%- links.repository %>" />
|
||||
<Property Id="Microsoft.VisualStudio.Services.Links.Getstarted" Value="<%- links.repository %>" />
|
||||
<% if (links.github) { %>
|
||||
<Property Id="Microsoft.VisualStudio.Services.Links.GitHub" Value="<%- links.github %>" />
|
||||
<% } else { %>
|
||||
<Property Id="Microsoft.VisualStudio.Services.Links.Repository" Value="<%- links.repository %>" />
|
||||
<% } %>
|
||||
<% } %>
|
||||
<% if (links.bugs) { %><Property Id="Microsoft.VisualStudio.Services.Links.Support" Value="<%- links.bugs %>" /><% } %>
|
||||
<% if (links.homepage) { %><Property Id="Microsoft.VisualStudio.Services.Links.Learn" Value="<%- links.homepage %>" /><% } %>
|
||||
<% if (galleryBanner.color) { %><Property Id="Microsoft.VisualStudio.Services.Branding.Color" Value="<%- galleryBanner.color %>" /><% } %>
|
||||
<% if (galleryBanner.theme) { %><Property Id="Microsoft.VisualStudio.Services.Branding.Theme" Value="<%- galleryBanner.theme %>" /><% } %>
|
||||
<Property Id="Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown" Value="<%- githubMarkdown %>" />
|
||||
<% if (typeof enableMarketplaceQnA === 'boolean') { %><Property Id="Microsoft.VisualStudio.Services.EnableMarketplaceQnA" Value="<%- enableMarketplaceQnA %>" /><% } %>
|
||||
<% if (customerQnALink) { %><Property Id="Microsoft.VisualStudio.Services.CustomerQnALink" Value="<%- customerQnALink %>" /><% } %>
|
||||
</Properties>
|
||||
<% if (license) { %><License><%- license %></License><% } %>
|
||||
<% if (icon) { %><Icon><%- icon %></Icon><% } %>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>
|
||||
</Installation>
|
||||
<Dependencies/>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />
|
||||
<% _.forEach(assets, function (asset) { %><Asset Type="<%- asset.type %>" Path="<%- asset.path %>" Addressable="true" /><% }); %>
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
Reference in New Issue
Block a user