@vscode/vsce 3.9.3-1 → 3.9.3-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -8
- package/dist/vsce.d.ts +4 -0
- package/out/main.js +6 -2
- package/out/npm.js +4 -9
- package/out/oidc.js +125 -0
- package/out/package.js +139 -65
- package/out/packageSpec.js +49 -0
- package/out/publicgalleryapi.js +3 -1
- package/out/publish.js +52 -26
- package/out/secretLint.js +130 -57
- package/out/store.js +7 -2
- package/out/util.js +2 -4
- package/out/validation.js +3 -6
- package/package.json +11 -19
- package/out/typings/secret-lint-types.js +0 -878
package/README.md
CHANGED
|
@@ -15,14 +15,7 @@ Read the [**Documentation**](https://code.visualstudio.com/api/working-with-exte
|
|
|
15
15
|
|
|
16
16
|
### Linux
|
|
17
17
|
|
|
18
|
-
In order to save credentials safely, this project uses [`
|
|
19
|
-
|
|
20
|
-
Depending on your distribution, you will need to run the following command:
|
|
21
|
-
|
|
22
|
-
- Debian/Ubuntu: `sudo apt-get install libsecret-1-dev`
|
|
23
|
-
- Alpine: `apk add libsecret`
|
|
24
|
-
- Red Hat-based: `sudo yum install libsecret-devel`
|
|
25
|
-
- Arch Linux: `sudo pacman -S libsecret`
|
|
18
|
+
In order to save credentials safely, this project uses [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring), which uses the system Secret Service and falls back to the Linux kernel keyring. Setting the `VSCE_STORE=file` environment variable will revert back to the file credential store. Using the `VSCE_PAT` environment variable will also avoid using the system credential store.
|
|
26
19
|
|
|
27
20
|
## Usage
|
|
28
21
|
|
|
@@ -58,6 +51,31 @@ Or you can also set them in the `package.json`, so that you avoid having to rety
|
|
|
58
51
|
}
|
|
59
52
|
```
|
|
60
53
|
|
|
54
|
+
### Trusted publishing
|
|
55
|
+
|
|
56
|
+
`vsce publish --oidc` publishes from GitHub Actions without storing a Personal Access Token. Configure a trusted
|
|
57
|
+
publishing policy for the repository and workflow on the Visual Studio Marketplace, then grant the workflow permission
|
|
58
|
+
to request an OIDC token:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
jobs:
|
|
62
|
+
publish:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
contents: read
|
|
66
|
+
id-token: write
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v4
|
|
69
|
+
- uses: actions/setup-node@v4
|
|
70
|
+
with:
|
|
71
|
+
node-version: 22
|
|
72
|
+
- run: npm ci
|
|
73
|
+
- run: npx @vscode/vsce publish --oidc
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
OIDC publishing requests a GitHub Actions token for the `marketplace.visualstudio.com` audience and exchanges it for a
|
|
77
|
+
short-lived Marketplace credential. It does not fall back to a PAT when token acquisition or exchange fails.
|
|
78
|
+
|
|
61
79
|
## Development
|
|
62
80
|
|
|
63
81
|
First clone this repository, then:
|
package/dist/vsce.d.ts
CHANGED
|
@@ -174,6 +174,10 @@ export declare interface IPublishOptions {
|
|
|
174
174
|
*/
|
|
175
175
|
readonly pat?: string;
|
|
176
176
|
readonly azureCredential?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Use OpenID Connect trusted publishing to acquire a short-lived Marketplace credential.
|
|
179
|
+
*/
|
|
180
|
+
readonly oidc?: boolean;
|
|
177
181
|
readonly allowProposedApi?: boolean;
|
|
178
182
|
readonly noVerify?: boolean;
|
|
179
183
|
readonly allowProposedApis?: string[];
|
package/out/main.js
CHANGED
|
@@ -173,6 +173,9 @@ module.exports = function (argv) {
|
|
|
173
173
|
.description('Publishes an extension')
|
|
174
174
|
.option('-p, --pat <token>', 'Personal Access Token (defaults to VSCE_PAT environment variable)', process.env['VSCE_PAT'])
|
|
175
175
|
.option('--azure-credential', 'Use Microsoft Entra ID for authentication')
|
|
176
|
+
.addOption(new commander_1.Option('--oidc', 'Use OpenID Connect trusted publishing for authentication')
|
|
177
|
+
.conflicts(['pat', 'azureCredential'])
|
|
178
|
+
.hideHelp(true))
|
|
176
179
|
.option('-t, --target <targets...>', `Target architectures. Valid targets: ${ValidTargets}`)
|
|
177
180
|
.option('--ignore-other-target-folders', `Ignore other target folders. Valid only when --target <target> is provided.`)
|
|
178
181
|
.option('--readme-path <path>', 'Path to README file (defaults to README.md)')
|
|
@@ -209,9 +212,10 @@ module.exports = function (argv) {
|
|
|
209
212
|
.option('--skip-duplicate', 'Fail silently if version already exists on the marketplace')
|
|
210
213
|
.option('--skip-license', 'Allow publishing without license file')
|
|
211
214
|
.option('--follow-symlinks', 'Recurse into symlinked directories instead of treating them as files')
|
|
212
|
-
.action((version, { pat, azureCredential, target, ignoreOtherTargetFolders, readmePath, changelogPath, message, gitTagVersion, updatePackageJson, packagePath, manifestPath, signaturePath, sigzipPath, githubBranch, gitlabBranch, baseContentUrl, baseImagesUrl, yarn, verify, noVerify, allowProposedApis, allowAllProposedApis, allowPackageSecrets, allowPackageAllSecrets, allowPackageEnvFile, ignoreFile, dependencies, preRelease, allowStarActivation, allowMissingRepository, allowUnusedFilesPattern, skipDuplicate, skipLicense, signTool, followSymlinks, }) => main((0, publish_1.publish)({
|
|
213
|
-
pat,
|
|
215
|
+
.action((version, { pat, azureCredential, oidc, target, ignoreOtherTargetFolders, readmePath, changelogPath, message, gitTagVersion, updatePackageJson, packagePath, manifestPath, signaturePath, sigzipPath, githubBranch, gitlabBranch, baseContentUrl, baseImagesUrl, yarn, verify, noVerify, allowProposedApis, allowAllProposedApis, allowPackageSecrets, allowPackageAllSecrets, allowPackageEnvFile, ignoreFile, dependencies, preRelease, allowStarActivation, allowMissingRepository, allowUnusedFilesPattern, skipDuplicate, skipLicense, signTool, followSymlinks, }) => main((0, publish_1.publish)({
|
|
216
|
+
pat: oidc ? undefined : pat,
|
|
214
217
|
azureCredential,
|
|
218
|
+
oidc,
|
|
215
219
|
version,
|
|
216
220
|
targets: target,
|
|
217
221
|
ignoreOtherTargetFolders,
|
package/out/npm.js
CHANGED
|
@@ -32,9 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.detectYarn = detectYarn;
|
|
40
37
|
exports.getDependencies = getDependencies;
|
|
@@ -42,8 +39,8 @@ exports.getLatestVersion = getLatestVersion;
|
|
|
42
39
|
const path = __importStar(require("path"));
|
|
43
40
|
const fs = __importStar(require("fs"));
|
|
44
41
|
const cp = __importStar(require("child_process"));
|
|
45
|
-
const parse_semver_1 = __importDefault(require("parse-semver"));
|
|
46
42
|
const util_1 = require("./util");
|
|
43
|
+
const packageSpec_1 = require("./packageSpec");
|
|
47
44
|
const exists = (file) => fs.promises.stat(file).then(_ => true, _ => false);
|
|
48
45
|
function parseStdout({ stdout }) {
|
|
49
46
|
return stdout.split(/[\r\n]/).filter(line => !!line)[0];
|
|
@@ -87,7 +84,7 @@ function asYarnDependency(prefix, tree, prune) {
|
|
|
87
84
|
}
|
|
88
85
|
let name;
|
|
89
86
|
try {
|
|
90
|
-
const parseResult = (0,
|
|
87
|
+
const parseResult = (0, packageSpec_1.parsePackageSpec)(tree.name);
|
|
91
88
|
name = parseResult.name;
|
|
92
89
|
}
|
|
93
90
|
catch (err) {
|
|
@@ -105,8 +102,8 @@ function asYarnDependency(prefix, tree, prune) {
|
|
|
105
102
|
}
|
|
106
103
|
function selectYarnDependencies(deps, packagedDependencies) {
|
|
107
104
|
const index = new (class {
|
|
105
|
+
data = Object.create(null);
|
|
108
106
|
constructor() {
|
|
109
|
-
this.data = Object.create(null);
|
|
110
107
|
for (const dep of deps) {
|
|
111
108
|
if (this.data[dep.name]) {
|
|
112
109
|
throw Error(`Dependency seen more than once: ${dep.name}`);
|
|
@@ -123,9 +120,7 @@ function selectYarnDependencies(deps, packagedDependencies) {
|
|
|
123
120
|
}
|
|
124
121
|
})();
|
|
125
122
|
const reached = new (class {
|
|
126
|
-
|
|
127
|
-
this.values = [];
|
|
128
|
-
}
|
|
123
|
+
values = [];
|
|
129
124
|
add(dep) {
|
|
130
125
|
if (this.values.indexOf(dep) < 0) {
|
|
131
126
|
this.values.push(dep);
|
package/out/oidc.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OIDC_AUDIENCE = void 0;
|
|
4
|
+
exports.getOIDCCredential = getOIDCCredential;
|
|
5
|
+
const util_1 = require("./util");
|
|
6
|
+
exports.OIDC_AUDIENCE = 'marketplace.visualstudio.com';
|
|
7
|
+
class GitHubActionsOIDCTokenProvider {
|
|
8
|
+
name = 'GitHub Actions';
|
|
9
|
+
isAvailable(environment) {
|
|
10
|
+
return environment['GITHUB_ACTIONS']?.toLowerCase() === 'true';
|
|
11
|
+
}
|
|
12
|
+
async getToken(audience, { environment, request }) {
|
|
13
|
+
const requestUrl = environment['ACTIONS_ID_TOKEN_REQUEST_URL'];
|
|
14
|
+
const requestToken = environment['ACTIONS_ID_TOKEN_REQUEST_TOKEN'];
|
|
15
|
+
if (!requestUrl || !requestToken) {
|
|
16
|
+
throw new Error('GitHub Actions did not provide an OIDC token request URL and token. Add `permissions: id-token: write` to the workflow or job.');
|
|
17
|
+
}
|
|
18
|
+
let tokenUrl;
|
|
19
|
+
try {
|
|
20
|
+
tokenUrl = new URL(requestUrl);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error('GitHub Actions provided an invalid ACTIONS_ID_TOKEN_REQUEST_URL.');
|
|
24
|
+
}
|
|
25
|
+
tokenUrl.searchParams.set('audience', audience);
|
|
26
|
+
const result = await requestJSON('GitHub Actions OIDC token request', tokenUrl.toString(), request, {
|
|
27
|
+
method: 'GET',
|
|
28
|
+
headers: {
|
|
29
|
+
Accept: 'application/json',
|
|
30
|
+
Authorization: `Bearer ${requestToken}`,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
if (!isRecord(result) || typeof result.value !== 'string' || !result.value) {
|
|
34
|
+
throw new Error('GitHub Actions OIDC token request returned an invalid response without a token.');
|
|
35
|
+
}
|
|
36
|
+
return result.value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const oidcTokenProviders = [new GitHubActionsOIDCTokenProvider()];
|
|
40
|
+
async function getOIDCCredential(publisherName, options = {}) {
|
|
41
|
+
const environment = options.environment ?? process.env;
|
|
42
|
+
const request = options.request ?? defaultRequest;
|
|
43
|
+
const provider = oidcTokenProviders.find(candidate => candidate.isAvailable(environment));
|
|
44
|
+
if (!provider) {
|
|
45
|
+
throw new Error('No supported OIDC provider was detected. OIDC publishing currently supports GitHub Actions only.');
|
|
46
|
+
}
|
|
47
|
+
const oidcToken = await provider.getToken(exports.OIDC_AUDIENCE, { environment, request });
|
|
48
|
+
return await exchangeOIDCToken(publisherName, oidcToken, options.marketplaceUrl ?? (0, util_1.getMarketplaceUrl)(), request);
|
|
49
|
+
}
|
|
50
|
+
async function exchangeOIDCToken(publisherName, oidcToken, marketplaceUrl, request) {
|
|
51
|
+
const result = await requestJSON('Marketplace OIDC token exchange', `${marketplaceUrl.replace(/\/$/, '')}/_apis/gallery/token`, request, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
Accept: 'application/json',
|
|
55
|
+
Authorization: `Bearer ${oidcToken}`,
|
|
56
|
+
'Content-Type': 'application/json',
|
|
57
|
+
'User-Agent': 'vsce',
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ publisherName }),
|
|
60
|
+
});
|
|
61
|
+
if (!isRecord(result) || typeof result.credential !== 'string' || !result.credential) {
|
|
62
|
+
throw new Error('Marketplace OIDC token exchange returned an invalid response without a credential.');
|
|
63
|
+
}
|
|
64
|
+
return result.credential;
|
|
65
|
+
}
|
|
66
|
+
async function defaultRequest(url, request) {
|
|
67
|
+
const response = await fetch(url, request);
|
|
68
|
+
return {
|
|
69
|
+
statusCode: response.status,
|
|
70
|
+
statusMessage: response.statusText,
|
|
71
|
+
readBody: () => response.text(),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function requestJSON(operation, url, request, init) {
|
|
75
|
+
let response;
|
|
76
|
+
try {
|
|
77
|
+
response = await request(url, init);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new Error(`${operation} failed: ${getErrorMessage(error)}`);
|
|
81
|
+
}
|
|
82
|
+
let body;
|
|
83
|
+
try {
|
|
84
|
+
body = await response.readBody();
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw new Error(`${operation} failed while reading the response: ${getErrorMessage(error)}`);
|
|
88
|
+
}
|
|
89
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
90
|
+
const status = `${response.statusCode}${response.statusMessage ? ` ${response.statusMessage}` : ''}`;
|
|
91
|
+
throw new Error(`${operation} failed with ${status}${getResponseDetails(body)}`);
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(body);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
throw new Error(`${operation} returned an invalid JSON response.`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function getResponseDetails(body) {
|
|
101
|
+
const trimmedBody = body.trim();
|
|
102
|
+
if (!trimmedBody) {
|
|
103
|
+
return '.';
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(trimmedBody);
|
|
107
|
+
if (isRecord(parsed)) {
|
|
108
|
+
const message = parsed.message ?? parsed.error_description ?? parsed.error;
|
|
109
|
+
if (typeof message === 'string' && message) {
|
|
110
|
+
return `: ${message}`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Use the plain response body below.
|
|
116
|
+
}
|
|
117
|
+
return `: ${trimmedBody.slice(0, 500)}`;
|
|
118
|
+
}
|
|
119
|
+
function getErrorMessage(error) {
|
|
120
|
+
return error instanceof Error ? error.message : String(error);
|
|
121
|
+
}
|
|
122
|
+
function isRecord(value) {
|
|
123
|
+
return typeof value === 'object' && value !== null;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=oidc.js.map
|
package/out/package.js
CHANGED
|
@@ -65,10 +65,10 @@ const cp = __importStar(require("child_process"));
|
|
|
65
65
|
const yazl = __importStar(require("yazl"));
|
|
66
66
|
const nls_1 = require("./nls");
|
|
67
67
|
const util = __importStar(require("./util"));
|
|
68
|
-
const
|
|
68
|
+
const tinyglobby_1 = require("tinyglobby");
|
|
69
69
|
const minimatch_1 = require("minimatch");
|
|
70
|
-
const
|
|
71
|
-
const
|
|
70
|
+
const parse5_1 = require("parse5");
|
|
71
|
+
const marked_1 = require("marked");
|
|
72
72
|
const url = __importStar(require("url"));
|
|
73
73
|
const mime_1 = __importDefault(require("mime"));
|
|
74
74
|
const semver = __importStar(require("semver"));
|
|
@@ -77,10 +77,10 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
77
77
|
const validation_1 = require("./validation");
|
|
78
78
|
const npm_1 = require("./npm");
|
|
79
79
|
const GitHost = __importStar(require("hosted-git-info"));
|
|
80
|
-
const parse_semver_1 = __importDefault(require("parse-semver"));
|
|
81
80
|
const jsonc = __importStar(require("jsonc-parser"));
|
|
82
81
|
const vsceSign = __importStar(require("@vscode/vsce-sign"));
|
|
83
82
|
const secretLint_1 = require("./secretLint");
|
|
83
|
+
const packageSpec_1 = require("./packageSpec");
|
|
84
84
|
const minimatchOptions = { dot: true };
|
|
85
85
|
function isInMemoryFile(file) {
|
|
86
86
|
return !!file.contents;
|
|
@@ -94,12 +94,13 @@ function read(file) {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
class BaseProcessor {
|
|
97
|
+
manifest;
|
|
97
98
|
constructor(manifest) {
|
|
98
99
|
this.manifest = manifest;
|
|
99
|
-
this.assets = [];
|
|
100
|
-
this.tags = [];
|
|
101
|
-
this.vsix = Object.create(null);
|
|
102
100
|
}
|
|
101
|
+
assets = [];
|
|
102
|
+
tags = [];
|
|
103
|
+
vsix = Object.create(null);
|
|
103
104
|
async onFile(file) {
|
|
104
105
|
return file;
|
|
105
106
|
}
|
|
@@ -299,6 +300,7 @@ exports.Targets = new Set([
|
|
|
299
300
|
'web',
|
|
300
301
|
]);
|
|
301
302
|
class ManifestProcessor extends BaseProcessor {
|
|
303
|
+
options;
|
|
302
304
|
constructor(manifest, options = {}) {
|
|
303
305
|
super(manifest);
|
|
304
306
|
this.options = options;
|
|
@@ -326,7 +328,7 @@ class ManifestProcessor extends BaseProcessor {
|
|
|
326
328
|
if (target || preRelease) {
|
|
327
329
|
let engineSemver;
|
|
328
330
|
try {
|
|
329
|
-
engineSemver = (0,
|
|
331
|
+
engineSemver = (0, packageSpec_1.parsePackageSpec)(`vscode@${manifest.engines.vscode}`);
|
|
330
332
|
}
|
|
331
333
|
catch (err) {
|
|
332
334
|
throw new Error('Failed to parse semver of engines.vscode');
|
|
@@ -430,6 +432,44 @@ class ManifestProcessor extends BaseProcessor {
|
|
|
430
432
|
}
|
|
431
433
|
exports.ManifestProcessor = ManifestProcessor;
|
|
432
434
|
class TagsProcessor extends BaseProcessor {
|
|
435
|
+
static Keywords = {
|
|
436
|
+
git: ['git'],
|
|
437
|
+
npm: ['node'],
|
|
438
|
+
spell: ['markdown'],
|
|
439
|
+
bootstrap: ['bootstrap'],
|
|
440
|
+
lint: ['linters'],
|
|
441
|
+
linting: ['linters'],
|
|
442
|
+
react: ['javascript'],
|
|
443
|
+
js: ['javascript'],
|
|
444
|
+
node: ['javascript', 'node'],
|
|
445
|
+
'c++': ['c++'],
|
|
446
|
+
Cplusplus: ['c++'],
|
|
447
|
+
xml: ['xml'],
|
|
448
|
+
angular: ['javascript'],
|
|
449
|
+
jquery: ['javascript'],
|
|
450
|
+
php: ['php'],
|
|
451
|
+
python: ['python'],
|
|
452
|
+
latex: ['latex'],
|
|
453
|
+
ruby: ['ruby'],
|
|
454
|
+
java: ['java'],
|
|
455
|
+
erlang: ['erlang'],
|
|
456
|
+
sql: ['sql'],
|
|
457
|
+
nodejs: ['node'],
|
|
458
|
+
'c#': ['c#'],
|
|
459
|
+
css: ['css'],
|
|
460
|
+
javascript: ['javascript'],
|
|
461
|
+
ftp: ['ftp'],
|
|
462
|
+
haskell: ['haskell'],
|
|
463
|
+
unity: ['unity'],
|
|
464
|
+
terminal: ['terminal'],
|
|
465
|
+
powershell: ['powershell'],
|
|
466
|
+
laravel: ['laravel'],
|
|
467
|
+
meteor: ['meteor'],
|
|
468
|
+
emmet: ['emmet'],
|
|
469
|
+
eslint: ['linters'],
|
|
470
|
+
tfs: ['tfs'],
|
|
471
|
+
rust: ['rust'],
|
|
472
|
+
};
|
|
433
473
|
async onEnd() {
|
|
434
474
|
const keywords = this.manifest.keywords ?? [];
|
|
435
475
|
const contributes = this.manifest.contributes;
|
|
@@ -493,51 +533,25 @@ class TagsProcessor extends BaseProcessor {
|
|
|
493
533
|
}
|
|
494
534
|
}
|
|
495
535
|
exports.TagsProcessor = TagsProcessor;
|
|
496
|
-
TagsProcessor.Keywords = {
|
|
497
|
-
git: ['git'],
|
|
498
|
-
npm: ['node'],
|
|
499
|
-
spell: ['markdown'],
|
|
500
|
-
bootstrap: ['bootstrap'],
|
|
501
|
-
lint: ['linters'],
|
|
502
|
-
linting: ['linters'],
|
|
503
|
-
react: ['javascript'],
|
|
504
|
-
js: ['javascript'],
|
|
505
|
-
node: ['javascript', 'node'],
|
|
506
|
-
'c++': ['c++'],
|
|
507
|
-
Cplusplus: ['c++'],
|
|
508
|
-
xml: ['xml'],
|
|
509
|
-
angular: ['javascript'],
|
|
510
|
-
jquery: ['javascript'],
|
|
511
|
-
php: ['php'],
|
|
512
|
-
python: ['python'],
|
|
513
|
-
latex: ['latex'],
|
|
514
|
-
ruby: ['ruby'],
|
|
515
|
-
java: ['java'],
|
|
516
|
-
erlang: ['erlang'],
|
|
517
|
-
sql: ['sql'],
|
|
518
|
-
nodejs: ['node'],
|
|
519
|
-
'c#': ['c#'],
|
|
520
|
-
css: ['css'],
|
|
521
|
-
javascript: ['javascript'],
|
|
522
|
-
ftp: ['ftp'],
|
|
523
|
-
haskell: ['haskell'],
|
|
524
|
-
unity: ['unity'],
|
|
525
|
-
terminal: ['terminal'],
|
|
526
|
-
powershell: ['powershell'],
|
|
527
|
-
laravel: ['laravel'],
|
|
528
|
-
meteor: ['meteor'],
|
|
529
|
-
emmet: ['emmet'],
|
|
530
|
-
eslint: ['linters'],
|
|
531
|
-
tfs: ['tfs'],
|
|
532
|
-
rust: ['rust'],
|
|
533
|
-
};
|
|
534
536
|
class MarkdownProcessor extends BaseProcessor {
|
|
537
|
+
name;
|
|
538
|
+
assetType;
|
|
539
|
+
options;
|
|
540
|
+
regexp;
|
|
541
|
+
baseContentUrl;
|
|
542
|
+
baseImagesUrl;
|
|
543
|
+
rewriteRelativeLinks;
|
|
544
|
+
isGitHub;
|
|
545
|
+
isGitLab;
|
|
546
|
+
repositoryUrl;
|
|
547
|
+
gitHubIssueLinking;
|
|
548
|
+
gitLabIssueLinking;
|
|
549
|
+
filesProcessed = 0;
|
|
535
550
|
constructor(manifest, name, filePath, assetType, options = {}) {
|
|
536
551
|
super(manifest);
|
|
537
552
|
this.name = name;
|
|
538
553
|
this.assetType = assetType;
|
|
539
554
|
this.options = options;
|
|
540
|
-
this.filesProcessed = 0;
|
|
541
555
|
this.regexp = new RegExp(`^${util.filePathToVsixPath(filePath)}$`, 'i');
|
|
542
556
|
const guess = this.guessBaseUrls(options.githubBranch || options.gitlabBranch);
|
|
543
557
|
this.baseContentUrl = options.baseContentUrl || (guess && guess.content);
|
|
@@ -627,11 +641,33 @@ class MarkdownProcessor extends BaseProcessor {
|
|
|
627
641
|
contents = contents.replace(markdownIssueRegex, issueReplace);
|
|
628
642
|
}
|
|
629
643
|
}
|
|
630
|
-
const html = (
|
|
631
|
-
const
|
|
644
|
+
const html = marked_1.marked.parse(contents, { async: false });
|
|
645
|
+
const document = (0, parse5_1.parse)(html);
|
|
646
|
+
const images = [];
|
|
647
|
+
let hasSvg = false;
|
|
648
|
+
const nodes = [document];
|
|
649
|
+
while (nodes.length > 0) {
|
|
650
|
+
const node = nodes.pop();
|
|
651
|
+
if ('tagName' in node) {
|
|
652
|
+
if (node.tagName === 'img') {
|
|
653
|
+
images.push(node);
|
|
654
|
+
}
|
|
655
|
+
else if (node.tagName === 'svg') {
|
|
656
|
+
hasSvg = true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
const children = 'content' in node
|
|
660
|
+
? node.content.childNodes
|
|
661
|
+
: 'childNodes' in node
|
|
662
|
+
? node.childNodes
|
|
663
|
+
: [];
|
|
664
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
665
|
+
nodes.push(children[index]);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
632
668
|
if (this.rewriteRelativeLinks) {
|
|
633
|
-
|
|
634
|
-
const rawSrc =
|
|
669
|
+
for (const image of images) {
|
|
670
|
+
const rawSrc = image.attrs.find(attribute => attribute.name === 'src')?.value;
|
|
635
671
|
if (!rawSrc) {
|
|
636
672
|
throw new Error(`Images in ${this.name} must have a source.`);
|
|
637
673
|
}
|
|
@@ -652,11 +688,11 @@ class MarkdownProcessor extends BaseProcessor {
|
|
|
652
688
|
if (/\.svg$/i.test(srcUrl.pathname) && !isHostTrusted(srcUrl)) {
|
|
653
689
|
throw new Error(`SVGs are restricted in ${this.name}; please use other file image formats, such as PNG: ${src}`);
|
|
654
690
|
}
|
|
655
|
-
}
|
|
691
|
+
}
|
|
656
692
|
}
|
|
657
|
-
|
|
693
|
+
if (hasSvg) {
|
|
658
694
|
throw new Error(`SVG tags are not allowed in ${this.name}.`);
|
|
659
|
-
}
|
|
695
|
+
}
|
|
660
696
|
return {
|
|
661
697
|
path: file.path,
|
|
662
698
|
contents: Buffer.from(contents, 'utf8'),
|
|
@@ -734,10 +770,13 @@ class ChangelogProcessor extends MarkdownProcessor {
|
|
|
734
770
|
}
|
|
735
771
|
exports.ChangelogProcessor = ChangelogProcessor;
|
|
736
772
|
class LicenseProcessor extends BaseProcessor {
|
|
773
|
+
options;
|
|
774
|
+
didFindLicense = false;
|
|
775
|
+
expectedLicenseName;
|
|
776
|
+
filter;
|
|
737
777
|
constructor(manifest, options = {}) {
|
|
738
778
|
super(manifest);
|
|
739
779
|
this.options = options;
|
|
740
|
-
this.didFindLicense = false;
|
|
741
780
|
const match = /^SEE LICENSE IN (.*)$/.exec(manifest.license || '');
|
|
742
781
|
if (!match || !match[1]) {
|
|
743
782
|
this.expectedLicenseName = 'LICENSE, LICENSE.md, or LICENSE.txt';
|
|
@@ -776,9 +815,9 @@ class LicenseProcessor extends BaseProcessor {
|
|
|
776
815
|
}
|
|
777
816
|
exports.LicenseProcessor = LicenseProcessor;
|
|
778
817
|
class LaunchEntryPointProcessor extends BaseProcessor {
|
|
818
|
+
seenFiles = new Set();
|
|
779
819
|
constructor(manifest) {
|
|
780
820
|
super(manifest);
|
|
781
|
-
this.seenFiles = new Set();
|
|
782
821
|
}
|
|
783
822
|
onFile(file) {
|
|
784
823
|
this.seenFiles.add(util.normalize(file.path));
|
|
@@ -811,9 +850,10 @@ class LaunchEntryPointProcessor extends BaseProcessor {
|
|
|
811
850
|
}
|
|
812
851
|
}
|
|
813
852
|
class IconProcessor extends BaseProcessor {
|
|
853
|
+
icon;
|
|
854
|
+
didFindIcon = false;
|
|
814
855
|
constructor(manifest) {
|
|
815
856
|
super(manifest);
|
|
816
|
-
this.didFindIcon = false;
|
|
817
857
|
this.icon = manifest.icon && path.posix.normalize(util.filePathToVsixPath(manifest.icon));
|
|
818
858
|
delete this.vsix.icon;
|
|
819
859
|
}
|
|
@@ -893,9 +933,9 @@ function deduceExtensionKinds(manifest) {
|
|
|
893
933
|
return result;
|
|
894
934
|
}
|
|
895
935
|
class NLSProcessor extends BaseProcessor {
|
|
936
|
+
translations = Object.create(null);
|
|
896
937
|
constructor(manifest) {
|
|
897
938
|
super(manifest);
|
|
898
|
-
this.translations = Object.create(null);
|
|
899
939
|
if (!manifest.contributes ||
|
|
900
940
|
!manifest.contributes.localizations ||
|
|
901
941
|
manifest.contributes.localizations.length === 0) {
|
|
@@ -928,11 +968,8 @@ class NLSProcessor extends BaseProcessor {
|
|
|
928
968
|
}
|
|
929
969
|
exports.NLSProcessor = NLSProcessor;
|
|
930
970
|
class ValidationProcessor extends BaseProcessor {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
this.files = new Map();
|
|
934
|
-
this.duplicates = new Set();
|
|
935
|
-
}
|
|
971
|
+
files = new Map();
|
|
972
|
+
duplicates = new Set();
|
|
936
973
|
async onFile(file) {
|
|
937
974
|
const lower = file.path.toLowerCase();
|
|
938
975
|
const existing = this.files.get(lower);
|
|
@@ -984,7 +1021,7 @@ function validateManifestForPackaging(manifest) {
|
|
|
984
1021
|
const hasBrowser = !!manifest.browser;
|
|
985
1022
|
let parsedEngineVersion;
|
|
986
1023
|
try {
|
|
987
|
-
const engineSemver = (0,
|
|
1024
|
+
const engineSemver = (0, packageSpec_1.parsePackageSpec)(`vscode@${engines.vscode}`);
|
|
988
1025
|
parsedEngineVersion = engineSemver.version;
|
|
989
1026
|
}
|
|
990
1027
|
catch (err) {
|
|
@@ -1248,9 +1285,46 @@ const defaultIgnore = [
|
|
|
1248
1285
|
'**/.vscode-test/**',
|
|
1249
1286
|
'**/.vscode-test-web/**',
|
|
1250
1287
|
];
|
|
1288
|
+
/**
|
|
1289
|
+
* `tinyglobby` skips symbolic links altogether when `followSymbolicLinks` is disabled, while
|
|
1290
|
+
* vsce treats them as regular files instead (see the `--follow-symlinks` option). Presenting
|
|
1291
|
+
* symbolic links to the crawler as regular files keeps them in the result without recursing
|
|
1292
|
+
* into symlinked directories.
|
|
1293
|
+
*/
|
|
1294
|
+
const symlinksAsFilesFileSystem = {
|
|
1295
|
+
readdir: (dir, options, callback) => fs.readdir(dir, options, (err, entries) => callback(err, err ? entries : entries.map(asFile))),
|
|
1296
|
+
readdirSync: (dir, options) => fs.readdirSync(dir, options).map(asFile),
|
|
1297
|
+
};
|
|
1298
|
+
function asFile(entry) {
|
|
1299
|
+
if (!entry.isSymbolicLink()) {
|
|
1300
|
+
return entry;
|
|
1301
|
+
}
|
|
1302
|
+
return Object.create(entry, {
|
|
1303
|
+
isFile: { value: () => true },
|
|
1304
|
+
isDirectory: { value: () => false },
|
|
1305
|
+
isSymbolicLink: { value: () => false },
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* `glob` matched patterns case-insensitively on Windows and macOS and case-sensitively
|
|
1310
|
+
* everywhere else, based on `process.platform` rather than on the actual filesystem.
|
|
1311
|
+
* `tinyglobby` always matches case-sensitively, so this keeps the previous behaviour, which
|
|
1312
|
+
* matters for the `node_modules` folder being ignored regardless of how it is cased on disk.
|
|
1313
|
+
* Keep this keyed off the platform: probing the filesystem instead would change what is
|
|
1314
|
+
* packaged on case-sensitive macOS volumes and case-insensitive Linux mounts.
|
|
1315
|
+
*/
|
|
1316
|
+
const caseSensitiveMatch = process.platform !== 'win32' && process.platform !== 'darwin';
|
|
1251
1317
|
async function collectAllFiles(cwd, dependencies, dependencyEntryPoints, followSymlinks = true) {
|
|
1252
1318
|
const deps = await (0, npm_1.getDependencies)(cwd, dependencies, dependencyEntryPoints);
|
|
1253
|
-
const promises = deps.map(dep => (0,
|
|
1319
|
+
const promises = deps.map(dep => (0, tinyglobby_1.glob)('**', {
|
|
1320
|
+
cwd: dep,
|
|
1321
|
+
onlyFiles: true,
|
|
1322
|
+
followSymbolicLinks: followSymlinks,
|
|
1323
|
+
fs: followSymlinks ? undefined : symlinksAsFilesFileSystem,
|
|
1324
|
+
caseSensitiveMatch,
|
|
1325
|
+
dot: true,
|
|
1326
|
+
ignore: ['node_modules/**'],
|
|
1327
|
+
}).then(files => files.map(f => path.relative(cwd, path.join(dep, f))).map(f => f.replace(/\\/g, '/'))));
|
|
1254
1328
|
return Promise.all(promises).then(util.flatten);
|
|
1255
1329
|
}
|
|
1256
1330
|
function getDependenciesOption(options) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parsePackageSpec = parsePackageSpec;
|
|
37
|
+
const semver = __importStar(require("semver"));
|
|
38
|
+
function parsePackageSpec(value) {
|
|
39
|
+
const separator = value.indexOf('@', value.startsWith('@') ? 1 : 0);
|
|
40
|
+
const name = separator === -1 ? value : value.slice(0, separator);
|
|
41
|
+
const originalVersion = separator === -1 ? '' : value.slice(separator + 1);
|
|
42
|
+
const range = semver.validRange(originalVersion);
|
|
43
|
+
if (originalVersion && !range) {
|
|
44
|
+
throw new Error(`Invalid semver range: ${originalVersion}`);
|
|
45
|
+
}
|
|
46
|
+
const version = originalVersion.replace(/^[^0-9]+/, '') || 'latest';
|
|
47
|
+
return { name, range: range ?? '*', version };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=packageSpec.js.map
|
package/out/publicgalleryapi.js
CHANGED
|
@@ -5,10 +5,12 @@ const HttpClient_1 = require("typed-rest-client/HttpClient");
|
|
|
5
5
|
const GalleryInterfaces_1 = require("azure-devops-node-api/interfaces/GalleryInterfaces");
|
|
6
6
|
const Serialization_1 = require("azure-devops-node-api/Serialization");
|
|
7
7
|
class PublicGalleryAPI {
|
|
8
|
+
baseUrl;
|
|
9
|
+
apiVersion;
|
|
10
|
+
client = new HttpClient_1.HttpClient('vsce');
|
|
8
11
|
constructor(baseUrl, apiVersion = '3.0-preview.1') {
|
|
9
12
|
this.baseUrl = baseUrl;
|
|
10
13
|
this.apiVersion = apiVersion;
|
|
11
|
-
this.client = new HttpClient_1.HttpClient('vsce');
|
|
12
14
|
}
|
|
13
15
|
post(url, data, additionalHeaders) {
|
|
14
16
|
return this.client.post(`${this.baseUrl}/_apis/public${url}`, data, additionalHeaders);
|