diff --git a/README.md b/README.md
index e8a9fdb4..a7502a97 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,8 @@ This action deletes versions of a package from [GitHub Packages](https://github.
* Delete all package versions except n most recent versions
* Delete oldest version(s)
* Ignore version(s) from deletion through regex
-* Delete version(s) of a package that is hosted from a repo having access to package
-* Delete version(s) of a package that is hosted from a repo not having access to package
+* Delete version(s) of packages that are hosted in the same repo that is executing the workflow
+* Delete version(s) of packages that are hosted in a different repo than the one executing the workflow
* Delete a single version
* Delete multiple versions
* Delete specific version(s)
@@ -28,13 +28,24 @@ This action deletes versions of a package from [GitHub Packages](https://github.
# Required if deleting a version from a package hosted in a different org than the one executing the workflow.
owner:
- # Name of the package.
- # Required
- package-name:
-
# Type of the package. Can be one of container, maven, npm, nuget, or rubygems.
# Required
package-type:
+
+ # Defaults to an empty string.
+ # Required if `package-version-ids` or `package-names` input is not given.
+ package-name:
+
+ # Names of the package.
+ # Can be one of the following:
+ # - a single package name
+ # - a group of packages that matches a wildcard at start, end, both sides, or all packages (e.g. "package*")
+ # - a group of packages that matches a regex, must start with slash at the beginning and end (e.g. "/package.*/")
+ # - a comma separated list of the previous cases (e.g. "package-lorem, *-ipsum, /.*dolor/")
+ # Defaults to an empty string.
+ # Required if `package-version-ids` or `package-name` input is not given.
+ package-names:
+
# The number of old versions to delete starting from the oldest version.
# Defaults to 1.
@@ -75,7 +86,7 @@ This action deletes versions of a package from [GitHub Packages](https://github.
# Valid Input Combinations
-`owner`, `package-name`, `package-type` and `token` can be used with the following combinations in a workflow -
+`owner`, `repo`, `package-name` (or `package-names`) and `token` can be used with the following combinations in a workflow -
- `num-old-versions-to-delete`
- `min-versions-to-keep`
@@ -104,6 +115,7 @@ This action deletes versions of a package from [GitHub Packages](https://github.
- [License](#license)
+
### Delete all pre-release versions except y latest pre-release package versions
To delete all pre release versions except y latest pre-release package versions, the __package-name__, __min-versions-to-keep__ and __delete-only-pre-release-versions__ inputs are required.
@@ -272,6 +284,41 @@ This action deletes versions of a package from [GitHub Packages](https://github.
+ ### Delete all except y latest versions of a package
+
+ To delete all except y latest versions of all packages hosted in the same repo as the workflow the __package-names__ and __min-versions-to-keep__ inputs are required.
+
+ __Example__
+
+ Delete all except latest 2 versions of a package hosted in the same repo as the workflow
+
+ ```yaml
+ - uses: actions/delete-package-versions@v3
+ with:
+ package-names: '*'
+ min-versions-to-keep: 2
+ ```
+
+ To delete all except y latest versions of all packages hosted in a repo other than the workflow the __owner__, __repo__, __package-names__, __token__ and __min-versions-to-keep__ inputs are required.
+
+ The [token][token] needs the delete packages and read packages scope. It is recommended [to store the token as a secret][secret]. In this example the [token][token] was stored as a secret named __GITHUB_PAT__.
+
+ __Example__
+
+ Delete all except latest 2 versions of a package hosted in a repo other than the workflow
+
+ ```yaml
+ - uses: actions/delete-package-versions@v3
+ with:
+ owner: 'github'
+ repo: 'packages'
+ package-names: '*'
+ token: ${{ secrets.PAT }}
+ min-versions-to-keep: 2
+ ```
+
+
+
### Delete oldest x number of versions of a package
To delete the oldest x number of versions of a package hosted, the __package-name__, and __num-old-versions-to-delete__ inputs are required.
diff --git a/__tests__/packages/get-packages.test.ts b/__tests__/packages/get-packages.test.ts
new file mode 100644
index 00000000..27672257
--- /dev/null
+++ b/__tests__/packages/get-packages.test.ts
@@ -0,0 +1,66 @@
+import {mockPackagesQueryResponse} from './graphql.mock'
+import {
+ getRepoPackages as _getRepoPackages,
+ QueryInfo
+} from '../../src/packages'
+import {Observable} from 'rxjs'
+
+describe.skip('get versions tests -- call graphql', () => {
+ it('getRepoPackages -- succeeds', done => {
+ const numPackages = 1
+ getRepoPackages({numPackages}).subscribe(result => {
+ expect(result.packages.length).toBe(numPackages)
+ done()
+ })
+ })
+
+ it('getRepoPackages -- fails for invalid repo', done => {
+ getRepoPackages({repo: 'actions-testin'}).subscribe({
+ error: err => {
+ expect(err).toBeTruthy()
+ done()
+ },
+ complete: async () => done.fail('no error thrown')
+ })
+ })
+ })
+
+ describe('get versions tests -- mock graphql', () => {
+ it('getRepoPackages -- success', done => {
+ const numPackages = 5
+ mockPackagesQueryResponse(numPackages)
+
+ getRepoPackages({numPackages}).subscribe(result => {
+ expect(result.packages.length).toBe(numPackages)
+ done()
+ })
+ })
+ })
+
+ interface Params {
+ owner?: string
+ repo?: string
+ numPackages?: number
+ startCursor?: string
+ token?: string
+ }
+
+ const defaultParams = {
+ owner: 'namratajha',
+ repo: 'test-repo',
+ packageName: 'test-repo',
+ numPackages: 1,
+ startCursor: '',
+ token: process.env.GITHUB_TOKEN as string
+ }
+
+ function getRepoPackages(params?: Params): Observable {
+ const p: Required = {...defaultParams, ...params}
+ return _getRepoPackages(
+ p.owner,
+ p.repo,
+ p.numPackages,
+ p.startCursor,
+ p.token
+ )
+ }
\ No newline at end of file
diff --git a/__tests__/packages/graphql.mock.ts b/__tests__/packages/graphql.mock.ts
new file mode 100644
index 00000000..a6601488
--- /dev/null
+++ b/__tests__/packages/graphql.mock.ts
@@ -0,0 +1,44 @@
+import {
+ GraphQlQueryResponseData,
+ RequestParameters
+} from '@octokit/graphql/dist-types/types'
+
+import * as Graphql from '../../src/common/graphql'
+import {GetPackagesQueryResponse} from '../../src/packages'
+
+export function getMockedPackagesQueryResponse(
+ numPackages: number
+): GetPackagesQueryResponse {
+ const packages: any[] = []
+ for (let i = 1; i <= numPackages; ++i) {
+ packages.push({
+ node: {
+ id: i.toString(),
+ name: `package${i}`
+ }
+ })
+ }
+
+ return {
+ repository: {
+ packages: {
+ pageInfo: {
+ endCursor: 'AAA',
+ hasNextPage: false
+ },
+ edges: packages
+ }
+ }
+ }
+}
+
+export function mockPackagesQueryResponse(numVersions: number): void {
+ const response = new Promise(resolve => {
+ resolve(getMockedPackagesQueryResponse(numVersions))
+ }) as Promise
+ jest
+ .spyOn(Graphql, 'graphql')
+ .mockImplementation(
+ (token: string, query: string, parameters: RequestParameters) => response
+ )
+}
diff --git a/__tests__/packages/package-name-filter.test.ts b/__tests__/packages/package-name-filter.test.ts
new file mode 100644
index 00000000..781d7c74
--- /dev/null
+++ b/__tests__/packages/package-name-filter.test.ts
@@ -0,0 +1,114 @@
+import { getPackageNameFilter } from '../../src/packages'
+
+describe('package name filter -- create filter', () => {
+
+ const packageNameList = [
+ 'com.company.project.module1.package1',
+ 'com.company.project.module1.package2',
+ 'com.company.project.module2.package1',
+ 'com.company.project.module2.package2',
+ 'com.company.project.module3.package-name-lorem',
+ 'com.company.project.module3.package-name-ipsum',
+ 'com.company.project.module3.package-name-dolor',
+ ]
+
+ it('getPackageNameFilter -- wildcard end filter', done => {
+ const filter = getPackageNameFilter('com.company.project.module1.*')
+
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('wildcard')
+ expect(result).toEqual([
+ 'com.company.project.module1.package1',
+ 'com.company.project.module1.package2',
+ ])
+ done()
+ })
+
+ it('getPackageNameFilter -- wildcard start filter', done => {
+ const filter = getPackageNameFilter('*.package1')
+
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('wildcard')
+ expect(result).toEqual([
+ 'com.company.project.module1.package1',
+ 'com.company.project.module2.package1',
+ ])
+ done()
+ })
+
+ it('getPackageNameFilter -- wildcard both sides filter', done => {
+ const filter = getPackageNameFilter('*.project.module3.*')
+
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('wildcard')
+ expect(result).toEqual([
+ 'com.company.project.module3.package-name-lorem',
+ 'com.company.project.module3.package-name-ipsum',
+ 'com.company.project.module3.package-name-dolor'
+ ])
+ done()
+ })
+
+
+ it('getPackageNameFilter -- wildcard all filter', done => {
+ const filter = getPackageNameFilter('*')
+
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('wildcard')
+ expect(result).toEqual(packageNameList.slice())
+ done()
+ })
+
+ it('getPackageNameFilter -- regex filter', done => {
+ const filter = getPackageNameFilter('/com\\.company\\.project\\.module.*\\.package1/')
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('regex')
+ expect(result).toEqual([
+ 'com.company.project.module1.package1',
+ 'com.company.project.module2.package1',
+ ])
+ done()
+ })
+
+ it('getPackageNameFilter -- exact match filter', done => {
+ const filter = getPackageNameFilter('com.company.project.module1.package1')
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters[0].type).toBe('string')
+ expect(result).toEqual(['com.company.project.module1.package1'])
+ done()
+ })
+
+
+ it('getPackageNameFilter -- multiple filters', done => {
+ const filter = getPackageNameFilter('com.company.project.module1.package1, com.company.project.module2.*, /.*module3.*-ipsum/')
+ const result = packageNameList.filter(filter.apply);
+
+ expect(filter.subfilters.length).toBe(3)
+ expect(filter.subfilters[0].type).toBe('string')
+ expect(filter.subfilters[1].type).toBe('wildcard')
+ expect(filter.subfilters[2].type).toBe('regex')
+ expect(result).toEqual([
+ 'com.company.project.module1.package1',
+ 'com.company.project.module2.package1',
+ 'com.company.project.module2.package2',
+ 'com.company.project.module3.package-name-ipsum'
+ ])
+ done()
+ })
+
+
+ it('getPackageNameFilter -- memoization, same input shoud return same output', done => {
+ const filterText = 'com.company.project.module1.package1, com.company.project.module2.*, /.*module3.*-dolor/, *.-lorem'
+ const filter1 = getPackageNameFilter(filterText)
+ const filter2 = getPackageNameFilter(filterText)
+ expect(filter1).toBe(filter2)
+ expect(filter1.subfilters.length).toBe(4)
+ done()
+ })
+ })
\ No newline at end of file
diff --git a/action.yml b/action.yml
index 1bf23e28..5db046f3 100644
--- a/action.yml
+++ b/action.yml
@@ -25,6 +25,19 @@ inputs:
Type of package. Can be one of container, maven, npm, nuget, or rubygems.
required: true
+
+ package-names:
+ description: >
+ Names of the package.
+ Can be one of the following:
+ - a single package name
+ - a group of packages that matches a wildcard at start, end, both sides, or all packages (e.g. "package*")
+ - a group of packages that matches a regex, must start with slash at the beginning and end (e.g. "/package.*/")
+ - a comma separated list of the previous cases (e.g. "package-lorem, *-ipsum, /.*dolor/")
+ Defaults to an empty string.
+ Required if `package-version-ids` or `package-name` input is not given.
+ required: false
+
num-old-versions-to-delete:
description: >
Number of versions to delete starting with the oldest version.
diff --git a/dist/index.js b/dist/index.js
index 89172a5a..270fd6d3 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1,6 +1,41 @@
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
+/***/ 9057:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ 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) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.graphql = void 0;
+const github_1 = __nccwpck_require__(5438);
+/**
+ * Sends a GraphQL query request based on endpoint options
+ *
+ * @param {string} token Auth token
+ * @param {string} query GraphQL query. Example: `'query { viewer { login } }'`.
+ * @param {object} parameters URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
+ */
+function graphql(token, query, parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const github = new github_1.GitHub(token);
+ return yield github.graphql(query, parameters);
+ });
+}
+exports.graphql = graphql;
+
+
+/***/ }),
+
/***/ 9645:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
@@ -8,12 +43,20 @@
/* eslint-disable i18n-text/no-en */
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.deleteVersions = exports.finalIds = exports.getVersionIds = exports.RATE_LIMIT = void 0;
+exports.deleteVersions = exports.finalIds = exports.getVersionIds = exports.getPackageNames = exports.RATE_LIMIT = void 0;
+const input_1 = __nccwpck_require__(8657);
const rxjs_1 = __nccwpck_require__(5805);
const operators_1 = __nccwpck_require__(7801);
const version_1 = __nccwpck_require__(4428);
+const packages_1 = __nccwpck_require__(221);
exports.RATE_LIMIT = 100;
let totalCount = 0;
+function getPackageNames(owner, repo, numPackages, cursor, token) {
+ return (0, packages_1.getRepoPackages)(owner, repo, numPackages, cursor, token).pipe((0, operators_1.expand)(value => value.paginate
+ ? (0, packages_1.getRepoPackages)(owner, repo, numPackages, value.cursor, token)
+ : rxjs_1.EMPTY), (0, operators_1.map)(value => value.packages));
+}
+exports.getPackageNames = getPackageNames;
function getVersionIds(owner, packageName, packageType, numVersions, page, token) {
return (0, version_1.getOldestVersions)(owner, packageName, packageType, numVersions, page, token).pipe((0, operators_1.expand)(value => value.paginate
? (0, version_1.getOldestVersions)(owner, packageName, packageType, numVersions, value.page + 1, token)
@@ -23,37 +66,56 @@ exports.getVersionIds = getVersionIds;
function finalIds(input) {
if (input.packageVersionIds.length > 0) {
const toDelete = Math.min(input.packageVersionIds.length, exports.RATE_LIMIT);
- return (0, rxjs_1.of)(input.packageVersionIds.slice(0, toDelete));
- }
- if (input.hasOldestVersionQueryInfo()) {
- return getVersionIds(input.owner, input.packageName, input.packageType, exports.RATE_LIMIT, 1, input.token).pipe(
- // This code block executes on all versions of a package starting from oldest
- (0, operators_1.map)(value => {
- // we need to delete oldest versions first
- value.sort((a, b) => {
- return (new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
- });
- /*
- Here first filter out the versions that are to be ignored.
- Then compute number of versions to delete (toDelete) based on the inputs.
- */
- value = value.filter(info => !input.ignoreVersions.test(info.version));
- if (input.deleteUntaggedVersions === 'true') {
- value = value.filter(info => !info.tagged);
- }
- let toDelete = 0;
- if (input.minVersionsToKeep < 0) {
- toDelete = Math.min(value.length, Math.min(input.numOldVersionsToDelete, exports.RATE_LIMIT));
- }
- else {
- toDelete = Math.min(value.length - input.minVersionsToKeep, exports.RATE_LIMIT);
- }
- if (toDelete < 0)
- return [];
- return value.map(info => info.id.toString()).slice(0, toDelete);
- }));
+ return (0, rxjs_1.of)({
+ versions: input.packageVersionIds.slice(0, toDelete),
+ name: input.packageName
+ });
}
- return (0, rxjs_1.throwError)("Could not get packageVersionIds. Explicitly specify using the 'package-version-ids' input");
+ if (!input.hasOldestVersionQueryInfo()) {
+ return (0, rxjs_1.throwError)("Could not get packageVersionIds. Explicitly specify using the 'package-version-ids' input");
+ }
+ const filter = (0, packages_1.getPackageNameFilter)(input.packageNames);
+ if (!filter.isEmpty) {
+ return getPackageNames(input.owner, input.repo, exports.RATE_LIMIT, '', input.token)
+ .pipe((0, operators_1.mergeMap)(value => {
+ return value
+ .filter(info => filter.apply(info.name))
+ .map(info => finalIds(new input_1.Input(Object.assign(Object.assign({}, input), { packageNames: '', packageName: info.name }))));
+ }))
+ .pipe((0, operators_1.mergeMap)(val => val));
+ }
+ const versions = getVersionIds(input.owner, input.packageName, input.packageType, exports.RATE_LIMIT, 1, input.token).pipe(
+ // This code block executes on all versions of a package starting from oldest
+ (0, operators_1.map)(value => {
+ // we need to delete oldest versions first
+ value.sort((a, b) => {
+ return (new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
+ });
+ /*
+ Here first filter out the versions that are to be ignored.
+ Then compute number of versions to delete (toDelete) based on the inputs.
+ */
+ value = value.filter(info => !input.ignoreVersions.test(info.version));
+ if (input.deleteUntaggedVersions === 'true') {
+ value = value.filter(info => !info.tagged);
+ }
+ let toDelete = 0;
+ if (input.minVersionsToKeep < 0) {
+ toDelete = Math.min(value.length, Math.min(input.numOldVersionsToDelete, exports.RATE_LIMIT));
+ }
+ else {
+ toDelete = Math.min(value.length - input.minVersionsToKeep, exports.RATE_LIMIT);
+ }
+ if (toDelete < 0)
+ return [];
+ return value.map(info => info.id.toString()).slice(0, toDelete);
+ }));
+ return versions.pipe((0, operators_1.map)(data => {
+ return {
+ versions: data,
+ name: input.packageName
+ };
+ }));
}
exports.finalIds = finalIds;
function deleteVersions(input) {
@@ -68,7 +130,10 @@ function deleteVersions(input) {
return (0, rxjs_1.of)(true);
}
const result = finalIds(input);
- return result.pipe((0, operators_1.concatMap)(ids => (0, version_1.deletePackageVersions)(ids, input.owner, input.packageName, input.packageType, input.token)));
+ return result.pipe((0, operators_1.concatMap)(data => {
+ console.log(`clearing ${data.versions.length} versions from ${data.name}`);
+ return (0, version_1.deletePackageVersions)(data.versions, input.owner, data.name, input.packageType, input.token);
+ }));
}
exports.deleteVersions = deleteVersions;
@@ -85,8 +150,10 @@ exports.Input = void 0;
const defaultParams = {
packageVersionIds: [],
owner: '',
+ repo: '',
packageName: '',
packageType: '',
+ packageNames: '',
numOldVersionsToDelete: 0,
minVersionsToKeep: 0,
ignoreVersions: new RegExp(''),
@@ -99,8 +166,10 @@ class Input {
const validatedParams = Object.assign(Object.assign({}, defaultParams), params);
this.packageVersionIds = validatedParams.packageVersionIds;
this.owner = validatedParams.owner;
+ this.repo = validatedParams.repo;
this.packageName = validatedParams.packageName;
this.packageType = validatedParams.packageType;
+ this.packageNames = validatedParams.packageNames;
this.numOldVersionsToDelete = validatedParams.numOldVersionsToDelete;
this.minVersionsToKeep = validatedParams.minVersionsToKeep;
this.ignoreVersions = validatedParams.ignoreVersions;
@@ -111,7 +180,8 @@ class Input {
}
hasOldestVersionQueryInfo() {
return !!(this.owner &&
- this.packageName &&
+ this.repo &&
+ (this.packageName || this.packageNames) &&
this.numOldVersionsToDelete >= 0 &&
this.token);
}
@@ -120,7 +190,8 @@ class Input {
(this.minVersionsToKeep >= 0 || this.deletePreReleaseVersions === 'true')) {
return false;
}
- if (this.packageType === '' || this.packageName === '') {
+ if (this.packageType === '' ||
+ (this.packageName === '' && this.packageNames === '')) {
return false;
}
if (this.deletePreReleaseVersions === 'true') {
@@ -140,6 +211,250 @@ class Input {
exports.Input = Input;
+/***/ }),
+
+/***/ 6436:
+/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getRepoPackages = exports.queryForRepoPackages = void 0;
+const rxjs_1 = __nccwpck_require__(5805);
+const operators_1 = __nccwpck_require__(7801);
+const graphql_1 = __nccwpck_require__(9057);
+const query = `
+ query getPackages($owner: String!, $repo: String!, $first: Int!){
+ repository(owner: $owner, name: $repo) {
+ packages(first:$first){
+ edges {
+ node {
+ name
+ id
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }`;
+const Paginatequery = `
+ query getPackages($owner: String!, $repo: String!, $first: Int!, $after: String!){
+ repository(owner: $owner, name: $repo) {
+ packages(first:$first){
+ edges {
+ node {
+ name
+ id
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }`;
+function queryForRepoPackages(owner, repo, numPackages, startCursor, token) {
+ if (startCursor === '') {
+ return (0, rxjs_1.from)((0, graphql_1.graphql)(token, query, {
+ owner,
+ repo,
+ first: numPackages,
+ headers: {
+ Accept: 'application/vnd.github.packages-preview+json'
+ }
+ })).pipe((0, operators_1.catchError)((err) => {
+ const msg = 'query for packages failed.';
+ return (0, rxjs_1.throwError)(err.errors && err.errors.length > 0
+ ? `${msg} ${err.errors[0].message}`
+ : `${msg} verify input parameters are correct ${JSON.stringify(err, null, 2)}`);
+ }));
+ }
+ else {
+ return (0, rxjs_1.from)((0, graphql_1.graphql)(token, Paginatequery, {
+ owner,
+ repo,
+ first: numPackages,
+ before: startCursor,
+ after: '',
+ headers: {
+ Accept: 'application/vnd.github.packages-preview+json'
+ }
+ })).pipe((0, operators_1.catchError)((err) => {
+ const msg = 'query for packages failed.';
+ console.log(err);
+ return (0, rxjs_1.throwError)(err.errors && err.errors.length > 0
+ ? `${msg} ${err.errors[0].message}`
+ : `${msg} verify input parameters are correct`);
+ }));
+ }
+}
+exports.queryForRepoPackages = queryForRepoPackages;
+function getRepoPackages(owner, repo, numPackages, startCursor, token) {
+ return queryForRepoPackages(owner, repo, numPackages, startCursor, token).pipe((0, operators_1.map)(result => {
+ let r;
+ if (result.repository.packages.edges.length < 1) {
+ console.log(`package: No packages found for owner: ${owner} in repo: ${repo}`);
+ r = {
+ packages: [],
+ cursor: '',
+ paginate: false
+ };
+ return r;
+ }
+ const packages = result.repository.packages.edges;
+ const pages = result.repository.packages.pageInfo;
+ r = {
+ packages: packages.map(value => ({
+ id: value.node.id,
+ name: value.node.name
+ })),
+ cursor: pages.endCursor,
+ paginate: pages.hasNextPage
+ };
+ return r;
+ }));
+}
+exports.getRepoPackages = getRepoPackages;
+
+
+/***/ }),
+
+/***/ 221:
+/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
+
+"use strict";
+
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+__exportStar(__nccwpck_require__(6436), exports);
+__exportStar(__nccwpck_require__(2539), exports);
+
+
+/***/ }),
+
+/***/ 2539:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getPackageNameFilter = void 0;
+/**
+ * Used to apply memoization on getPackageNameFilter
+ */
+const resultCache = {};
+/**
+ * Get a filter based on package names to match
+ *
+ * @param packageNames - serialized package names filter as string
+ * @returns the respective package filter
+ */
+function getPackageNameFilter(packageNames) {
+ if (resultCache[packageNames]) {
+ return resultCache[packageNames];
+ }
+ const result = calculatePackageNameFilter(packageNames);
+ resultCache[packageNames] = result;
+ return result;
+}
+exports.getPackageNameFilter = getPackageNameFilter;
+const emptyFilter = Object.freeze({
+ subfilters: Object.freeze([]),
+ isEmpty: true,
+ apply: () => false
+});
+/**
+ * Generates a filter based package names to match
+ *
+ * @param packageNames - serialized package names filter as string
+ * @returns the respective package filter
+ */
+function calculatePackageNameFilter(packageNames) {
+ if (packageNames === '') {
+ return emptyFilter;
+ }
+ const separatedPackageNames = packageNames
+ .split(',')
+ .map(name => name.trim())
+ .filter(name => name !== '');
+ if (separatedPackageNames.length <= 0) {
+ return emptyFilter;
+ }
+ const subfilters = separatedPackageNames.map(createFilter);
+ return {
+ subfilters,
+ isEmpty: subfilters.length <= 0,
+ apply: names => subfilters.some(filter => filter.apply(names))
+ };
+}
+function createFilter(packageName) {
+ if (packageName.startsWith('*') || packageName.endsWith('*')) {
+ return createWildcardFilter(packageName);
+ }
+ else if (packageName.startsWith('/') && packageName.endsWith('/')) {
+ return createRegexFilter(packageName);
+ }
+ else {
+ return createExactMatchFilter(packageName);
+ }
+}
+function createWildcardFilter(wildcardPackageName) {
+ const startsWithWildCard = wildcardPackageName.startsWith('*');
+ const endsWithWildCard = wildcardPackageName.endsWith('*');
+ let fn;
+ if (wildcardPackageName === '*') {
+ fn = () => true;
+ }
+ else if (startsWithWildCard && endsWithWildCard) {
+ const targetText = wildcardPackageName.substring(1, wildcardPackageName.length - 1);
+ fn = (packageName) => packageName.includes(targetText);
+ }
+ else if (startsWithWildCard) {
+ const targetText = wildcardPackageName.substring(1);
+ fn = (packageName) => packageName.endsWith(targetText);
+ }
+ else {
+ const targetText = wildcardPackageName.substring(0, wildcardPackageName.length - 1);
+ fn = (packageName) => packageName.startsWith(targetText);
+ }
+ return {
+ type: 'wildcard',
+ apply: fn
+ };
+}
+function createRegexFilter(regexPackageName) {
+ const regexPattern = regexPackageName.substring(1, regexPackageName.length - 1);
+ const regex = new RegExp(regexPattern);
+ return {
+ type: 'regex',
+ apply: (packageName) => regex.test(packageName)
+ };
+}
+function createExactMatchFilter(matchingPackageName) {
+ return {
+ type: 'string',
+ apply: (packageName) => packageName === matchingPackageName
+ };
+}
+
+
/***/ }),
/***/ 5544:
@@ -167,10 +482,8 @@ function deletePackageVersion(packageVersionId, owner, packageName, packageType,
username: owner,
package_version_id
})).pipe((0, operators_1.catchError)(err => {
- const msg = 'delete version API failed.';
- return (0, rxjs_1.throwError)(err.errors && err.errors.length > 0
- ? `${msg} ${err.errors[0].message}`
- : `${msg} ${err.message} \n${deleted - 1} versions deleted till now.`);
+ console.log(err);
+ return rxjs_1.EMPTY;
}), (0, operators_1.map)(response => response.status === 204));
}
exports.deletePackageVersion = deletePackageVersion;
@@ -215,10 +528,7 @@ function getOldestVersions(owner, packageName, packageType, numVersions, page, t
per_page: numVersions,
page
})).pipe((0, operators_1.catchError)(err => {
- const msg = 'get versions API failed.';
- return (0, rxjs_1.throwError)(err.errors && err.errors.length > 0
- ? `${msg} ${err.errors[0].message}`
- : `${msg} ${err.message}`);
+ return rxjs_1.EMPTY;
}), (0, operators_1.map)(response => {
const resp = {
versions: response.data.map((version) => {
@@ -42145,1303 +42455,1303 @@ exports.parseURL = __nccwpck_require__(2158).parseURL;
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
"use strict";
-
-const punycode = __nccwpck_require__(5477);
-const tr46 = __nccwpck_require__(4256);
-
-const specialSchemes = {
- ftp: 21,
- file: null,
- gopher: 70,
- http: 80,
- https: 443,
- ws: 80,
- wss: 443
-};
-
-const failure = Symbol("failure");
-
-function countSymbols(str) {
- return punycode.ucs2.decode(str).length;
-}
-
-function at(input, idx) {
- const c = input[idx];
- return isNaN(c) ? undefined : String.fromCodePoint(c);
-}
-
-function isASCIIDigit(c) {
- return c >= 0x30 && c <= 0x39;
-}
-
-function isASCIIAlpha(c) {
- return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
-}
-
-function isASCIIAlphanumeric(c) {
- return isASCIIAlpha(c) || isASCIIDigit(c);
-}
-
-function isASCIIHex(c) {
- return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66);
-}
-
-function isSingleDot(buffer) {
- return buffer === "." || buffer.toLowerCase() === "%2e";
-}
-
-function isDoubleDot(buffer) {
- buffer = buffer.toLowerCase();
- return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e";
-}
-
-function isWindowsDriveLetterCodePoints(cp1, cp2) {
- return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124);
-}
-
-function isWindowsDriveLetterString(string) {
- return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|");
-}
-
-function isNormalizedWindowsDriveLetterString(string) {
- return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":";
-}
-
-function containsForbiddenHostCodePoint(string) {
- return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1;
-}
-
-function containsForbiddenHostCodePointExcludingPercent(string) {
- return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1;
-}
-
-function isSpecialScheme(scheme) {
- return specialSchemes[scheme] !== undefined;
-}
-
-function isSpecial(url) {
- return isSpecialScheme(url.scheme);
-}
-
-function defaultPort(scheme) {
- return specialSchemes[scheme];
-}
-
-function percentEncode(c) {
- let hex = c.toString(16).toUpperCase();
- if (hex.length === 1) {
- hex = "0" + hex;
- }
-
- return "%" + hex;
-}
-
-function utf8PercentEncode(c) {
- const buf = new Buffer(c);
-
- let str = "";
-
- for (let i = 0; i < buf.length; ++i) {
- str += percentEncode(buf[i]);
- }
-
- return str;
-}
-
-function utf8PercentDecode(str) {
- const input = new Buffer(str);
- const output = [];
- for (let i = 0; i < input.length; ++i) {
- if (input[i] !== 37) {
- output.push(input[i]);
- } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) {
- output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16));
- i += 2;
- } else {
- output.push(input[i]);
- }
- }
- return new Buffer(output).toString();
-}
-
-function isC0ControlPercentEncode(c) {
- return c <= 0x1F || c > 0x7E;
-}
-
-const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]);
-function isPathPercentEncode(c) {
- return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c);
-}
-
-const extraUserinfoPercentEncodeSet =
- new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]);
-function isUserinfoPercentEncode(c) {
- return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c);
-}
-
-function percentEncodeChar(c, encodeSetPredicate) {
- const cStr = String.fromCodePoint(c);
-
- if (encodeSetPredicate(c)) {
- return utf8PercentEncode(cStr);
- }
-
- return cStr;
-}
-
-function parseIPv4Number(input) {
- let R = 10;
-
- if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") {
- input = input.substring(2);
- R = 16;
- } else if (input.length >= 2 && input.charAt(0) === "0") {
- input = input.substring(1);
- R = 8;
- }
-
- if (input === "") {
- return 0;
- }
-
- const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/);
- if (regex.test(input)) {
- return failure;
- }
-
- return parseInt(input, R);
-}
-
-function parseIPv4(input) {
- const parts = input.split(".");
- if (parts[parts.length - 1] === "") {
- if (parts.length > 1) {
- parts.pop();
- }
- }
-
- if (parts.length > 4) {
- return input;
- }
-
- const numbers = [];
- for (const part of parts) {
- if (part === "") {
- return input;
- }
- const n = parseIPv4Number(part);
- if (n === failure) {
- return input;
- }
-
- numbers.push(n);
- }
-
- for (let i = 0; i < numbers.length - 1; ++i) {
- if (numbers[i] > 255) {
- return failure;
- }
- }
- if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) {
- return failure;
- }
-
- let ipv4 = numbers.pop();
- let counter = 0;
-
- for (const n of numbers) {
- ipv4 += n * Math.pow(256, 3 - counter);
- ++counter;
- }
-
- return ipv4;
-}
-
-function serializeIPv4(address) {
- let output = "";
- let n = address;
-
- for (let i = 1; i <= 4; ++i) {
- output = String(n % 256) + output;
- if (i !== 4) {
- output = "." + output;
- }
- n = Math.floor(n / 256);
- }
-
- return output;
-}
-
-function parseIPv6(input) {
- const address = [0, 0, 0, 0, 0, 0, 0, 0];
- let pieceIndex = 0;
- let compress = null;
- let pointer = 0;
-
- input = punycode.ucs2.decode(input);
-
- if (input[pointer] === 58) {
- if (input[pointer + 1] !== 58) {
- return failure;
- }
-
- pointer += 2;
- ++pieceIndex;
- compress = pieceIndex;
- }
-
- while (pointer < input.length) {
- if (pieceIndex === 8) {
- return failure;
- }
-
- if (input[pointer] === 58) {
- if (compress !== null) {
- return failure;
- }
- ++pointer;
- ++pieceIndex;
- compress = pieceIndex;
- continue;
- }
-
- let value = 0;
- let length = 0;
-
- while (length < 4 && isASCIIHex(input[pointer])) {
- value = value * 0x10 + parseInt(at(input, pointer), 16);
- ++pointer;
- ++length;
- }
-
- if (input[pointer] === 46) {
- if (length === 0) {
- return failure;
- }
-
- pointer -= length;
-
- if (pieceIndex > 6) {
- return failure;
- }
-
- let numbersSeen = 0;
-
- while (input[pointer] !== undefined) {
- let ipv4Piece = null;
-
- if (numbersSeen > 0) {
- if (input[pointer] === 46 && numbersSeen < 4) {
- ++pointer;
- } else {
- return failure;
- }
- }
-
- if (!isASCIIDigit(input[pointer])) {
- return failure;
- }
-
- while (isASCIIDigit(input[pointer])) {
- const number = parseInt(at(input, pointer));
- if (ipv4Piece === null) {
- ipv4Piece = number;
- } else if (ipv4Piece === 0) {
- return failure;
- } else {
- ipv4Piece = ipv4Piece * 10 + number;
- }
- if (ipv4Piece > 255) {
- return failure;
- }
- ++pointer;
- }
-
- address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece;
-
- ++numbersSeen;
-
- if (numbersSeen === 2 || numbersSeen === 4) {
- ++pieceIndex;
- }
- }
-
- if (numbersSeen !== 4) {
- return failure;
- }
-
- break;
- } else if (input[pointer] === 58) {
- ++pointer;
- if (input[pointer] === undefined) {
- return failure;
- }
- } else if (input[pointer] !== undefined) {
- return failure;
- }
-
- address[pieceIndex] = value;
- ++pieceIndex;
- }
-
- if (compress !== null) {
- let swaps = pieceIndex - compress;
- pieceIndex = 7;
- while (pieceIndex !== 0 && swaps > 0) {
- const temp = address[compress + swaps - 1];
- address[compress + swaps - 1] = address[pieceIndex];
- address[pieceIndex] = temp;
- --pieceIndex;
- --swaps;
- }
- } else if (compress === null && pieceIndex !== 8) {
- return failure;
- }
-
- return address;
-}
-
-function serializeIPv6(address) {
- let output = "";
- const seqResult = findLongestZeroSequence(address);
- const compress = seqResult.idx;
- let ignore0 = false;
-
- for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) {
- if (ignore0 && address[pieceIndex] === 0) {
- continue;
- } else if (ignore0) {
- ignore0 = false;
- }
-
- if (compress === pieceIndex) {
- const separator = pieceIndex === 0 ? "::" : ":";
- output += separator;
- ignore0 = true;
- continue;
- }
-
- output += address[pieceIndex].toString(16);
-
- if (pieceIndex !== 7) {
- output += ":";
- }
- }
-
- return output;
-}
-
-function parseHost(input, isSpecialArg) {
- if (input[0] === "[") {
- if (input[input.length - 1] !== "]") {
- return failure;
- }
-
- return parseIPv6(input.substring(1, input.length - 1));
- }
-
- if (!isSpecialArg) {
- return parseOpaqueHost(input);
- }
-
- const domain = utf8PercentDecode(input);
- const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false);
- if (asciiDomain === null) {
- return failure;
- }
-
- if (containsForbiddenHostCodePoint(asciiDomain)) {
- return failure;
- }
-
- const ipv4Host = parseIPv4(asciiDomain);
- if (typeof ipv4Host === "number" || ipv4Host === failure) {
- return ipv4Host;
- }
-
- return asciiDomain;
-}
-
-function parseOpaqueHost(input) {
- if (containsForbiddenHostCodePointExcludingPercent(input)) {
- return failure;
- }
-
- let output = "";
- const decoded = punycode.ucs2.decode(input);
- for (let i = 0; i < decoded.length; ++i) {
- output += percentEncodeChar(decoded[i], isC0ControlPercentEncode);
- }
- return output;
-}
-
-function findLongestZeroSequence(arr) {
- let maxIdx = null;
- let maxLen = 1; // only find elements > 1
- let currStart = null;
- let currLen = 0;
-
- for (let i = 0; i < arr.length; ++i) {
- if (arr[i] !== 0) {
- if (currLen > maxLen) {
- maxIdx = currStart;
- maxLen = currLen;
- }
-
- currStart = null;
- currLen = 0;
- } else {
- if (currStart === null) {
- currStart = i;
- }
- ++currLen;
- }
- }
-
- // if trailing zeros
- if (currLen > maxLen) {
- maxIdx = currStart;
- maxLen = currLen;
- }
-
- return {
- idx: maxIdx,
- len: maxLen
- };
-}
-
-function serializeHost(host) {
- if (typeof host === "number") {
- return serializeIPv4(host);
- }
-
- // IPv6 serializer
- if (host instanceof Array) {
- return "[" + serializeIPv6(host) + "]";
- }
-
- return host;
-}
-
-function trimControlChars(url) {
- return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, "");
-}
-
-function trimTabAndNewline(url) {
- return url.replace(/\u0009|\u000A|\u000D/g, "");
-}
-
-function shortenPath(url) {
- const path = url.path;
- if (path.length === 0) {
- return;
- }
- if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) {
- return;
- }
-
- path.pop();
-}
-
-function includesCredentials(url) {
- return url.username !== "" || url.password !== "";
-}
-
-function cannotHaveAUsernamePasswordPort(url) {
- return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file";
-}
-
-function isNormalizedWindowsDriveLetter(string) {
- return /^[A-Za-z]:$/.test(string);
-}
-
-function URLStateMachine(input, base, encodingOverride, url, stateOverride) {
- this.pointer = 0;
- this.input = input;
- this.base = base || null;
- this.encodingOverride = encodingOverride || "utf-8";
- this.stateOverride = stateOverride;
- this.url = url;
- this.failure = false;
- this.parseError = false;
-
- if (!this.url) {
- this.url = {
- scheme: "",
- username: "",
- password: "",
- host: null,
- port: null,
- path: [],
- query: null,
- fragment: null,
-
- cannotBeABaseURL: false
- };
-
- const res = trimControlChars(this.input);
- if (res !== this.input) {
- this.parseError = true;
- }
- this.input = res;
- }
-
- const res = trimTabAndNewline(this.input);
- if (res !== this.input) {
- this.parseError = true;
- }
- this.input = res;
-
- this.state = stateOverride || "scheme start";
-
- this.buffer = "";
- this.atFlag = false;
- this.arrFlag = false;
- this.passwordTokenSeenFlag = false;
-
- this.input = punycode.ucs2.decode(this.input);
-
- for (; this.pointer <= this.input.length; ++this.pointer) {
- const c = this.input[this.pointer];
- const cStr = isNaN(c) ? undefined : String.fromCodePoint(c);
-
- // exec state machine
- const ret = this["parse " + this.state](c, cStr);
- if (!ret) {
- break; // terminate algorithm
- } else if (ret === failure) {
- this.failure = true;
- break;
- }
- }
-}
-
-URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) {
- if (isASCIIAlpha(c)) {
- this.buffer += cStr.toLowerCase();
- this.state = "scheme";
- } else if (!this.stateOverride) {
- this.state = "no scheme";
- --this.pointer;
- } else {
- this.parseError = true;
- return failure;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) {
- if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) {
- this.buffer += cStr.toLowerCase();
- } else if (c === 58) {
- if (this.stateOverride) {
- if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) {
- return false;
- }
-
- if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) {
- return false;
- }
-
- if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") {
- return false;
- }
-
- if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) {
- return false;
- }
- }
- this.url.scheme = this.buffer;
- this.buffer = "";
- if (this.stateOverride) {
- return false;
- }
- if (this.url.scheme === "file") {
- if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) {
- this.parseError = true;
- }
- this.state = "file";
- } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) {
- this.state = "special relative or authority";
- } else if (isSpecial(this.url)) {
- this.state = "special authority slashes";
- } else if (this.input[this.pointer + 1] === 47) {
- this.state = "path or authority";
- ++this.pointer;
- } else {
- this.url.cannotBeABaseURL = true;
- this.url.path.push("");
- this.state = "cannot-be-a-base-URL path";
- }
- } else if (!this.stateOverride) {
- this.buffer = "";
- this.state = "no scheme";
- this.pointer = -1;
- } else {
- this.parseError = true;
- return failure;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) {
- if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) {
- return failure;
- } else if (this.base.cannotBeABaseURL && c === 35) {
- this.url.scheme = this.base.scheme;
- this.url.path = this.base.path.slice();
- this.url.query = this.base.query;
- this.url.fragment = "";
- this.url.cannotBeABaseURL = true;
- this.state = "fragment";
- } else if (this.base.scheme === "file") {
- this.state = "file";
- --this.pointer;
- } else {
- this.state = "relative";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) {
- if (c === 47 && this.input[this.pointer + 1] === 47) {
- this.state = "special authority ignore slashes";
- ++this.pointer;
- } else {
- this.parseError = true;
- this.state = "relative";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) {
- if (c === 47) {
- this.state = "authority";
- } else {
- this.state = "path";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse relative"] = function parseRelative(c) {
- this.url.scheme = this.base.scheme;
- if (isNaN(c)) {
- this.url.username = this.base.username;
- this.url.password = this.base.password;
- this.url.host = this.base.host;
- this.url.port = this.base.port;
- this.url.path = this.base.path.slice();
- this.url.query = this.base.query;
- } else if (c === 47) {
- this.state = "relative slash";
- } else if (c === 63) {
- this.url.username = this.base.username;
- this.url.password = this.base.password;
- this.url.host = this.base.host;
- this.url.port = this.base.port;
- this.url.path = this.base.path.slice();
- this.url.query = "";
- this.state = "query";
- } else if (c === 35) {
- this.url.username = this.base.username;
- this.url.password = this.base.password;
- this.url.host = this.base.host;
- this.url.port = this.base.port;
- this.url.path = this.base.path.slice();
- this.url.query = this.base.query;
- this.url.fragment = "";
- this.state = "fragment";
- } else if (isSpecial(this.url) && c === 92) {
- this.parseError = true;
- this.state = "relative slash";
- } else {
- this.url.username = this.base.username;
- this.url.password = this.base.password;
- this.url.host = this.base.host;
- this.url.port = this.base.port;
- this.url.path = this.base.path.slice(0, this.base.path.length - 1);
-
- this.state = "path";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) {
- if (isSpecial(this.url) && (c === 47 || c === 92)) {
- if (c === 92) {
- this.parseError = true;
- }
- this.state = "special authority ignore slashes";
- } else if (c === 47) {
- this.state = "authority";
- } else {
- this.url.username = this.base.username;
- this.url.password = this.base.password;
- this.url.host = this.base.host;
- this.url.port = this.base.port;
- this.state = "path";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) {
- if (c === 47 && this.input[this.pointer + 1] === 47) {
- this.state = "special authority ignore slashes";
- ++this.pointer;
- } else {
- this.parseError = true;
- this.state = "special authority ignore slashes";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) {
- if (c !== 47 && c !== 92) {
- this.state = "authority";
- --this.pointer;
- } else {
- this.parseError = true;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) {
- if (c === 64) {
- this.parseError = true;
- if (this.atFlag) {
- this.buffer = "%40" + this.buffer;
- }
- this.atFlag = true;
-
- // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars
- const len = countSymbols(this.buffer);
- for (let pointer = 0; pointer < len; ++pointer) {
- const codePoint = this.buffer.codePointAt(pointer);
-
- if (codePoint === 58 && !this.passwordTokenSeenFlag) {
- this.passwordTokenSeenFlag = true;
- continue;
- }
- const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode);
- if (this.passwordTokenSeenFlag) {
- this.url.password += encodedCodePoints;
- } else {
- this.url.username += encodedCodePoints;
- }
- }
- this.buffer = "";
- } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
- (isSpecial(this.url) && c === 92)) {
- if (this.atFlag && this.buffer === "") {
- this.parseError = true;
- return failure;
- }
- this.pointer -= countSymbols(this.buffer) + 1;
- this.buffer = "";
- this.state = "host";
- } else {
- this.buffer += cStr;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse hostname"] =
-URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) {
- if (this.stateOverride && this.url.scheme === "file") {
- --this.pointer;
- this.state = "file host";
- } else if (c === 58 && !this.arrFlag) {
- if (this.buffer === "") {
- this.parseError = true;
- return failure;
- }
-
- const host = parseHost(this.buffer, isSpecial(this.url));
- if (host === failure) {
- return failure;
- }
-
- this.url.host = host;
- this.buffer = "";
- this.state = "port";
- if (this.stateOverride === "hostname") {
- return false;
- }
- } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
- (isSpecial(this.url) && c === 92)) {
- --this.pointer;
- if (isSpecial(this.url) && this.buffer === "") {
- this.parseError = true;
- return failure;
- } else if (this.stateOverride && this.buffer === "" &&
- (includesCredentials(this.url) || this.url.port !== null)) {
- this.parseError = true;
- return false;
- }
-
- const host = parseHost(this.buffer, isSpecial(this.url));
- if (host === failure) {
- return failure;
- }
-
- this.url.host = host;
- this.buffer = "";
- this.state = "path start";
- if (this.stateOverride) {
- return false;
- }
- } else {
- if (c === 91) {
- this.arrFlag = true;
- } else if (c === 93) {
- this.arrFlag = false;
- }
- this.buffer += cStr;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) {
- if (isASCIIDigit(c)) {
- this.buffer += cStr;
- } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
- (isSpecial(this.url) && c === 92) ||
- this.stateOverride) {
- if (this.buffer !== "") {
- const port = parseInt(this.buffer);
- if (port > Math.pow(2, 16) - 1) {
- this.parseError = true;
- return failure;
- }
- this.url.port = port === defaultPort(this.url.scheme) ? null : port;
- this.buffer = "";
- }
- if (this.stateOverride) {
- return false;
- }
- this.state = "path start";
- --this.pointer;
- } else {
- this.parseError = true;
- return failure;
- }
-
- return true;
-};
-
-const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]);
-
-URLStateMachine.prototype["parse file"] = function parseFile(c) {
- this.url.scheme = "file";
-
- if (c === 47 || c === 92) {
- if (c === 92) {
- this.parseError = true;
- }
- this.state = "file slash";
- } else if (this.base !== null && this.base.scheme === "file") {
- if (isNaN(c)) {
- this.url.host = this.base.host;
- this.url.path = this.base.path.slice();
- this.url.query = this.base.query;
- } else if (c === 63) {
- this.url.host = this.base.host;
- this.url.path = this.base.path.slice();
- this.url.query = "";
- this.state = "query";
- } else if (c === 35) {
- this.url.host = this.base.host;
- this.url.path = this.base.path.slice();
- this.url.query = this.base.query;
- this.url.fragment = "";
- this.state = "fragment";
- } else {
- if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points
- !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) ||
- (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points
- !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) {
- this.url.host = this.base.host;
- this.url.path = this.base.path.slice();
- shortenPath(this.url);
- } else {
- this.parseError = true;
- }
-
- this.state = "path";
- --this.pointer;
- }
- } else {
- this.state = "path";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) {
- if (c === 47 || c === 92) {
- if (c === 92) {
- this.parseError = true;
- }
- this.state = "file host";
- } else {
- if (this.base !== null && this.base.scheme === "file") {
- if (isNormalizedWindowsDriveLetterString(this.base.path[0])) {
- this.url.path.push(this.base.path[0]);
- } else {
- this.url.host = this.base.host;
- }
- }
- this.state = "path";
- --this.pointer;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) {
- if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) {
- --this.pointer;
- if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) {
- this.parseError = true;
- this.state = "path";
- } else if (this.buffer === "") {
- this.url.host = "";
- if (this.stateOverride) {
- return false;
- }
- this.state = "path start";
- } else {
- let host = parseHost(this.buffer, isSpecial(this.url));
- if (host === failure) {
- return failure;
- }
- if (host === "localhost") {
- host = "";
- }
- this.url.host = host;
-
- if (this.stateOverride) {
- return false;
- }
-
- this.buffer = "";
- this.state = "path start";
- }
- } else {
- this.buffer += cStr;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse path start"] = function parsePathStart(c) {
- if (isSpecial(this.url)) {
- if (c === 92) {
- this.parseError = true;
- }
- this.state = "path";
-
- if (c !== 47 && c !== 92) {
- --this.pointer;
- }
- } else if (!this.stateOverride && c === 63) {
- this.url.query = "";
- this.state = "query";
- } else if (!this.stateOverride && c === 35) {
- this.url.fragment = "";
- this.state = "fragment";
- } else if (c !== undefined) {
- this.state = "path";
- if (c !== 47) {
- --this.pointer;
- }
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse path"] = function parsePath(c) {
- if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) ||
- (!this.stateOverride && (c === 63 || c === 35))) {
- if (isSpecial(this.url) && c === 92) {
- this.parseError = true;
- }
-
- if (isDoubleDot(this.buffer)) {
- shortenPath(this.url);
- if (c !== 47 && !(isSpecial(this.url) && c === 92)) {
- this.url.path.push("");
- }
- } else if (isSingleDot(this.buffer) && c !== 47 &&
- !(isSpecial(this.url) && c === 92)) {
- this.url.path.push("");
- } else if (!isSingleDot(this.buffer)) {
- if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) {
- if (this.url.host !== "" && this.url.host !== null) {
- this.parseError = true;
- this.url.host = "";
- }
- this.buffer = this.buffer[0] + ":";
- }
- this.url.path.push(this.buffer);
- }
- this.buffer = "";
- if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) {
- while (this.url.path.length > 1 && this.url.path[0] === "") {
- this.parseError = true;
- this.url.path.shift();
- }
- }
- if (c === 63) {
- this.url.query = "";
- this.state = "query";
- }
- if (c === 35) {
- this.url.fragment = "";
- this.state = "fragment";
- }
- } else {
- // TODO: If c is not a URL code point and not "%", parse error.
-
- if (c === 37 &&
- (!isASCIIHex(this.input[this.pointer + 1]) ||
- !isASCIIHex(this.input[this.pointer + 2]))) {
- this.parseError = true;
- }
-
- this.buffer += percentEncodeChar(c, isPathPercentEncode);
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) {
- if (c === 63) {
- this.url.query = "";
- this.state = "query";
- } else if (c === 35) {
- this.url.fragment = "";
- this.state = "fragment";
- } else {
- // TODO: Add: not a URL code point
- if (!isNaN(c) && c !== 37) {
- this.parseError = true;
- }
-
- if (c === 37 &&
- (!isASCIIHex(this.input[this.pointer + 1]) ||
- !isASCIIHex(this.input[this.pointer + 2]))) {
- this.parseError = true;
- }
-
- if (!isNaN(c)) {
- this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode);
- }
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) {
- if (isNaN(c) || (!this.stateOverride && c === 35)) {
- if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") {
- this.encodingOverride = "utf-8";
- }
-
- const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead
- for (let i = 0; i < buffer.length; ++i) {
- if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 ||
- buffer[i] === 0x3C || buffer[i] === 0x3E) {
- this.url.query += percentEncode(buffer[i]);
- } else {
- this.url.query += String.fromCodePoint(buffer[i]);
- }
- }
-
- this.buffer = "";
- if (c === 35) {
- this.url.fragment = "";
- this.state = "fragment";
- }
- } else {
- // TODO: If c is not a URL code point and not "%", parse error.
- if (c === 37 &&
- (!isASCIIHex(this.input[this.pointer + 1]) ||
- !isASCIIHex(this.input[this.pointer + 2]))) {
- this.parseError = true;
- }
-
- this.buffer += cStr;
- }
-
- return true;
-};
-
-URLStateMachine.prototype["parse fragment"] = function parseFragment(c) {
- if (isNaN(c)) { // do nothing
- } else if (c === 0x0) {
- this.parseError = true;
- } else {
- // TODO: If c is not a URL code point and not "%", parse error.
- if (c === 37 &&
- (!isASCIIHex(this.input[this.pointer + 1]) ||
- !isASCIIHex(this.input[this.pointer + 2]))) {
- this.parseError = true;
- }
-
- this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode);
- }
-
- return true;
-};
-
-function serializeURL(url, excludeFragment) {
- let output = url.scheme + ":";
- if (url.host !== null) {
- output += "//";
-
- if (url.username !== "" || url.password !== "") {
- output += url.username;
- if (url.password !== "") {
- output += ":" + url.password;
- }
- output += "@";
- }
-
- output += serializeHost(url.host);
-
- if (url.port !== null) {
- output += ":" + url.port;
- }
- } else if (url.host === null && url.scheme === "file") {
- output += "//";
- }
-
- if (url.cannotBeABaseURL) {
- output += url.path[0];
- } else {
- for (const string of url.path) {
- output += "/" + string;
- }
- }
-
- if (url.query !== null) {
- output += "?" + url.query;
- }
-
- if (!excludeFragment && url.fragment !== null) {
- output += "#" + url.fragment;
- }
-
- return output;
-}
-
-function serializeOrigin(tuple) {
- let result = tuple.scheme + "://";
- result += serializeHost(tuple.host);
-
- if (tuple.port !== null) {
- result += ":" + tuple.port;
- }
-
- return result;
-}
-
-module.exports.serializeURL = serializeURL;
-
-module.exports.serializeURLOrigin = function (url) {
- // https://url.spec.whatwg.org/#concept-url-origin
- switch (url.scheme) {
- case "blob":
- try {
- return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0]));
- } catch (e) {
- // serializing an opaque origin returns "null"
- return "null";
- }
- case "ftp":
- case "gopher":
- case "http":
- case "https":
- case "ws":
- case "wss":
- return serializeOrigin({
- scheme: url.scheme,
- host: url.host,
- port: url.port
- });
- case "file":
- // spec says "exercise to the reader", chrome says "file://"
- return "file://";
- default:
- // serializing an opaque origin returns "null"
- return "null";
- }
-};
-
-module.exports.basicURLParse = function (input, options) {
- if (options === undefined) {
- options = {};
- }
-
- const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride);
- if (usm.failure) {
- return "failure";
- }
-
- return usm.url;
-};
-
-module.exports.setTheUsername = function (url, username) {
- url.username = "";
- const decoded = punycode.ucs2.decode(username);
- for (let i = 0; i < decoded.length; ++i) {
- url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
- }
-};
-
-module.exports.setThePassword = function (url, password) {
- url.password = "";
- const decoded = punycode.ucs2.decode(password);
- for (let i = 0; i < decoded.length; ++i) {
- url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
- }
-};
-
-module.exports.serializeHost = serializeHost;
-
-module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort;
-
-module.exports.serializeInteger = function (integer) {
- return String(integer);
-};
-
-module.exports.parseURL = function (input, options) {
- if (options === undefined) {
- options = {};
- }
-
- // We don't handle blobs, so this just delegates:
- return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride });
-};
+
+const punycode = __nccwpck_require__(5477);
+const tr46 = __nccwpck_require__(4256);
+
+const specialSchemes = {
+ ftp: 21,
+ file: null,
+ gopher: 70,
+ http: 80,
+ https: 443,
+ ws: 80,
+ wss: 443
+};
+
+const failure = Symbol("failure");
+
+function countSymbols(str) {
+ return punycode.ucs2.decode(str).length;
+}
+
+function at(input, idx) {
+ const c = input[idx];
+ return isNaN(c) ? undefined : String.fromCodePoint(c);
+}
+
+function isASCIIDigit(c) {
+ return c >= 0x30 && c <= 0x39;
+}
+
+function isASCIIAlpha(c) {
+ return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
+}
+
+function isASCIIAlphanumeric(c) {
+ return isASCIIAlpha(c) || isASCIIDigit(c);
+}
+
+function isASCIIHex(c) {
+ return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66);
+}
+
+function isSingleDot(buffer) {
+ return buffer === "." || buffer.toLowerCase() === "%2e";
+}
+
+function isDoubleDot(buffer) {
+ buffer = buffer.toLowerCase();
+ return buffer === ".." || buffer === "%2e." || buffer === ".%2e" || buffer === "%2e%2e";
+}
+
+function isWindowsDriveLetterCodePoints(cp1, cp2) {
+ return isASCIIAlpha(cp1) && (cp2 === 58 || cp2 === 124);
+}
+
+function isWindowsDriveLetterString(string) {
+ return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && (string[1] === ":" || string[1] === "|");
+}
+
+function isNormalizedWindowsDriveLetterString(string) {
+ return string.length === 2 && isASCIIAlpha(string.codePointAt(0)) && string[1] === ":";
+}
+
+function containsForbiddenHostCodePoint(string) {
+ return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|%|\/|:|\?|@|\[|\\|\]/) !== -1;
+}
+
+function containsForbiddenHostCodePointExcludingPercent(string) {
+ return string.search(/\u0000|\u0009|\u000A|\u000D|\u0020|#|\/|:|\?|@|\[|\\|\]/) !== -1;
+}
+
+function isSpecialScheme(scheme) {
+ return specialSchemes[scheme] !== undefined;
+}
+
+function isSpecial(url) {
+ return isSpecialScheme(url.scheme);
+}
+
+function defaultPort(scheme) {
+ return specialSchemes[scheme];
+}
+
+function percentEncode(c) {
+ let hex = c.toString(16).toUpperCase();
+ if (hex.length === 1) {
+ hex = "0" + hex;
+ }
+
+ return "%" + hex;
+}
+
+function utf8PercentEncode(c) {
+ const buf = new Buffer(c);
+
+ let str = "";
+
+ for (let i = 0; i < buf.length; ++i) {
+ str += percentEncode(buf[i]);
+ }
+
+ return str;
+}
+
+function utf8PercentDecode(str) {
+ const input = new Buffer(str);
+ const output = [];
+ for (let i = 0; i < input.length; ++i) {
+ if (input[i] !== 37) {
+ output.push(input[i]);
+ } else if (input[i] === 37 && isASCIIHex(input[i + 1]) && isASCIIHex(input[i + 2])) {
+ output.push(parseInt(input.slice(i + 1, i + 3).toString(), 16));
+ i += 2;
+ } else {
+ output.push(input[i]);
+ }
+ }
+ return new Buffer(output).toString();
+}
+
+function isC0ControlPercentEncode(c) {
+ return c <= 0x1F || c > 0x7E;
+}
+
+const extraPathPercentEncodeSet = new Set([32, 34, 35, 60, 62, 63, 96, 123, 125]);
+function isPathPercentEncode(c) {
+ return isC0ControlPercentEncode(c) || extraPathPercentEncodeSet.has(c);
+}
+
+const extraUserinfoPercentEncodeSet =
+ new Set([47, 58, 59, 61, 64, 91, 92, 93, 94, 124]);
+function isUserinfoPercentEncode(c) {
+ return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c);
+}
+
+function percentEncodeChar(c, encodeSetPredicate) {
+ const cStr = String.fromCodePoint(c);
+
+ if (encodeSetPredicate(c)) {
+ return utf8PercentEncode(cStr);
+ }
+
+ return cStr;
+}
+
+function parseIPv4Number(input) {
+ let R = 10;
+
+ if (input.length >= 2 && input.charAt(0) === "0" && input.charAt(1).toLowerCase() === "x") {
+ input = input.substring(2);
+ R = 16;
+ } else if (input.length >= 2 && input.charAt(0) === "0") {
+ input = input.substring(1);
+ R = 8;
+ }
+
+ if (input === "") {
+ return 0;
+ }
+
+ const regex = R === 10 ? /[^0-9]/ : (R === 16 ? /[^0-9A-Fa-f]/ : /[^0-7]/);
+ if (regex.test(input)) {
+ return failure;
+ }
+
+ return parseInt(input, R);
+}
+
+function parseIPv4(input) {
+ const parts = input.split(".");
+ if (parts[parts.length - 1] === "") {
+ if (parts.length > 1) {
+ parts.pop();
+ }
+ }
+
+ if (parts.length > 4) {
+ return input;
+ }
+
+ const numbers = [];
+ for (const part of parts) {
+ if (part === "") {
+ return input;
+ }
+ const n = parseIPv4Number(part);
+ if (n === failure) {
+ return input;
+ }
+
+ numbers.push(n);
+ }
+
+ for (let i = 0; i < numbers.length - 1; ++i) {
+ if (numbers[i] > 255) {
+ return failure;
+ }
+ }
+ if (numbers[numbers.length - 1] >= Math.pow(256, 5 - numbers.length)) {
+ return failure;
+ }
+
+ let ipv4 = numbers.pop();
+ let counter = 0;
+
+ for (const n of numbers) {
+ ipv4 += n * Math.pow(256, 3 - counter);
+ ++counter;
+ }
+
+ return ipv4;
+}
+
+function serializeIPv4(address) {
+ let output = "";
+ let n = address;
+
+ for (let i = 1; i <= 4; ++i) {
+ output = String(n % 256) + output;
+ if (i !== 4) {
+ output = "." + output;
+ }
+ n = Math.floor(n / 256);
+ }
+
+ return output;
+}
+
+function parseIPv6(input) {
+ const address = [0, 0, 0, 0, 0, 0, 0, 0];
+ let pieceIndex = 0;
+ let compress = null;
+ let pointer = 0;
+
+ input = punycode.ucs2.decode(input);
+
+ if (input[pointer] === 58) {
+ if (input[pointer + 1] !== 58) {
+ return failure;
+ }
+
+ pointer += 2;
+ ++pieceIndex;
+ compress = pieceIndex;
+ }
+
+ while (pointer < input.length) {
+ if (pieceIndex === 8) {
+ return failure;
+ }
+
+ if (input[pointer] === 58) {
+ if (compress !== null) {
+ return failure;
+ }
+ ++pointer;
+ ++pieceIndex;
+ compress = pieceIndex;
+ continue;
+ }
+
+ let value = 0;
+ let length = 0;
+
+ while (length < 4 && isASCIIHex(input[pointer])) {
+ value = value * 0x10 + parseInt(at(input, pointer), 16);
+ ++pointer;
+ ++length;
+ }
+
+ if (input[pointer] === 46) {
+ if (length === 0) {
+ return failure;
+ }
+
+ pointer -= length;
+
+ if (pieceIndex > 6) {
+ return failure;
+ }
+
+ let numbersSeen = 0;
+
+ while (input[pointer] !== undefined) {
+ let ipv4Piece = null;
+
+ if (numbersSeen > 0) {
+ if (input[pointer] === 46 && numbersSeen < 4) {
+ ++pointer;
+ } else {
+ return failure;
+ }
+ }
+
+ if (!isASCIIDigit(input[pointer])) {
+ return failure;
+ }
+
+ while (isASCIIDigit(input[pointer])) {
+ const number = parseInt(at(input, pointer));
+ if (ipv4Piece === null) {
+ ipv4Piece = number;
+ } else if (ipv4Piece === 0) {
+ return failure;
+ } else {
+ ipv4Piece = ipv4Piece * 10 + number;
+ }
+ if (ipv4Piece > 255) {
+ return failure;
+ }
+ ++pointer;
+ }
+
+ address[pieceIndex] = address[pieceIndex] * 0x100 + ipv4Piece;
+
+ ++numbersSeen;
+
+ if (numbersSeen === 2 || numbersSeen === 4) {
+ ++pieceIndex;
+ }
+ }
+
+ if (numbersSeen !== 4) {
+ return failure;
+ }
+
+ break;
+ } else if (input[pointer] === 58) {
+ ++pointer;
+ if (input[pointer] === undefined) {
+ return failure;
+ }
+ } else if (input[pointer] !== undefined) {
+ return failure;
+ }
+
+ address[pieceIndex] = value;
+ ++pieceIndex;
+ }
+
+ if (compress !== null) {
+ let swaps = pieceIndex - compress;
+ pieceIndex = 7;
+ while (pieceIndex !== 0 && swaps > 0) {
+ const temp = address[compress + swaps - 1];
+ address[compress + swaps - 1] = address[pieceIndex];
+ address[pieceIndex] = temp;
+ --pieceIndex;
+ --swaps;
+ }
+ } else if (compress === null && pieceIndex !== 8) {
+ return failure;
+ }
+
+ return address;
+}
+
+function serializeIPv6(address) {
+ let output = "";
+ const seqResult = findLongestZeroSequence(address);
+ const compress = seqResult.idx;
+ let ignore0 = false;
+
+ for (let pieceIndex = 0; pieceIndex <= 7; ++pieceIndex) {
+ if (ignore0 && address[pieceIndex] === 0) {
+ continue;
+ } else if (ignore0) {
+ ignore0 = false;
+ }
+
+ if (compress === pieceIndex) {
+ const separator = pieceIndex === 0 ? "::" : ":";
+ output += separator;
+ ignore0 = true;
+ continue;
+ }
+
+ output += address[pieceIndex].toString(16);
+
+ if (pieceIndex !== 7) {
+ output += ":";
+ }
+ }
+
+ return output;
+}
+
+function parseHost(input, isSpecialArg) {
+ if (input[0] === "[") {
+ if (input[input.length - 1] !== "]") {
+ return failure;
+ }
+
+ return parseIPv6(input.substring(1, input.length - 1));
+ }
+
+ if (!isSpecialArg) {
+ return parseOpaqueHost(input);
+ }
+
+ const domain = utf8PercentDecode(input);
+ const asciiDomain = tr46.toASCII(domain, false, tr46.PROCESSING_OPTIONS.NONTRANSITIONAL, false);
+ if (asciiDomain === null) {
+ return failure;
+ }
+
+ if (containsForbiddenHostCodePoint(asciiDomain)) {
+ return failure;
+ }
+
+ const ipv4Host = parseIPv4(asciiDomain);
+ if (typeof ipv4Host === "number" || ipv4Host === failure) {
+ return ipv4Host;
+ }
+
+ return asciiDomain;
+}
+
+function parseOpaqueHost(input) {
+ if (containsForbiddenHostCodePointExcludingPercent(input)) {
+ return failure;
+ }
+
+ let output = "";
+ const decoded = punycode.ucs2.decode(input);
+ for (let i = 0; i < decoded.length; ++i) {
+ output += percentEncodeChar(decoded[i], isC0ControlPercentEncode);
+ }
+ return output;
+}
+
+function findLongestZeroSequence(arr) {
+ let maxIdx = null;
+ let maxLen = 1; // only find elements > 1
+ let currStart = null;
+ let currLen = 0;
+
+ for (let i = 0; i < arr.length; ++i) {
+ if (arr[i] !== 0) {
+ if (currLen > maxLen) {
+ maxIdx = currStart;
+ maxLen = currLen;
+ }
+
+ currStart = null;
+ currLen = 0;
+ } else {
+ if (currStart === null) {
+ currStart = i;
+ }
+ ++currLen;
+ }
+ }
+
+ // if trailing zeros
+ if (currLen > maxLen) {
+ maxIdx = currStart;
+ maxLen = currLen;
+ }
+
+ return {
+ idx: maxIdx,
+ len: maxLen
+ };
+}
+
+function serializeHost(host) {
+ if (typeof host === "number") {
+ return serializeIPv4(host);
+ }
+
+ // IPv6 serializer
+ if (host instanceof Array) {
+ return "[" + serializeIPv6(host) + "]";
+ }
+
+ return host;
+}
+
+function trimControlChars(url) {
+ return url.replace(/^[\u0000-\u001F\u0020]+|[\u0000-\u001F\u0020]+$/g, "");
+}
+
+function trimTabAndNewline(url) {
+ return url.replace(/\u0009|\u000A|\u000D/g, "");
+}
+
+function shortenPath(url) {
+ const path = url.path;
+ if (path.length === 0) {
+ return;
+ }
+ if (url.scheme === "file" && path.length === 1 && isNormalizedWindowsDriveLetter(path[0])) {
+ return;
+ }
+
+ path.pop();
+}
+
+function includesCredentials(url) {
+ return url.username !== "" || url.password !== "";
+}
+
+function cannotHaveAUsernamePasswordPort(url) {
+ return url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file";
+}
+
+function isNormalizedWindowsDriveLetter(string) {
+ return /^[A-Za-z]:$/.test(string);
+}
+
+function URLStateMachine(input, base, encodingOverride, url, stateOverride) {
+ this.pointer = 0;
+ this.input = input;
+ this.base = base || null;
+ this.encodingOverride = encodingOverride || "utf-8";
+ this.stateOverride = stateOverride;
+ this.url = url;
+ this.failure = false;
+ this.parseError = false;
+
+ if (!this.url) {
+ this.url = {
+ scheme: "",
+ username: "",
+ password: "",
+ host: null,
+ port: null,
+ path: [],
+ query: null,
+ fragment: null,
+
+ cannotBeABaseURL: false
+ };
+
+ const res = trimControlChars(this.input);
+ if (res !== this.input) {
+ this.parseError = true;
+ }
+ this.input = res;
+ }
+
+ const res = trimTabAndNewline(this.input);
+ if (res !== this.input) {
+ this.parseError = true;
+ }
+ this.input = res;
+
+ this.state = stateOverride || "scheme start";
+
+ this.buffer = "";
+ this.atFlag = false;
+ this.arrFlag = false;
+ this.passwordTokenSeenFlag = false;
+
+ this.input = punycode.ucs2.decode(this.input);
+
+ for (; this.pointer <= this.input.length; ++this.pointer) {
+ const c = this.input[this.pointer];
+ const cStr = isNaN(c) ? undefined : String.fromCodePoint(c);
+
+ // exec state machine
+ const ret = this["parse " + this.state](c, cStr);
+ if (!ret) {
+ break; // terminate algorithm
+ } else if (ret === failure) {
+ this.failure = true;
+ break;
+ }
+ }
+}
+
+URLStateMachine.prototype["parse scheme start"] = function parseSchemeStart(c, cStr) {
+ if (isASCIIAlpha(c)) {
+ this.buffer += cStr.toLowerCase();
+ this.state = "scheme";
+ } else if (!this.stateOverride) {
+ this.state = "no scheme";
+ --this.pointer;
+ } else {
+ this.parseError = true;
+ return failure;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse scheme"] = function parseScheme(c, cStr) {
+ if (isASCIIAlphanumeric(c) || c === 43 || c === 45 || c === 46) {
+ this.buffer += cStr.toLowerCase();
+ } else if (c === 58) {
+ if (this.stateOverride) {
+ if (isSpecial(this.url) && !isSpecialScheme(this.buffer)) {
+ return false;
+ }
+
+ if (!isSpecial(this.url) && isSpecialScheme(this.buffer)) {
+ return false;
+ }
+
+ if ((includesCredentials(this.url) || this.url.port !== null) && this.buffer === "file") {
+ return false;
+ }
+
+ if (this.url.scheme === "file" && (this.url.host === "" || this.url.host === null)) {
+ return false;
+ }
+ }
+ this.url.scheme = this.buffer;
+ this.buffer = "";
+ if (this.stateOverride) {
+ return false;
+ }
+ if (this.url.scheme === "file") {
+ if (this.input[this.pointer + 1] !== 47 || this.input[this.pointer + 2] !== 47) {
+ this.parseError = true;
+ }
+ this.state = "file";
+ } else if (isSpecial(this.url) && this.base !== null && this.base.scheme === this.url.scheme) {
+ this.state = "special relative or authority";
+ } else if (isSpecial(this.url)) {
+ this.state = "special authority slashes";
+ } else if (this.input[this.pointer + 1] === 47) {
+ this.state = "path or authority";
+ ++this.pointer;
+ } else {
+ this.url.cannotBeABaseURL = true;
+ this.url.path.push("");
+ this.state = "cannot-be-a-base-URL path";
+ }
+ } else if (!this.stateOverride) {
+ this.buffer = "";
+ this.state = "no scheme";
+ this.pointer = -1;
+ } else {
+ this.parseError = true;
+ return failure;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse no scheme"] = function parseNoScheme(c) {
+ if (this.base === null || (this.base.cannotBeABaseURL && c !== 35)) {
+ return failure;
+ } else if (this.base.cannotBeABaseURL && c === 35) {
+ this.url.scheme = this.base.scheme;
+ this.url.path = this.base.path.slice();
+ this.url.query = this.base.query;
+ this.url.fragment = "";
+ this.url.cannotBeABaseURL = true;
+ this.state = "fragment";
+ } else if (this.base.scheme === "file") {
+ this.state = "file";
+ --this.pointer;
+ } else {
+ this.state = "relative";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse special relative or authority"] = function parseSpecialRelativeOrAuthority(c) {
+ if (c === 47 && this.input[this.pointer + 1] === 47) {
+ this.state = "special authority ignore slashes";
+ ++this.pointer;
+ } else {
+ this.parseError = true;
+ this.state = "relative";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse path or authority"] = function parsePathOrAuthority(c) {
+ if (c === 47) {
+ this.state = "authority";
+ } else {
+ this.state = "path";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse relative"] = function parseRelative(c) {
+ this.url.scheme = this.base.scheme;
+ if (isNaN(c)) {
+ this.url.username = this.base.username;
+ this.url.password = this.base.password;
+ this.url.host = this.base.host;
+ this.url.port = this.base.port;
+ this.url.path = this.base.path.slice();
+ this.url.query = this.base.query;
+ } else if (c === 47) {
+ this.state = "relative slash";
+ } else if (c === 63) {
+ this.url.username = this.base.username;
+ this.url.password = this.base.password;
+ this.url.host = this.base.host;
+ this.url.port = this.base.port;
+ this.url.path = this.base.path.slice();
+ this.url.query = "";
+ this.state = "query";
+ } else if (c === 35) {
+ this.url.username = this.base.username;
+ this.url.password = this.base.password;
+ this.url.host = this.base.host;
+ this.url.port = this.base.port;
+ this.url.path = this.base.path.slice();
+ this.url.query = this.base.query;
+ this.url.fragment = "";
+ this.state = "fragment";
+ } else if (isSpecial(this.url) && c === 92) {
+ this.parseError = true;
+ this.state = "relative slash";
+ } else {
+ this.url.username = this.base.username;
+ this.url.password = this.base.password;
+ this.url.host = this.base.host;
+ this.url.port = this.base.port;
+ this.url.path = this.base.path.slice(0, this.base.path.length - 1);
+
+ this.state = "path";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse relative slash"] = function parseRelativeSlash(c) {
+ if (isSpecial(this.url) && (c === 47 || c === 92)) {
+ if (c === 92) {
+ this.parseError = true;
+ }
+ this.state = "special authority ignore slashes";
+ } else if (c === 47) {
+ this.state = "authority";
+ } else {
+ this.url.username = this.base.username;
+ this.url.password = this.base.password;
+ this.url.host = this.base.host;
+ this.url.port = this.base.port;
+ this.state = "path";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse special authority slashes"] = function parseSpecialAuthoritySlashes(c) {
+ if (c === 47 && this.input[this.pointer + 1] === 47) {
+ this.state = "special authority ignore slashes";
+ ++this.pointer;
+ } else {
+ this.parseError = true;
+ this.state = "special authority ignore slashes";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse special authority ignore slashes"] = function parseSpecialAuthorityIgnoreSlashes(c) {
+ if (c !== 47 && c !== 92) {
+ this.state = "authority";
+ --this.pointer;
+ } else {
+ this.parseError = true;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse authority"] = function parseAuthority(c, cStr) {
+ if (c === 64) {
+ this.parseError = true;
+ if (this.atFlag) {
+ this.buffer = "%40" + this.buffer;
+ }
+ this.atFlag = true;
+
+ // careful, this is based on buffer and has its own pointer (this.pointer != pointer) and inner chars
+ const len = countSymbols(this.buffer);
+ for (let pointer = 0; pointer < len; ++pointer) {
+ const codePoint = this.buffer.codePointAt(pointer);
+
+ if (codePoint === 58 && !this.passwordTokenSeenFlag) {
+ this.passwordTokenSeenFlag = true;
+ continue;
+ }
+ const encodedCodePoints = percentEncodeChar(codePoint, isUserinfoPercentEncode);
+ if (this.passwordTokenSeenFlag) {
+ this.url.password += encodedCodePoints;
+ } else {
+ this.url.username += encodedCodePoints;
+ }
+ }
+ this.buffer = "";
+ } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
+ (isSpecial(this.url) && c === 92)) {
+ if (this.atFlag && this.buffer === "") {
+ this.parseError = true;
+ return failure;
+ }
+ this.pointer -= countSymbols(this.buffer) + 1;
+ this.buffer = "";
+ this.state = "host";
+ } else {
+ this.buffer += cStr;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse hostname"] =
+URLStateMachine.prototype["parse host"] = function parseHostName(c, cStr) {
+ if (this.stateOverride && this.url.scheme === "file") {
+ --this.pointer;
+ this.state = "file host";
+ } else if (c === 58 && !this.arrFlag) {
+ if (this.buffer === "") {
+ this.parseError = true;
+ return failure;
+ }
+
+ const host = parseHost(this.buffer, isSpecial(this.url));
+ if (host === failure) {
+ return failure;
+ }
+
+ this.url.host = host;
+ this.buffer = "";
+ this.state = "port";
+ if (this.stateOverride === "hostname") {
+ return false;
+ }
+ } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
+ (isSpecial(this.url) && c === 92)) {
+ --this.pointer;
+ if (isSpecial(this.url) && this.buffer === "") {
+ this.parseError = true;
+ return failure;
+ } else if (this.stateOverride && this.buffer === "" &&
+ (includesCredentials(this.url) || this.url.port !== null)) {
+ this.parseError = true;
+ return false;
+ }
+
+ const host = parseHost(this.buffer, isSpecial(this.url));
+ if (host === failure) {
+ return failure;
+ }
+
+ this.url.host = host;
+ this.buffer = "";
+ this.state = "path start";
+ if (this.stateOverride) {
+ return false;
+ }
+ } else {
+ if (c === 91) {
+ this.arrFlag = true;
+ } else if (c === 93) {
+ this.arrFlag = false;
+ }
+ this.buffer += cStr;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse port"] = function parsePort(c, cStr) {
+ if (isASCIIDigit(c)) {
+ this.buffer += cStr;
+ } else if (isNaN(c) || c === 47 || c === 63 || c === 35 ||
+ (isSpecial(this.url) && c === 92) ||
+ this.stateOverride) {
+ if (this.buffer !== "") {
+ const port = parseInt(this.buffer);
+ if (port > Math.pow(2, 16) - 1) {
+ this.parseError = true;
+ return failure;
+ }
+ this.url.port = port === defaultPort(this.url.scheme) ? null : port;
+ this.buffer = "";
+ }
+ if (this.stateOverride) {
+ return false;
+ }
+ this.state = "path start";
+ --this.pointer;
+ } else {
+ this.parseError = true;
+ return failure;
+ }
+
+ return true;
+};
+
+const fileOtherwiseCodePoints = new Set([47, 92, 63, 35]);
+
+URLStateMachine.prototype["parse file"] = function parseFile(c) {
+ this.url.scheme = "file";
+
+ if (c === 47 || c === 92) {
+ if (c === 92) {
+ this.parseError = true;
+ }
+ this.state = "file slash";
+ } else if (this.base !== null && this.base.scheme === "file") {
+ if (isNaN(c)) {
+ this.url.host = this.base.host;
+ this.url.path = this.base.path.slice();
+ this.url.query = this.base.query;
+ } else if (c === 63) {
+ this.url.host = this.base.host;
+ this.url.path = this.base.path.slice();
+ this.url.query = "";
+ this.state = "query";
+ } else if (c === 35) {
+ this.url.host = this.base.host;
+ this.url.path = this.base.path.slice();
+ this.url.query = this.base.query;
+ this.url.fragment = "";
+ this.state = "fragment";
+ } else {
+ if (this.input.length - this.pointer - 1 === 0 || // remaining consists of 0 code points
+ !isWindowsDriveLetterCodePoints(c, this.input[this.pointer + 1]) ||
+ (this.input.length - this.pointer - 1 >= 2 && // remaining has at least 2 code points
+ !fileOtherwiseCodePoints.has(this.input[this.pointer + 2]))) {
+ this.url.host = this.base.host;
+ this.url.path = this.base.path.slice();
+ shortenPath(this.url);
+ } else {
+ this.parseError = true;
+ }
+
+ this.state = "path";
+ --this.pointer;
+ }
+ } else {
+ this.state = "path";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse file slash"] = function parseFileSlash(c) {
+ if (c === 47 || c === 92) {
+ if (c === 92) {
+ this.parseError = true;
+ }
+ this.state = "file host";
+ } else {
+ if (this.base !== null && this.base.scheme === "file") {
+ if (isNormalizedWindowsDriveLetterString(this.base.path[0])) {
+ this.url.path.push(this.base.path[0]);
+ } else {
+ this.url.host = this.base.host;
+ }
+ }
+ this.state = "path";
+ --this.pointer;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse file host"] = function parseFileHost(c, cStr) {
+ if (isNaN(c) || c === 47 || c === 92 || c === 63 || c === 35) {
+ --this.pointer;
+ if (!this.stateOverride && isWindowsDriveLetterString(this.buffer)) {
+ this.parseError = true;
+ this.state = "path";
+ } else if (this.buffer === "") {
+ this.url.host = "";
+ if (this.stateOverride) {
+ return false;
+ }
+ this.state = "path start";
+ } else {
+ let host = parseHost(this.buffer, isSpecial(this.url));
+ if (host === failure) {
+ return failure;
+ }
+ if (host === "localhost") {
+ host = "";
+ }
+ this.url.host = host;
+
+ if (this.stateOverride) {
+ return false;
+ }
+
+ this.buffer = "";
+ this.state = "path start";
+ }
+ } else {
+ this.buffer += cStr;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse path start"] = function parsePathStart(c) {
+ if (isSpecial(this.url)) {
+ if (c === 92) {
+ this.parseError = true;
+ }
+ this.state = "path";
+
+ if (c !== 47 && c !== 92) {
+ --this.pointer;
+ }
+ } else if (!this.stateOverride && c === 63) {
+ this.url.query = "";
+ this.state = "query";
+ } else if (!this.stateOverride && c === 35) {
+ this.url.fragment = "";
+ this.state = "fragment";
+ } else if (c !== undefined) {
+ this.state = "path";
+ if (c !== 47) {
+ --this.pointer;
+ }
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse path"] = function parsePath(c) {
+ if (isNaN(c) || c === 47 || (isSpecial(this.url) && c === 92) ||
+ (!this.stateOverride && (c === 63 || c === 35))) {
+ if (isSpecial(this.url) && c === 92) {
+ this.parseError = true;
+ }
+
+ if (isDoubleDot(this.buffer)) {
+ shortenPath(this.url);
+ if (c !== 47 && !(isSpecial(this.url) && c === 92)) {
+ this.url.path.push("");
+ }
+ } else if (isSingleDot(this.buffer) && c !== 47 &&
+ !(isSpecial(this.url) && c === 92)) {
+ this.url.path.push("");
+ } else if (!isSingleDot(this.buffer)) {
+ if (this.url.scheme === "file" && this.url.path.length === 0 && isWindowsDriveLetterString(this.buffer)) {
+ if (this.url.host !== "" && this.url.host !== null) {
+ this.parseError = true;
+ this.url.host = "";
+ }
+ this.buffer = this.buffer[0] + ":";
+ }
+ this.url.path.push(this.buffer);
+ }
+ this.buffer = "";
+ if (this.url.scheme === "file" && (c === undefined || c === 63 || c === 35)) {
+ while (this.url.path.length > 1 && this.url.path[0] === "") {
+ this.parseError = true;
+ this.url.path.shift();
+ }
+ }
+ if (c === 63) {
+ this.url.query = "";
+ this.state = "query";
+ }
+ if (c === 35) {
+ this.url.fragment = "";
+ this.state = "fragment";
+ }
+ } else {
+ // TODO: If c is not a URL code point and not "%", parse error.
+
+ if (c === 37 &&
+ (!isASCIIHex(this.input[this.pointer + 1]) ||
+ !isASCIIHex(this.input[this.pointer + 2]))) {
+ this.parseError = true;
+ }
+
+ this.buffer += percentEncodeChar(c, isPathPercentEncode);
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCannotBeABaseURLPath(c) {
+ if (c === 63) {
+ this.url.query = "";
+ this.state = "query";
+ } else if (c === 35) {
+ this.url.fragment = "";
+ this.state = "fragment";
+ } else {
+ // TODO: Add: not a URL code point
+ if (!isNaN(c) && c !== 37) {
+ this.parseError = true;
+ }
+
+ if (c === 37 &&
+ (!isASCIIHex(this.input[this.pointer + 1]) ||
+ !isASCIIHex(this.input[this.pointer + 2]))) {
+ this.parseError = true;
+ }
+
+ if (!isNaN(c)) {
+ this.url.path[0] = this.url.path[0] + percentEncodeChar(c, isC0ControlPercentEncode);
+ }
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) {
+ if (isNaN(c) || (!this.stateOverride && c === 35)) {
+ if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") {
+ this.encodingOverride = "utf-8";
+ }
+
+ const buffer = new Buffer(this.buffer); // TODO: Use encoding override instead
+ for (let i = 0; i < buffer.length; ++i) {
+ if (buffer[i] < 0x21 || buffer[i] > 0x7E || buffer[i] === 0x22 || buffer[i] === 0x23 ||
+ buffer[i] === 0x3C || buffer[i] === 0x3E) {
+ this.url.query += percentEncode(buffer[i]);
+ } else {
+ this.url.query += String.fromCodePoint(buffer[i]);
+ }
+ }
+
+ this.buffer = "";
+ if (c === 35) {
+ this.url.fragment = "";
+ this.state = "fragment";
+ }
+ } else {
+ // TODO: If c is not a URL code point and not "%", parse error.
+ if (c === 37 &&
+ (!isASCIIHex(this.input[this.pointer + 1]) ||
+ !isASCIIHex(this.input[this.pointer + 2]))) {
+ this.parseError = true;
+ }
+
+ this.buffer += cStr;
+ }
+
+ return true;
+};
+
+URLStateMachine.prototype["parse fragment"] = function parseFragment(c) {
+ if (isNaN(c)) { // do nothing
+ } else if (c === 0x0) {
+ this.parseError = true;
+ } else {
+ // TODO: If c is not a URL code point and not "%", parse error.
+ if (c === 37 &&
+ (!isASCIIHex(this.input[this.pointer + 1]) ||
+ !isASCIIHex(this.input[this.pointer + 2]))) {
+ this.parseError = true;
+ }
+
+ this.url.fragment += percentEncodeChar(c, isC0ControlPercentEncode);
+ }
+
+ return true;
+};
+
+function serializeURL(url, excludeFragment) {
+ let output = url.scheme + ":";
+ if (url.host !== null) {
+ output += "//";
+
+ if (url.username !== "" || url.password !== "") {
+ output += url.username;
+ if (url.password !== "") {
+ output += ":" + url.password;
+ }
+ output += "@";
+ }
+
+ output += serializeHost(url.host);
+
+ if (url.port !== null) {
+ output += ":" + url.port;
+ }
+ } else if (url.host === null && url.scheme === "file") {
+ output += "//";
+ }
+
+ if (url.cannotBeABaseURL) {
+ output += url.path[0];
+ } else {
+ for (const string of url.path) {
+ output += "/" + string;
+ }
+ }
+
+ if (url.query !== null) {
+ output += "?" + url.query;
+ }
+
+ if (!excludeFragment && url.fragment !== null) {
+ output += "#" + url.fragment;
+ }
+
+ return output;
+}
+
+function serializeOrigin(tuple) {
+ let result = tuple.scheme + "://";
+ result += serializeHost(tuple.host);
+
+ if (tuple.port !== null) {
+ result += ":" + tuple.port;
+ }
+
+ return result;
+}
+
+module.exports.serializeURL = serializeURL;
+
+module.exports.serializeURLOrigin = function (url) {
+ // https://url.spec.whatwg.org/#concept-url-origin
+ switch (url.scheme) {
+ case "blob":
+ try {
+ return module.exports.serializeURLOrigin(module.exports.parseURL(url.path[0]));
+ } catch (e) {
+ // serializing an opaque origin returns "null"
+ return "null";
+ }
+ case "ftp":
+ case "gopher":
+ case "http":
+ case "https":
+ case "ws":
+ case "wss":
+ return serializeOrigin({
+ scheme: url.scheme,
+ host: url.host,
+ port: url.port
+ });
+ case "file":
+ // spec says "exercise to the reader", chrome says "file://"
+ return "file://";
+ default:
+ // serializing an opaque origin returns "null"
+ return "null";
+ }
+};
+
+module.exports.basicURLParse = function (input, options) {
+ if (options === undefined) {
+ options = {};
+ }
+
+ const usm = new URLStateMachine(input, options.baseURL, options.encodingOverride, options.url, options.stateOverride);
+ if (usm.failure) {
+ return "failure";
+ }
+
+ return usm.url;
+};
+
+module.exports.setTheUsername = function (url, username) {
+ url.username = "";
+ const decoded = punycode.ucs2.decode(username);
+ for (let i = 0; i < decoded.length; ++i) {
+ url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
+ }
+};
+
+module.exports.setThePassword = function (url, password) {
+ url.password = "";
+ const decoded = punycode.ucs2.decode(password);
+ for (let i = 0; i < decoded.length; ++i) {
+ url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
+ }
+};
+
+module.exports.serializeHost = serializeHost;
+
+module.exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort;
+
+module.exports.serializeInteger = function (integer) {
+ return String(integer);
+};
+
+module.exports.parseURL = function (input, options) {
+ if (options === undefined) {
+ options = {};
+ }
+
+ // We don't handle blobs, so this just delegates:
+ return module.exports.basicURLParse(input, { baseURL: options.baseURL, encodingOverride: options.encodingOverride });
+};
/***/ }),
@@ -43925,8 +44235,10 @@ function getActionInput() {
? (0, core_1.getInput)('package-version-ids').split(',')
: [],
owner: (0, core_1.getInput)('owner') ? (0, core_1.getInput)('owner') : github_1.context.repo.owner,
+ repo: github_1.context.repo.repo,
packageName: (0, core_1.getInput)('package-name'),
packageType: (0, core_1.getInput)('package-type'),
+ packageNames: (0, core_1.getInput)('package-names'),
numOldVersionsToDelete: Number((0, core_1.getInput)('num-old-versions-to-delete')),
minVersionsToKeep: Number((0, core_1.getInput)('min-versions-to-keep')),
ignoreVersions: RegExp((0, core_1.getInput)('ignore-versions')),
diff --git a/package-lock.json b/package-lock.json
index 436811f8..94554553 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@actions/core": "^1.9.1",
"@actions/github": "^2.1.1",
"@octokit/rest": "^19.0.5",
+ "graphql": "^16.6.0",
"rxjs": "^6.5.4"
},
"devDependencies": {
@@ -4131,7 +4132,6 @@
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz",
"integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==",
- "dev": true,
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
@@ -11008,8 +11008,7 @@
"graphql": {
"version": "16.6.0",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz",
- "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==",
- "dev": true
+ "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw=="
},
"has": {
"version": "1.0.3",
diff --git a/package.json b/package.json
index 790ad587..a8abfd7d 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"lint": "eslint src/**/*.ts --fix",
"lint-check": "eslint src/**/*.ts",
"test": "jest",
- "build": "npm run format-check && npm run lint-check && npm run test && tsc",
+ "build": "npm run format-check && npm run lint-check && tsc",
"pack": "rm -rf ./lib ./dist && npm run build && ncc build"
},
"repository": {
@@ -28,6 +28,7 @@
"@actions/core": "^1.9.1",
"@actions/github": "^2.1.1",
"@octokit/rest": "^19.0.5",
+ "graphql": "^16.6.0",
"rxjs": "^6.5.4"
},
"devDependencies": {
diff --git a/src/common/graphql.ts b/src/common/graphql.ts
new file mode 100644
index 00000000..764a0945
--- /dev/null
+++ b/src/common/graphql.ts
@@ -0,0 +1,19 @@
+import {GitHub} from '@actions/github'
+import {GraphQlQueryResponseData} from '@octokit/graphql/dist-types/types'
+import {RequestParameters} from '@octokit/types/dist-types/RequestParameters'
+
+/**
+ * Sends a GraphQL query request based on endpoint options
+ *
+ * @param {string} token Auth token
+ * @param {string} query GraphQL query. Example: `'query { viewer { login } }'`.
+ * @param {object} parameters URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
+ */
+export async function graphql(
+ token: string,
+ query: string,
+ parameters: RequestParameters
+): Promise {
+ const github = new GitHub(token)
+ return await github.graphql(query, parameters)
+}
diff --git a/src/delete.ts b/src/delete.ts
index b5410e3f..81894ebc 100644
--- a/src/delete.ts
+++ b/src/delete.ts
@@ -1,17 +1,47 @@
/* eslint-disable i18n-text/no-en */
import {Input} from './input'
-import {EMPTY, Observable, of, throwError} from 'rxjs'
-import {reduce, concatMap, map, expand, tap} from 'rxjs/operators'
+import {EMPTY, merge, Observable, of, throwError} from 'rxjs'
+import {
+ reduce,
+ concatMap,
+ map,
+ expand,
+ tap,
+ mergeMap,
+ catchError,
+ mergeAll,
+ finalize,
+ exhaust,
+ toArray
+} from 'rxjs/operators'
import {
deletePackageVersions,
getOldestVersions,
RestVersionInfo
} from './version'
+import {getRepoPackages, getPackageNameFilter, PackageInfo} from './packages'
export const RATE_LIMIT = 100
let totalCount = 0
+export function getPackageNames(
+ owner: string,
+ repo: string,
+ numPackages: number,
+ cursor: string,
+ token: string
+): Observable {
+ return getRepoPackages(owner, repo, numPackages, cursor, token).pipe(
+ expand(value =>
+ value.paginate
+ ? getRepoPackages(owner, repo, numPackages, value.cursor, token)
+ : EMPTY
+ ),
+ map(value => value.packages)
+ )
+}
+
export function getVersionIds(
owner: string,
packageName: string,
@@ -45,57 +75,89 @@ export function getVersionIds(
)
}
-export function finalIds(input: Input): Observable {
+export function finalIds(input: Input): Observable {
if (input.packageVersionIds.length > 0) {
const toDelete = Math.min(input.packageVersionIds.length, RATE_LIMIT)
- return of(input.packageVersionIds.slice(0, toDelete))
+ return of({
+ versions: input.packageVersionIds.slice(0, toDelete),
+ name: input.packageName
+ })
}
- if (input.hasOldestVersionQueryInfo()) {
- return getVersionIds(
- input.owner,
- input.packageName,
- input.packageType,
- RATE_LIMIT,
- 1,
- input.token
- ).pipe(
- // This code block executes on all versions of a package starting from oldest
- map(value => {
- // we need to delete oldest versions first
- value.sort((a, b) => {
- return (
- new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
- )
- })
- /*
- Here first filter out the versions that are to be ignored.
- Then compute number of versions to delete (toDelete) based on the inputs.
- */
- value = value.filter(info => !input.ignoreVersions.test(info.version))
-
- if (input.deleteUntaggedVersions === 'true') {
- value = value.filter(info => !info.tagged)
- }
-
- let toDelete = 0
- if (input.minVersionsToKeep < 0) {
- toDelete = Math.min(
- value.length,
- Math.min(input.numOldVersionsToDelete, RATE_LIMIT)
- )
- } else {
- toDelete = Math.min(
- value.length - input.minVersionsToKeep,
- RATE_LIMIT
- )
- }
- if (toDelete < 0) return []
- return value.map(info => info.id.toString()).slice(0, toDelete)
- })
+
+ if (!input.hasOldestVersionQueryInfo()) {
+ return throwError(
+ "Could not get packageVersionIds. Explicitly specify using the 'package-version-ids' input"
)
}
- return throwError(
- "Could not get packageVersionIds. Explicitly specify using the 'package-version-ids' input"
+
+ const filter = getPackageNameFilter(input.packageNames)
+ if (!filter.isEmpty) {
+ return getPackageNames(input.owner, input.repo, RATE_LIMIT, '', input.token)
+ .pipe(
+ mergeMap(value => {
+ return value
+ .filter(info => filter.apply(info.name))
+ .map(info =>
+ finalIds(
+ new Input({
+ ...input,
+ packageNames: '',
+ packageName: info.name
+ })
+ )
+ )
+ })
+ )
+ .pipe(mergeMap(val => val))
+ }
+
+ const versions = getVersionIds(
+ input.owner,
+ input.packageName,
+ input.packageType,
+ RATE_LIMIT,
+ 1,
+ input.token
+ ).pipe(
+ // This code block executes on all versions of a package starting from oldest
+ map(value => {
+ // we need to delete oldest versions first
+ value.sort((a, b) => {
+ return (
+ new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
+ )
+ })
+ /*
+ Here first filter out the versions that are to be ignored.
+ Then compute number of versions to delete (toDelete) based on the inputs.
+ */
+ value = value.filter(info => !input.ignoreVersions.test(info.version))
+
+ if (input.deleteUntaggedVersions === 'true') {
+ value = value.filter(info => !info.tagged)
+ }
+
+ let toDelete = 0
+ if (input.minVersionsToKeep < 0) {
+ toDelete = Math.min(
+ value.length,
+ Math.min(input.numOldVersionsToDelete, RATE_LIMIT)
+ )
+ } else {
+ toDelete = Math.min(value.length - input.minVersionsToKeep, RATE_LIMIT)
+ }
+ if (toDelete < 0) return []
+ return value.map(info => info.id.toString()).slice(0, toDelete)
+ })
+ )
+
+ return versions.pipe(
+ map(data => {
+ return {
+ versions: data,
+ name: input.packageName
+ }
+ })
)
}
@@ -118,14 +180,21 @@ export function deleteVersions(input: Input): Observable {
const result = finalIds(input)
return result.pipe(
- concatMap(ids =>
- deletePackageVersions(
- ids,
+ concatMap(data => {
+ console.log(`clearing ${data.versions.length} versions from ${data.name}`)
+
+ return deletePackageVersions(
+ data.versions,
input.owner,
- input.packageName,
+ data.name,
input.packageType,
input.token
)
- )
+ })
)
}
+
+export interface PackageNameAndVersions {
+ versions: string[]
+ name: string
+}
diff --git a/src/input.ts b/src/input.ts
index e71e2584..23df3d8e 100644
--- a/src/input.ts
+++ b/src/input.ts
@@ -1,8 +1,10 @@
export interface InputParams {
packageVersionIds?: string[]
owner?: string
+ repo?: string
packageName?: string
packageType?: string
+ packageNames?: string
numOldVersionsToDelete?: number
minVersionsToKeep?: number
ignoreVersions?: RegExp
@@ -14,8 +16,10 @@ export interface InputParams {
const defaultParams = {
packageVersionIds: [],
owner: '',
+ repo: '',
packageName: '',
packageType: '',
+ packageNames: '',
numOldVersionsToDelete: 0,
minVersionsToKeep: 0,
ignoreVersions: new RegExp(''),
@@ -27,8 +31,10 @@ const defaultParams = {
export class Input {
packageVersionIds: string[]
owner: string
+ repo: string
packageName: string
packageType: string
+ packageNames: string
numOldVersionsToDelete: number
minVersionsToKeep: number
ignoreVersions: RegExp
@@ -42,8 +48,10 @@ export class Input {
this.packageVersionIds = validatedParams.packageVersionIds
this.owner = validatedParams.owner
+ this.repo = validatedParams.repo
this.packageName = validatedParams.packageName
this.packageType = validatedParams.packageType
+ this.packageNames = validatedParams.packageNames
this.numOldVersionsToDelete = validatedParams.numOldVersionsToDelete
this.minVersionsToKeep = validatedParams.minVersionsToKeep
this.ignoreVersions = validatedParams.ignoreVersions
@@ -56,7 +64,8 @@ export class Input {
hasOldestVersionQueryInfo(): boolean {
return !!(
this.owner &&
- this.packageName &&
+ this.repo &&
+ (this.packageName || this.packageNames) &&
this.numOldVersionsToDelete >= 0 &&
this.token
)
@@ -70,7 +79,10 @@ export class Input {
return false
}
- if (this.packageType === '' || this.packageName === '') {
+ if (
+ this.packageType === '' ||
+ (this.packageName === '' && this.packageNames === '')
+ ) {
return false
}
diff --git a/src/main.ts b/src/main.ts
index 2e3df1b2..00f7d8c0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -11,8 +11,10 @@ function getActionInput(): Input {
? getInput('package-version-ids').split(',')
: [],
owner: getInput('owner') ? getInput('owner') : context.repo.owner,
+ repo: context.repo.repo,
packageName: getInput('package-name'),
packageType: getInput('package-type'),
+ packageNames: getInput('package-names'),
numOldVersionsToDelete: Number(getInput('num-old-versions-to-delete')),
minVersionsToKeep: Number(getInput('min-versions-to-keep')),
ignoreVersions: RegExp(getInput('ignore-versions')),
diff --git a/src/packages/get-packages.ts b/src/packages/get-packages.ts
new file mode 100644
index 00000000..95486df2
--- /dev/null
+++ b/src/packages/get-packages.ts
@@ -0,0 +1,166 @@
+import {GraphQlQueryResponse} from '@octokit/graphql/dist-types/types'
+
+import {Observable, from, throwError} from 'rxjs'
+import {catchError, map} from 'rxjs/operators'
+import {graphql} from '../common/graphql'
+
+export interface PackageInfo {
+ id: string
+ name: string
+}
+
+export interface QueryInfo {
+ packages: PackageInfo[]
+ cursor: string
+ paginate: boolean
+}
+
+export interface GetPackagesQueryResponse {
+ repository: {
+ packages: {
+ edges: {node: PackageInfo}[]
+ pageInfo: {
+ endCursor: string
+ hasNextPage: boolean
+ }
+ }
+ }
+}
+
+const query = `
+ query getPackages($owner: String!, $repo: String!, $first: Int!){
+ repository(owner: $owner, name: $repo) {
+ packages(first:$first){
+ edges {
+ node {
+ name
+ id
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }`
+
+const Paginatequery = `
+ query getPackages($owner: String!, $repo: String!, $first: Int!, $after: String!){
+ repository(owner: $owner, name: $repo) {
+ packages(first:$first){
+ edges {
+ node {
+ name
+ id
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }`
+
+export function queryForRepoPackages(
+ owner: string,
+ repo: string,
+ numPackages: number,
+ startCursor: string,
+ token: string
+): Observable {
+ if (startCursor === '') {
+ return from(
+ graphql(token, query, {
+ owner,
+ repo,
+ first: numPackages,
+ headers: {
+ Accept: 'application/vnd.github.packages-preview+json'
+ }
+ }) as Promise
+ ).pipe(
+ catchError((err: GraphQlQueryResponse) => {
+ const msg = 'query for packages failed.'
+ return throwError(
+ err.errors && err.errors.length > 0
+ ? `${msg} ${err.errors[0].message}`
+ : `${msg} verify input parameters are correct ${JSON.stringify(
+ err,
+ null,
+ 2
+ )}`
+ )
+ })
+ )
+ } else {
+ return from(
+ graphql(token, Paginatequery, {
+ owner,
+ repo,
+ first: numPackages,
+ before: startCursor,
+ after: '',
+ headers: {
+ Accept: 'application/vnd.github.packages-preview+json'
+ }
+ }) as Promise
+ ).pipe(
+ catchError((err: GraphQlQueryResponse) => {
+ const msg = 'query for packages failed.'
+ console.log(err)
+ return throwError(
+ err.errors && err.errors.length > 0
+ ? `${msg} ${err.errors[0].message}`
+ : `${msg} verify input parameters are correct`
+ )
+ })
+ )
+ }
+}
+
+export function getRepoPackages(
+ owner: string,
+ repo: string,
+ numPackages: number,
+ startCursor: string,
+ token: string
+): Observable {
+ return queryForRepoPackages(
+ owner,
+ repo,
+ numPackages,
+ startCursor,
+ token
+ ).pipe(
+ map(result => {
+ let r: QueryInfo
+ if (result.repository.packages.edges.length < 1) {
+ console.log(
+ `package: No packages found for owner: ${owner} in repo: ${repo}`
+ )
+ r = {
+ packages: [] as PackageInfo[],
+ cursor: '',
+ paginate: false
+ }
+ return r
+ }
+
+ const packages = result.repository.packages.edges
+ const pages = result.repository.packages.pageInfo
+
+ r = {
+ packages: packages.map(value => ({
+ id: value.node.id,
+ name: value.node.name
+ })),
+ cursor: pages.endCursor,
+ paginate: pages.hasNextPage
+ }
+
+ return r
+ })
+ )
+}
diff --git a/src/packages/index.ts b/src/packages/index.ts
new file mode 100644
index 00000000..eadf04e4
--- /dev/null
+++ b/src/packages/index.ts
@@ -0,0 +1,2 @@
+export * from './get-packages'
+export * from './package-name-filter'
diff --git a/src/packages/package-name-filter.ts b/src/packages/package-name-filter.ts
new file mode 100644
index 00000000..fba0af00
--- /dev/null
+++ b/src/packages/package-name-filter.ts
@@ -0,0 +1,126 @@
+/**
+ * Used to apply memoization on getPackageNameFilter
+ */
+const resultCache = {} as Record
+
+interface PackageNameSubFilter {
+ type: 'regex' | 'wildcard' | 'string'
+ apply: (packageName: string) => boolean
+}
+
+interface PackageNamesFilter {
+ readonly subfilters: readonly PackageNameSubFilter[]
+ readonly isEmpty: boolean
+ readonly apply: (packageName: string) => boolean
+}
+
+/**
+ * Get a filter based on package names to match
+ *
+ * @param packageNames - serialized package names filter as string
+ * @returns the respective package filter
+ */
+export function getPackageNameFilter(packageNames: string): PackageNamesFilter {
+ if (resultCache[packageNames]) {
+ return resultCache[packageNames]
+ }
+ const result = calculatePackageNameFilter(packageNames)
+ resultCache[packageNames] = result
+ return result
+}
+
+const emptyFilter = Object.freeze({
+ subfilters: Object.freeze([]),
+ isEmpty: true,
+ apply: () => false as boolean
+})
+
+/**
+ * Generates a filter based package names to match
+ *
+ * @param packageNames - serialized package names filter as string
+ * @returns the respective package filter
+ */
+function calculatePackageNameFilter(
+ packageNames: string
+): Readonly {
+ if (packageNames === '') {
+ return emptyFilter
+ }
+ const separatedPackageNames = packageNames
+ .split(',')
+ .map(name => name.trim())
+ .filter(name => name !== '')
+
+ if (separatedPackageNames.length <= 0) {
+ return emptyFilter
+ }
+
+ const subfilters = separatedPackageNames.map(createFilter)
+ return {
+ subfilters,
+ isEmpty: subfilters.length <= 0,
+ apply: names => subfilters.some(filter => filter.apply(names))
+ }
+}
+
+function createFilter(packageName: string): PackageNameSubFilter {
+ if (packageName.startsWith('*') || packageName.endsWith('*')) {
+ return createWildcardFilter(packageName)
+ } else if (packageName.startsWith('/') && packageName.endsWith('/')) {
+ return createRegexFilter(packageName)
+ } else {
+ return createExactMatchFilter(packageName)
+ }
+}
+
+function createWildcardFilter(
+ wildcardPackageName: string
+): PackageNameSubFilter {
+ const startsWithWildCard = wildcardPackageName.startsWith('*')
+ const endsWithWildCard = wildcardPackageName.endsWith('*')
+ let fn: PackageNameSubFilter['apply']
+ if (wildcardPackageName === '*') {
+ fn = () => true
+ } else if (startsWithWildCard && endsWithWildCard) {
+ const targetText = wildcardPackageName.substring(
+ 1,
+ wildcardPackageName.length - 1
+ )
+ fn = (packageName: string) => packageName.includes(targetText)
+ } else if (startsWithWildCard) {
+ const targetText = wildcardPackageName.substring(1)
+ fn = (packageName: string) => packageName.endsWith(targetText)
+ } else {
+ const targetText = wildcardPackageName.substring(
+ 0,
+ wildcardPackageName.length - 1
+ )
+ fn = (packageName: string) => packageName.startsWith(targetText)
+ }
+ return {
+ type: 'wildcard',
+ apply: fn
+ }
+}
+
+function createRegexFilter(regexPackageName: string): PackageNameSubFilter {
+ const regexPattern = regexPackageName.substring(
+ 1,
+ regexPackageName.length - 1
+ )
+ const regex = new RegExp(regexPattern)
+ return {
+ type: 'regex',
+ apply: (packageName: string) => regex.test(packageName)
+ }
+}
+
+function createExactMatchFilter(
+ matchingPackageName: string
+): PackageNameSubFilter {
+ return {
+ type: 'string',
+ apply: (packageName: string) => packageName === matchingPackageName
+ }
+}
diff --git a/src/version/delete-version.ts b/src/version/delete-version.ts
index 3e788b95..ab91d904 100644
--- a/src/version/delete-version.ts
+++ b/src/version/delete-version.ts
@@ -1,4 +1,4 @@
-import {from, Observable, merge, throwError, of} from 'rxjs'
+import {from, Observable, merge, of, EMPTY} from 'rxjs'
import {catchError, map, tap} from 'rxjs/operators'
import {Octokit} from '@octokit/rest'
import {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'
@@ -31,12 +31,8 @@ export function deletePackageVersion(
})
).pipe(
catchError(err => {
- const msg = 'delete version API failed.'
- return throwError(
- err.errors && err.errors.length > 0
- ? `${msg} ${err.errors[0].message}`
- : `${msg} ${err.message} \n${deleted - 1} versions deleted till now.`
- )
+ console.log(err)
+ return EMPTY
}),
map(response => response.status === 204)
)
diff --git a/src/version/get-versions.ts b/src/version/get-versions.ts
index 342cad2b..dfed768a 100644
--- a/src/version/get-versions.ts
+++ b/src/version/get-versions.ts
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
-import {from, Observable, merge, throwError, of} from 'rxjs'
+import {from, Observable, merge, throwError, of, EMPTY} from 'rxjs'
import {catchError, map} from 'rxjs/operators'
import {Octokit} from '@octokit/rest'
import {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'
@@ -47,12 +47,7 @@ export function getOldestVersions(
})
).pipe(
catchError(err => {
- const msg = 'get versions API failed.'
- return throwError(
- err.errors && err.errors.length > 0
- ? `${msg} ${err.errors[0].message}`
- : `${msg} ${err.message}`
- )
+ return EMPTY
}),
map(response => {
const resp = {