From b6861e20cfb246ae9b922bcbbc7d9687005b4395 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 11:57:08 +0100 Subject: [PATCH 01/27] refactor: move editor-version type and module Move editor-version type into corresponding module and move that module into the types folder --- src/cmd-add.ts | 2 +- src/{utils => types}/editor-version.ts | 12 +++++++++++- src/types/global.ts | 12 ------------ test/test-editor-version.ts | 2 +- 4 files changed, 13 insertions(+), 15 deletions(-) rename src/{utils => types}/editor-version.ts (91%) diff --git a/src/cmd-add.ts b/src/cmd-add.ts index 1380f34f..9399dad9 100644 --- a/src/cmd-add.ts +++ b/src/cmd-add.ts @@ -8,7 +8,7 @@ import { env, parseEnv } from "./utils/env"; import { compareEditorVersion, tryParseEditorVersion, -} from "./utils/editor-version"; +} from "./types/editor-version"; import { fetchPackageDependencies, fetchPackageInfo } from "./registry-client"; import { DomainName, isDomainName } from "./types/domain-name"; import { SemanticVersion } from "./types/semantic-version"; diff --git a/src/utils/editor-version.ts b/src/types/editor-version.ts similarity index 91% rename from src/utils/editor-version.ts rename to src/types/editor-version.ts index aed12f0a..17bf4622 100644 --- a/src/utils/editor-version.ts +++ b/src/types/editor-version.ts @@ -1,4 +1,14 @@ -import { EditorVersion } from "../types/global"; +export type EditorVersion = { + major: number; + minor: number; + patch?: number; + flag?: "a" | "b" | "f" | "c"; + flagValue?: 0 | 1 | 2; + build?: number; + loc?: string; + locValue?: number; + locBuild?: number; +}; /** * Compares two editor versions for ordering diff --git a/src/types/global.ts b/src/types/global.ts index 85d2f82c..48585b6f 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -8,18 +8,6 @@ import { RegistryUrl } from "./registry-url"; export type Region = "us" | "cn"; -export type EditorVersion = { - major: number; - minor: number; - patch?: number; - flag?: "a" | "b" | "f" | "c"; - flagValue?: 0 | 1 | 2; - build?: number; - loc?: string; - locValue?: number; - locBuild?: number; -}; - export type Env = { cwd: string; color: boolean; diff --git a/test/test-editor-version.ts b/test/test-editor-version.ts index 2fca64c2..82307a2f 100644 --- a/test/test-editor-version.ts +++ b/test/test-editor-version.ts @@ -2,7 +2,7 @@ import { describe } from "mocha"; import { compareEditorVersion, tryParseEditorVersion, -} from "../src/utils/editor-version"; +} from "../src/types/editor-version"; import "should"; import assert from "assert"; From 361a900ed76d0eed78ae750cb027ffd8fdcd62f3 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:01:43 +0100 Subject: [PATCH 02/27] doc: jsdoc for editor-version type --- src/types/editor-version.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/types/editor-version.ts b/src/types/editor-version.ts index 17bf4622..29f2e73d 100644 --- a/src/types/editor-version.ts +++ b/src/types/editor-version.ts @@ -1,12 +1,38 @@ +/** + * Describes a version of a Unity editor. Mostly this follows calendar-versioning, + * with some extra rules for chinese releases. + * @see https://calver.org/ + */ export type EditorVersion = { + /** + * The major version. This is the release year. + */ major: number; + /** + * The minor version. This is usually a number from 1 to 3 + */ minor: number; + /** + * An optional patch. + */ patch?: number; + /** + * A flag describing a specific release + */ flag?: "a" | "b" | "f" | "c"; flagValue?: 0 | 1 | 2; + /** + * A specific build + */ build?: number; + /** + * A flag describing a specific locale build + */ loc?: string; locValue?: number; + /** + * The specific build for a locale + */ locBuild?: number; }; From e8d9c0094714c7c51311cb1b2417338c50593324 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:05:58 +0100 Subject: [PATCH 03/27] refactor: move pkg-info type and module Move pkg-info type into corresponding module. Also move that module into types folder. --- src/cmd-add.ts | 2 +- src/cmd-search.ts | 4 ++-- src/cmd-view.ts | 4 ++-- src/registry-client.ts | 4 ++-- src/types/another-npm-registry-client.d.ts | 3 ++- src/types/global.ts | 20 ----------------- src/{utils => types}/pkg-info.ts | 25 ++++++++++++++++++++-- test/data-pkg-info.ts | 3 ++- test/mock-registry.ts | 2 +- test/test-pgk-info.ts | 2 +- 10 files changed, 36 insertions(+), 33 deletions(-) rename src/{utils => types}/pkg-info.ts (51%) diff --git a/src/cmd-add.ts b/src/cmd-add.ts index 9399dad9..ce2c8f4a 100644 --- a/src/cmd-add.ts +++ b/src/cmd-add.ts @@ -2,7 +2,7 @@ import log from "./logger"; import url from "url"; import { isPackageUrl } from "./types/package-url"; import { GlobalOptions, ScopedRegistry } from "./types/global"; -import { tryGetLatestVersion } from "./utils/pkg-info"; +import { tryGetLatestVersion } from "./types/pkg-info"; import { loadManifest, saveManifest } from "./utils/manifest"; import { env, parseEnv } from "./utils/env"; import { diff --git a/src/cmd-search.ts b/src/cmd-search.ts index e1d4a4ec..0ae06d0c 100644 --- a/src/cmd-search.ts +++ b/src/cmd-search.ts @@ -5,8 +5,8 @@ import log from "./logger"; import { is404Error, isHttpError } from "./utils/error-type-guards"; import * as os from "os"; import assert from "assert"; -import { GlobalOptions, PkgInfo } from "./types/global"; -import { tryGetLatestVersion } from "./utils/pkg-info"; +import { GlobalOptions } from "./types/global"; +import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; import { env, parseEnv } from "./utils/env"; import { DomainName } from "./types/domain-name"; import { SemanticVersion } from "./types/semantic-version"; diff --git a/src/cmd-view.ts b/src/cmd-view.ts index 0208cf66..ceb5bade 100644 --- a/src/cmd-view.ts +++ b/src/cmd-view.ts @@ -1,8 +1,8 @@ import chalk from "chalk"; import log from "./logger"; import assert from "assert"; -import { GlobalOptions, PkgInfo } from "./types/global"; -import { tryGetLatestVersion } from "./utils/pkg-info"; +import { GlobalOptions } from "./types/global"; +import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; import { env, parseEnv } from "./utils/env"; import { fetchPackageInfo } from "./registry-client"; import { DomainName } from "./types/domain-name"; diff --git a/src/registry-client.ts b/src/registry-client.ts index 99d20e32..8452bc75 100644 --- a/src/registry-client.ts +++ b/src/registry-client.ts @@ -8,10 +8,10 @@ import RegClient, { import log from "./logger"; import request from "request"; import assert, { AssertionError } from "assert"; -import { Dependency, NameVersionPair, PkgInfo } from "./types/global"; +import { Dependency, NameVersionPair } from "./types/global"; import { env } from "./utils/env"; import _ from "lodash"; -import { tryGetLatestVersion } from "./utils/pkg-info"; +import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; import { DomainName, isInternalPackage } from "./types/domain-name"; import { SemanticVersion } from "./types/semantic-version"; import { packageReference } from "./types/package-reference"; diff --git a/src/types/another-npm-registry-client.d.ts b/src/types/another-npm-registry-client.d.ts index b74b52ad..6eff650d 100644 --- a/src/types/another-npm-registry-client.d.ts +++ b/src/types/another-npm-registry-client.d.ts @@ -1,5 +1,6 @@ import { Response } from "request"; -import { PkgInfo } from "./global"; + +import { PkgInfo } from "./pkg-info"; declare module "another-npm-registry-client" { export type NpmAuth = diff --git a/src/types/global.ts b/src/types/global.ts index 48585b6f..39e964fe 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -59,26 +59,6 @@ export type PkgVersionInfo = { dist?: Dist; }; -export type PkgInfo = { - name: DomainName; - _id?: DomainName; - _rev?: string; - _attachments?: Record; - readme?: string; - versions: Record; - "dist-tags"?: { latest?: SemanticVersion }; - version?: SemanticVersion; - description?: string; - keywords?: string[]; - time: { - [key: SemanticVersion]: string; - created?: string; - modified?: string; - }; - date?: Date; - users?: Record; -}; - export type NameVersionPair = { name: DomainName; version: SemanticVersion | "latest" | undefined; diff --git a/src/utils/pkg-info.ts b/src/types/pkg-info.ts similarity index 51% rename from src/utils/pkg-info.ts rename to src/types/pkg-info.ts index 62616842..becbc7cb 100644 --- a/src/utils/pkg-info.ts +++ b/src/types/pkg-info.ts @@ -1,5 +1,26 @@ -import { PkgInfo } from "../types/global"; -import { SemanticVersion } from "../types/semantic-version"; +import { SemanticVersion } from "./semantic-version"; +import { DomainName } from "./domain-name"; +import { PkgVersionInfo } from "./global"; + +export type PkgInfo = { + name: DomainName; + _id?: DomainName; + _rev?: string; + _attachments?: Record; + readme?: string; + versions: Record; + "dist-tags"?: { latest?: SemanticVersion }; + version?: SemanticVersion; + description?: string; + keywords?: string[]; + time: { + [key: SemanticVersion]: string; + created?: string; + modified?: string; + }; + date?: Date; + users?: Record; +}; const hasLatestDistTag = ( pkgInfo: Partial diff --git a/test/data-pkg-info.ts b/test/data-pkg-info.ts index 278089be..c3eda776 100644 --- a/test/data-pkg-info.ts +++ b/test/data-pkg-info.ts @@ -1,4 +1,3 @@ -import { PkgInfo, PkgVersionInfo } from "../src/types/global"; import assert from "assert"; import { DomainName, isDomainName } from "../src/types/domain-name"; import { @@ -6,6 +5,8 @@ import { SemanticVersion, } from "../src/types/semantic-version"; import { packageId } from "../src/types/package-id"; +import { PkgInfo } from "../src/types/pkg-info"; +import { PkgVersionInfo } from "../src/types/global"; /** * Builder class for {@link PkgVersionInfo} diff --git a/test/mock-registry.ts b/test/mock-registry.ts index bcddc0e9..f05e9dc9 100644 --- a/test/mock-registry.ts +++ b/test/mock-registry.ts @@ -1,9 +1,9 @@ -import { PkgInfo } from "../src/types/global"; import nock from "nock"; import { SearchEndpointResult } from "./types"; import { domainName, isDomainName } from "../src/types/domain-name"; import assert from "assert"; import { registryUrl } from "../src/types/registry-url"; +import { PkgInfo } from "../src/types/pkg-info"; export const unityRegistryUrl = registryUrl("https://packages.unity.com"); export const exampleRegistryUrl = registryUrl("http://example.com"); diff --git a/test/test-pgk-info.ts b/test/test-pgk-info.ts index 1e4c5ac0..c0ab0214 100644 --- a/test/test-pgk-info.ts +++ b/test/test-pgk-info.ts @@ -1,4 +1,4 @@ -import { tryGetLatestVersion } from "../src/utils/pkg-info"; +import { tryGetLatestVersion } from "../src/types/pkg-info"; import "should"; import { describe } from "mocha"; import should from "should"; From 6f5f7a27024756580ecbb183bd2332631b8e1c98 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:11:11 +0100 Subject: [PATCH 04/27] doc: jsdoc for pkg-info --- src/types/pkg-info.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/types/pkg-info.ts b/src/types/pkg-info.ts index becbc7cb..851f9a8f 100644 --- a/src/types/pkg-info.ts +++ b/src/types/pkg-info.ts @@ -2,17 +2,44 @@ import { SemanticVersion } from "./semantic-version"; import { DomainName } from "./domain-name"; import { PkgVersionInfo } from "./global"; +/** + * Describes a package + */ export type PkgInfo = { + /** + * The packages name + */ name: DomainName; + /** + * Same as {@link name} + */ _id?: DomainName; _rev?: string; _attachments?: Record; readme?: string; + /** + * The packages versions, organized by their version + */ versions: Record; + /** + * Dist-tags. Only includes information about the latest version + */ "dist-tags"?: { latest?: SemanticVersion }; + /** + * May contain the latest version. Legacy property, use {@link dist-tags} instead + */ version?: SemanticVersion; + /** + * Short description for the package + */ description?: string; + /** + * Package keywords + */ keywords?: string[]; + /** + * Information about package and version creation/modification times + */ time: { [key: SemanticVersion]: string; created?: string; From ccf37e4ad10745c7e10ff9b92fd34770e188d501 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:13:32 +0100 Subject: [PATCH 05/27] refactor: rename module Rename upm-config to upm-config-io. This is in preparation for moving the UpmConfig type and functions which act on it into own module which should be called upm-config --- src/cmd-login.ts | 2 +- src/utils/env.ts | 2 +- src/utils/{upm-config.ts => upm-config-io.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/utils/{upm-config.ts => upm-config-io.ts} (100%) diff --git a/src/cmd-login.ts b/src/cmd-login.ts index fbb010d3..fc08f011 100644 --- a/src/cmd-login.ts +++ b/src/cmd-login.ts @@ -11,7 +11,7 @@ import { getUpmConfigDir, loadUpmConfig, saveUpmConfig, -} from "./utils/upm-config"; +} from "./utils/upm-config-io"; import { parseEnv } from "./utils/env"; import { RegistryUrl, diff --git a/src/utils/env.ts b/src/utils/env.ts index bca13744..45a7fff4 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,7 +1,7 @@ import { Env, GlobalOptions } from "../types/global"; import log from "../logger"; import chalk from "chalk"; -import { loadUpmConfig } from "./upm-config"; +import { loadUpmConfig } from "./upm-config-io"; import path from "path"; import fs from "fs"; import yaml from "yaml"; diff --git a/src/utils/upm-config.ts b/src/utils/upm-config-io.ts similarity index 100% rename from src/utils/upm-config.ts rename to src/utils/upm-config-io.ts From eff5885afd45ff1bfec83acdf01e43bead0defe1 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:15:14 +0100 Subject: [PATCH 06/27] refactor: move upm-config types to own module This will be its own module so that it can also contain helpers related to the type which do not involve io --- src/types/global.ts | 10 +--------- src/types/upm-config.ts | 10 ++++++++++ src/utils/upm-config-io.ts | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 src/types/upm-config.ts diff --git a/src/types/global.ts b/src/types/global.ts index 39e964fe..be0b13f3 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -5,6 +5,7 @@ import { PackageUrl } from "./package-url"; import { SemanticVersion } from "./semantic-version"; import { PackageId } from "./package-id"; import { RegistryUrl } from "./registry-url"; +import { UpmAuth } from "./upm-config"; export type Region = "us" | "cn"; @@ -96,12 +97,3 @@ export type GlobalOptions = { wsl?: boolean; chdir?: string; }; - -export type UpmAuth = { - email: string; - alwaysAuth: boolean; -} & ({ token: string } | { _auth: string }); - -export type UPMConfig = { - npmAuth?: Record; -}; diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts new file mode 100644 index 00000000..e86eac40 --- /dev/null +++ b/src/types/upm-config.ts @@ -0,0 +1,10 @@ +import { Registry } from "./global"; + +export type UpmAuth = { + email: string; + alwaysAuth: boolean; +} & ({ token: string } | { _auth: string }); + +export type UPMConfig = { + npmAuth?: Record; +}; diff --git a/src/utils/upm-config-io.ts b/src/utils/upm-config-io.ts index 2cdfc2fe..43b9bf31 100644 --- a/src/utils/upm-config-io.ts +++ b/src/utils/upm-config-io.ts @@ -1,4 +1,3 @@ -import { UPMConfig } from "../types/global"; import mkdirp from "mkdirp"; import path from "path"; import TOML from "@iarna/toml"; @@ -7,6 +6,7 @@ import log from "../logger"; import isWsl from "is-wsl"; import execute from "./process"; import { env } from "./env"; +import { UPMConfig } from "../types/upm-config"; /** * Gets the path to directory in which the upm config is stored From a0181768fd900f6cb2bdf7d262d5f7871d4f97a6 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:20:10 +0100 Subject: [PATCH 07/27] doc: jsdoc for upm-config types --- src/types/upm-config.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index e86eac40..3280c088 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -1,10 +1,39 @@ import { Registry } from "./global"; +/** + * Authentication information for a registry + */ export type UpmAuth = { + /** + * The email to use + */ email: string; + /** + * Whether to always authenticate + */ alwaysAuth: boolean; -} & ({ token: string } | { _auth: string }); +} & ( + | { + /** + * A token to authenticate with + */ + token: string; + } + | { + /** + * Base64 encoded username and password to authenticate with + */ + _auth: string; + } +); +/** + * Content of .upmconfig.toml. Used to authenticate with package registries + * @see https://medium.com/openupm/how-to-authenticate-with-a-upm-scoped-registry-using-cli-afc29c13a2f8 + */ export type UPMConfig = { + /** + * Authentication information organized by the registry they should be used on + */ npmAuth?: Record; }; From 94e82bd138461e74b194d0fa0c586e5c90636cd2 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:21:21 +0100 Subject: [PATCH 08/27] refactor: extract constant --- src/utils/upm-config-io.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/utils/upm-config-io.ts b/src/utils/upm-config-io.ts index 43b9bf31..49913f9f 100644 --- a/src/utils/upm-config-io.ts +++ b/src/utils/upm-config-io.ts @@ -8,6 +8,8 @@ import execute from "./process"; import { env } from "./env"; import { UPMConfig } from "../types/upm-config"; +const configFileName = ".upmconfig.toml"; + /** * Gets the path to directory in which the upm config is stored */ @@ -52,7 +54,7 @@ export const loadUpmConfig = async ( configDir?: string ): Promise => { if (configDir === undefined) configDir = await getUpmConfigDir(); - const configPath = path.join(configDir, ".upmconfig.toml"); + const configPath = path.join(configDir, configFileName); if (fs.existsSync(configPath)) { const content = fs.readFileSync(configPath, "utf8"); const config = TOML.parse(content); @@ -68,7 +70,7 @@ export const loadUpmConfig = async ( export const saveUpmConfig = async (config: UPMConfig, configDir: string) => { if (configDir === undefined) configDir = await getUpmConfigDir(); mkdirp.sync(configDir); - const configPath = path.join(configDir, ".upmconfig.toml"); + const configPath = path.join(configDir, configFileName); const content = TOML.stringify(config); fs.writeFileSync(configPath, content, "utf8"); log.notice("config", "saved unity config at " + configPath); From b13ca1a88be4da514f041a5fc1d3aa4feb8e437a Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:28:08 +0100 Subject: [PATCH 09/27] refactor: split UpmAuth type Split into multiple types in preparation for further refactors --- src/types/upm-config.ts | 44 ++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index 3280c088..21844c67 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -1,9 +1,9 @@ import { Registry } from "./global"; /** - * Authentication information for a registry + * Authentication information that is shared between different authentication methods */ -export type UpmAuth = { +type AuthBase = { /** * The email to use */ @@ -12,20 +12,32 @@ export type UpmAuth = { * Whether to always authenticate */ alwaysAuth: boolean; -} & ( - | { - /** - * A token to authenticate with - */ - token: string; - } - | { - /** - * Base64 encoded username and password to authenticate with - */ - _auth: string; - } -); +}; + +/** + * Authenticates using encoded username and password + */ +export type BasicAuth = AuthBase & { + /** + * Base64 encoded username and password to authenticate with + */ + _auth: string; +}; + +/** + * Authenticates using token + */ +export type TokenAuth = AuthBase & { + /** + * A token to authenticate with + */ + token: string; +}; + +/** + * Authentication information for a registry + */ +export type UpmAuth = BasicAuth | TokenAuth; /** * Content of .upmconfig.toml. Used to authenticate with package registries From 488c0ce101b8a82e4140950ad481d45d36d52cbc Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:34:56 +0100 Subject: [PATCH 10/27] refactor: auth classification helpers --- src/types/upm-config.ts | 15 +++++++++++++++ src/utils/env.ts | 5 +++-- test/test-upm-config.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/test-upm-config.ts diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index 21844c67..8c6e8efc 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -49,3 +49,18 @@ export type UPMConfig = { */ npmAuth?: Record; }; + +/** + * Checks if an auth-object uses basic authentication + * @param auth The auth-object + */ +export function isBasicAuth(auth: UpmAuth): auth is BasicAuth { + return "_auth" in auth; +} +/** + * Checks if an auth-object uses token authentication + * @param auth The auth-object + */ +export function isTokenAuth(auth: UpmAuth): auth is TokenAuth { + return "token" in auth; +} diff --git a/src/utils/env.ts b/src/utils/env.ts index 45a7fff4..48613ca9 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -13,6 +13,7 @@ import { registryUrl, } from "../types/registry-url"; import url from "url"; +import { isBasicAuth, isTokenAuth } from "../types/upm-config"; export const env: Env = {}; @@ -72,12 +73,12 @@ export const parseEnv = async function ( if (env.npmAuth !== undefined) { (Object.keys(env.npmAuth) as RegistryUrl[]).forEach((reg) => { const regAuth = env.npmAuth![reg]; - if ("token" in regAuth) { + if (isTokenAuth(regAuth)) { env.auth[reg] = { token: regAuth.token, alwaysAuth: regAuth.alwaysAuth || false, }; - } else if ("_auth" in regAuth) { + } else if (isBasicAuth(regAuth)) { const buf = Buffer.from(regAuth._auth, "base64"); const text = buf.toString("utf-8"); const [username, password] = text.split(":", 2); diff --git a/test/test-upm-config.ts b/test/test-upm-config.ts new file mode 100644 index 00000000..21afca1c --- /dev/null +++ b/test/test-upm-config.ts @@ -0,0 +1,28 @@ +import { describe } from "mocha"; +import { isBasicAuth, isTokenAuth, UpmAuth } from "../src/types/upm-config"; +import should from "should"; + +describe("upm-config", function () { + describe("auth", function () { + describe("classification", function () { + it("should be basic auth if it has _auth property", () => { + const auth: UpmAuth = { + email: "real@email.com", + alwaysAuth: true, + // Not a real base64 string, but we don't care in this test + _auth: "h8gz8s9zgseihgisejf", + }; + should(isBasicAuth(auth)).be.true(); + }); + it("should be token auth if it has token property", () => { + const auth: UpmAuth = { + email: "real@email.com", + alwaysAuth: true, + // Not a real token, but we don't care in this test + token: "h8gz8s9zgseihgisejf", + }; + should(isTokenAuth(auth)).be.true(); + }); + }); + }); +}); From 6e4cf61b58f0cc688c0ff00699af0dcaf72bea05 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:49:48 +0100 Subject: [PATCH 11/27] refactor: helpers for encoding/decoding basic auth --- src/cmd-login.ts | 9 +++++---- src/types/upm-config.ts | 33 ++++++++++++++++++++++++++++++++- src/utils/env.ts | 6 ++---- test/test-upm-config.ts | 21 +++++++++++++++++++-- 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/cmd-login.ts b/src/cmd-login.ts index fc08f011..42b1f2bd 100644 --- a/src/cmd-login.ts +++ b/src/cmd-login.ts @@ -18,6 +18,8 @@ import { registryUrl, removeTrailingSlash, } from "./types/registry-url"; +import { Base64AuthData, encodeBasicAuth } from "./types/upm-config"; +import { userInfo } from "os"; export type LoginOptions = { username?: string; @@ -42,11 +44,10 @@ export const login = async function (options: LoginOptions) { validator: [registryUrl], })) as RegistryUrl; let token: string | null = null; - let _auth: string | null = null; + let _auth: Base64AuthData | null = null; if (options.basicAuth) { // basic auth - const userPass = `${options.username}:${options.password}`; - _auth = Buffer.from(userPass).toString("base64"); + _auth = encodeBasicAuth(options.username, options.password); } else { // npm login const result = await npmLogin({ @@ -205,7 +206,7 @@ const writeUnityToken = async function ({ registry, token, }: { - _auth: string | null; + _auth: Base64AuthData | null; alwaysAuth: boolean; basicAuth: boolean; email: string; diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index 8c6e8efc..b1118817 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -1,4 +1,8 @@ import { Registry } from "./global"; +import { trySplitAtFirstOccurrenceOf } from "../utils/string-utils"; +import { Brand } from "ts-brand"; + +export type Base64AuthData = Brand; /** * Authentication information that is shared between different authentication methods @@ -21,7 +25,7 @@ export type BasicAuth = AuthBase & { /** * Base64 encoded username and password to authenticate with */ - _auth: string; + _auth: Base64AuthData; }; /** @@ -64,3 +68,30 @@ export function isBasicAuth(auth: UpmAuth): auth is BasicAuth { export function isTokenAuth(auth: UpmAuth): auth is TokenAuth { return "token" in auth; } + +/** + * Encodes a username and password using base64 + * @param username The username + * @param password The password + */ +export function encodeBasicAuth( + username: string, + password: string +): Base64AuthData { + return Buffer.from(`${username}:${password}`).toString( + "base64" + ) as Base64AuthData; +} + +/** + * Decodes a base64 encoded username and password + * @param base64 The base64 string + * @throws Error if the string cannot be decoded + */ +export function decodeBasicAuth(base64: Base64AuthData): [string, string] { + const buffer = Buffer.from(base64, "base64"); + const text = buffer.toString("utf-8"); + const [username, password] = trySplitAtFirstOccurrenceOf(text, ":"); + if (password === undefined) throw new Error("Base64 had invalid format"); + return [username, password]; +} diff --git a/src/utils/env.ts b/src/utils/env.ts index 48613ca9..99c5ce78 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -13,7 +13,7 @@ import { registryUrl, } from "../types/registry-url"; import url from "url"; -import { isBasicAuth, isTokenAuth } from "../types/upm-config"; +import { decodeBasicAuth, isBasicAuth, isTokenAuth } from "../types/upm-config"; export const env: Env = {}; @@ -79,9 +79,7 @@ export const parseEnv = async function ( alwaysAuth: regAuth.alwaysAuth || false, }; } else if (isBasicAuth(regAuth)) { - const buf = Buffer.from(regAuth._auth, "base64"); - const text = buf.toString("utf-8"); - const [username, password] = text.split(":", 2); + const [username, password] = decodeBasicAuth(regAuth._auth); env.auth[reg] = { username, password: Buffer.from(password).toString("base64"), diff --git a/test/test-upm-config.ts b/test/test-upm-config.ts index 21afca1c..68fefa1f 100644 --- a/test/test-upm-config.ts +++ b/test/test-upm-config.ts @@ -1,5 +1,12 @@ import { describe } from "mocha"; -import { isBasicAuth, isTokenAuth, UpmAuth } from "../src/types/upm-config"; +import { + Base64AuthData, + decodeBasicAuth, + encodeBasicAuth, + isBasicAuth, + isTokenAuth, + UpmAuth, +} from "../src/types/upm-config"; import should from "should"; describe("upm-config", function () { @@ -10,7 +17,7 @@ describe("upm-config", function () { email: "real@email.com", alwaysAuth: true, // Not a real base64 string, but we don't care in this test - _auth: "h8gz8s9zgseihgisejf", + _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, }; should(isBasicAuth(auth)).be.true(); }); @@ -24,5 +31,15 @@ describe("upm-config", function () { should(isTokenAuth(auth)).be.true(); }); }); + describe("encode/decode", function () { + it("should decode the same basic auth as was encoded", () => { + const expectedUsername = "my-name"; + const expectedPassword = "123pass"; + const encoded = encodeBasicAuth(expectedUsername, expectedPassword); + const [actualUsername, actualPassword] = decodeBasicAuth(encoded); + should(actualUsername).be.equal(expectedUsername); + should(actualPassword).be.equal(expectedPassword); + }); + }); }); }); From 006462beb76698d7dad339d198add58f94a087f9 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:53:55 +0100 Subject: [PATCH 12/27] refactor: helper for always-auth --- src/types/upm-config.ts | 10 +++++++++- src/utils/env.ts | 11 ++++++++--- test/test-upm-config.ts | 29 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index b1118817..d711e168 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -15,7 +15,7 @@ type AuthBase = { /** * Whether to always authenticate */ - alwaysAuth: boolean; + alwaysAuth?: boolean; }; /** @@ -95,3 +95,11 @@ export function decodeBasicAuth(base64: Base64AuthData): [string, string] { if (password === undefined) throw new Error("Base64 had invalid format"); return [username, password]; } + +/** + * Checks if this auth-object should always authenticate + * @param auth The auth-object + */ +export function shouldAlwaysAuth(auth: UpmAuth): boolean { + return auth.alwaysAuth || false; +} diff --git a/src/utils/env.ts b/src/utils/env.ts index 99c5ce78..618afb0a 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -13,7 +13,12 @@ import { registryUrl, } from "../types/registry-url"; import url from "url"; -import { decodeBasicAuth, isBasicAuth, isTokenAuth } from "../types/upm-config"; +import { + decodeBasicAuth, + isBasicAuth, + isTokenAuth, + shouldAlwaysAuth, +} from "../types/upm-config"; export const env: Env = {}; @@ -76,7 +81,7 @@ export const parseEnv = async function ( if (isTokenAuth(regAuth)) { env.auth[reg] = { token: regAuth.token, - alwaysAuth: regAuth.alwaysAuth || false, + alwaysAuth: shouldAlwaysAuth(regAuth), }; } else if (isBasicAuth(regAuth)) { const [username, password] = decodeBasicAuth(regAuth._auth); @@ -84,7 +89,7 @@ export const parseEnv = async function ( username, password: Buffer.from(password).toString("base64"), email: regAuth.email, - alwaysAuth: regAuth.alwaysAuth || false, + alwaysAuth: shouldAlwaysAuth(regAuth), }; } else { log.warn( diff --git a/test/test-upm-config.ts b/test/test-upm-config.ts index 68fefa1f..9d9e0a45 100644 --- a/test/test-upm-config.ts +++ b/test/test-upm-config.ts @@ -5,6 +5,7 @@ import { encodeBasicAuth, isBasicAuth, isTokenAuth, + shouldAlwaysAuth, UpmAuth, } from "../src/types/upm-config"; import should from "should"; @@ -41,5 +42,33 @@ describe("upm-config", function () { should(actualPassword).be.equal(expectedPassword); }); }); + describe("always-auth", function () { + it("should always-auth when prop is true", () => { + const auth: UpmAuth = { + email: "real@email.com", + alwaysAuth: true, + // Not a real base64 string, but we don't care in this test + _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + }; + should(shouldAlwaysAuth(auth)).be.true(); + }); + it("should not always-auth when prop is false", () => { + const auth: UpmAuth = { + email: "real@email.com", + alwaysAuth: false, + // Not a real base64 string, but we don't care in this test + _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + }; + should(shouldAlwaysAuth(auth)).be.false(); + }); + it("should not always-auth when prop is missing", () => { + const auth: UpmAuth = { + email: "real@email.com", + // Not a real base64 string, but we don't care in this test + _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + }; + should(shouldAlwaysAuth(auth)).be.false(); + }); + }); }); }); From 2d9941f17c451601767f66931a57e4ebd8cb3ede Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 12:58:13 +0100 Subject: [PATCH 13/27] refactor: base64 helper functions --- src/cmd-login.ts | 8 ++++---- src/types/base64.ts | 20 ++++++++++++++++++++ src/types/upm-config.ts | 20 ++++++-------------- src/utils/env.ts | 4 +++- 4 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 src/types/base64.ts diff --git a/src/cmd-login.ts b/src/cmd-login.ts index 42b1f2bd..7592b1bd 100644 --- a/src/cmd-login.ts +++ b/src/cmd-login.ts @@ -18,8 +18,8 @@ import { registryUrl, removeTrailingSlash, } from "./types/registry-url"; -import { Base64AuthData, encodeBasicAuth } from "./types/upm-config"; -import { userInfo } from "os"; +import { encodeBasicAuth } from "./types/upm-config"; +import { Base64 } from "./types/base64"; export type LoginOptions = { username?: string; @@ -44,7 +44,7 @@ export const login = async function (options: LoginOptions) { validator: [registryUrl], })) as RegistryUrl; let token: string | null = null; - let _auth: Base64AuthData | null = null; + let _auth: Base64 | null = null; if (options.basicAuth) { // basic auth _auth = encodeBasicAuth(options.username, options.password); @@ -206,7 +206,7 @@ const writeUnityToken = async function ({ registry, token, }: { - _auth: Base64AuthData | null; + _auth: Base64 | null; alwaysAuth: boolean; basicAuth: boolean; email: string; diff --git a/src/types/base64.ts b/src/types/base64.ts new file mode 100644 index 00000000..4e9e8721 --- /dev/null +++ b/src/types/base64.ts @@ -0,0 +1,20 @@ +import { Brand } from "ts-brand"; + +export type Base64 = Brand; + +/** + * Encodes a string using base64 + * @param s The string + */ +export function encodeBase64(s: string): Base64 { + return Buffer.from(s).toString("base64") as Base64; +} + +/** + * Decodes a base64 string + * @param base64 The string + */ +export function decodeBase64(base64: Base64): string { + const buffer = Buffer.from(base64, "base64"); + return buffer.toString("utf-8"); +} diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index d711e168..70266611 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -1,8 +1,6 @@ import { Registry } from "./global"; import { trySplitAtFirstOccurrenceOf } from "../utils/string-utils"; -import { Brand } from "ts-brand"; - -export type Base64AuthData = Brand; +import { Base64, decodeBase64, encodeBase64 } from "./base64"; /** * Authentication information that is shared between different authentication methods @@ -25,7 +23,7 @@ export type BasicAuth = AuthBase & { /** * Base64 encoded username and password to authenticate with */ - _auth: Base64AuthData; + _auth: Base64; }; /** @@ -74,13 +72,8 @@ export function isTokenAuth(auth: UpmAuth): auth is TokenAuth { * @param username The username * @param password The password */ -export function encodeBasicAuth( - username: string, - password: string -): Base64AuthData { - return Buffer.from(`${username}:${password}`).toString( - "base64" - ) as Base64AuthData; +export function encodeBasicAuth(username: string, password: string): Base64 { + return encodeBase64(`${username}:${password}`); } /** @@ -88,9 +81,8 @@ export function encodeBasicAuth( * @param base64 The base64 string * @throws Error if the string cannot be decoded */ -export function decodeBasicAuth(base64: Base64AuthData): [string, string] { - const buffer = Buffer.from(base64, "base64"); - const text = buffer.toString("utf-8"); +export function decodeBasicAuth(base64: Base64): [string, string] { + const text = decodeBase64(base64); const [username, password] = trySplitAtFirstOccurrenceOf(text, ":"); if (password === undefined) throw new Error("Base64 had invalid format"); return [username, password]; diff --git a/src/utils/env.ts b/src/utils/env.ts index 618afb0a..4ee2e53d 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -15,10 +15,12 @@ import { import url from "url"; import { decodeBasicAuth, + encodeBasicAuth, isBasicAuth, isTokenAuth, shouldAlwaysAuth, } from "../types/upm-config"; +import { encodeBase64 } from "../types/base64"; export const env: Env = {}; @@ -87,7 +89,7 @@ export const parseEnv = async function ( const [username, password] = decodeBasicAuth(regAuth._auth); env.auth[reg] = { username, - password: Buffer.from(password).toString("base64"), + password: encodeBase64(password), email: regAuth.email, alwaysAuth: shouldAlwaysAuth(regAuth), }; From 1c753b1b8e6b91e67ad1f644e2c38932fa6c7da7 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 13:55:48 +0100 Subject: [PATCH 14/27] fix: incorrect type name --- src/types/upm-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/upm-config.ts b/src/types/upm-config.ts index 70266611..dd4e0e4c 100644 --- a/src/types/upm-config.ts +++ b/src/types/upm-config.ts @@ -1,6 +1,6 @@ -import { Registry } from "./global"; import { trySplitAtFirstOccurrenceOf } from "../utils/string-utils"; import { Base64, decodeBase64, encodeBase64 } from "./base64"; +import { RegistryUrl } from "./registry-url"; /** * Authentication information that is shared between different authentication methods @@ -49,7 +49,7 @@ export type UPMConfig = { /** * Authentication information organized by the registry they should be used on */ - npmAuth?: Record; + npmAuth?: Record; }; /** From f87066926baeacc103a3c4ed548f7b5d37a5d38b Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:01:46 +0100 Subject: [PATCH 15/27] refactor: move type Move env type into corresponding module --- src/types/global.ts | 19 ------------------- src/utils/env.ts | 29 +++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/types/global.ts b/src/types/global.ts index be0b13f3..eaaeaf0f 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -1,30 +1,11 @@ -import { NpmAuth } from "another-npm-registry-client"; -import { IpAddress } from "./ip-address"; import { DomainName } from "./domain-name"; import { PackageUrl } from "./package-url"; import { SemanticVersion } from "./semantic-version"; import { PackageId } from "./package-id"; import { RegistryUrl } from "./registry-url"; -import { UpmAuth } from "./upm-config"; export type Region = "us" | "cn"; -export type Env = { - cwd: string; - color: boolean; - systemUser: boolean; - wsl: boolean; - npmAuth?: Record; - auth: Record; - upstream: boolean; - upstreamRegistry: RegistryUrl; - registry: RegistryUrl; - namespace: DomainName | IpAddress; - editorVersion: string | null; - region: Region; - manifestPath: string; -}; - export type Dist = { tarball: string; shasum: string; diff --git a/src/utils/env.ts b/src/utils/env.ts index 4ee2e53d..c7a5ef4a 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,12 +1,16 @@ -import { Env, GlobalOptions } from "../types/global"; +import { GlobalOptions, Region } from "../types/global"; import log from "../logger"; import chalk from "chalk"; import { loadUpmConfig } from "./upm-config-io"; import path from "path"; import fs from "fs"; import yaml from "yaml"; -import { isIpAddress } from "../types/ip-address"; -import { namespaceFor, openUpmReverseDomainName } from "../types/domain-name"; +import { IpAddress, isIpAddress } from "../types/ip-address"; +import { + DomainName, + namespaceFor, + openUpmReverseDomainName, +} from "../types/domain-name"; import { coerceRegistryUrl, RegistryUrl, @@ -15,12 +19,29 @@ import { import url from "url"; import { decodeBasicAuth, - encodeBasicAuth, isBasicAuth, isTokenAuth, shouldAlwaysAuth, + UpmAuth, } from "../types/upm-config"; import { encodeBase64 } from "../types/base64"; +import { NpmAuth } from "another-npm-registry-client"; + +export type Env = { + cwd: string; + color: boolean; + systemUser: boolean; + wsl: boolean; + npmAuth?: Record; + auth: Record; + upstream: boolean; + upstreamRegistry: RegistryUrl; + registry: RegistryUrl; + namespace: DomainName | IpAddress; + editorVersion: string | null; + region: Region; + manifestPath: string; +}; export const env: Env = {}; From dc7ce7640a86c692e63c098dc38ea215e3191735 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:07:00 +0100 Subject: [PATCH 16/27] fix: missing import From 65025fd7378852ed48717f5e047a2d2a55b148cf Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:31:14 +0100 Subject: [PATCH 17/27] refactor: extract scoped-registry utilities Move ScopedRegistry type to own module and add utility functions with tests --- src/cmd-add.ts | 9 ++--- src/cmd-remove.ts | 8 ++--- src/types/global.ts | 8 +---- src/types/scoped-registry.ts | 65 ++++++++++++++++++++++++++++++++++++ test/data-pkg-manifest.ts | 12 +++---- test/manifest-assertions.ts | 3 +- test/test-scoped-registry.ts | 47 ++++++++++++++++++++++++++ 7 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 src/types/scoped-registry.ts create mode 100644 test/test-scoped-registry.ts diff --git a/src/cmd-add.ts b/src/cmd-add.ts index ce2c8f4a..363c7856 100644 --- a/src/cmd-add.ts +++ b/src/cmd-add.ts @@ -1,7 +1,7 @@ import log from "./logger"; import url from "url"; import { isPackageUrl } from "./types/package-url"; -import { GlobalOptions, ScopedRegistry } from "./types/global"; +import { GlobalOptions } from "./types/global"; import { tryGetLatestVersion } from "./types/pkg-info"; import { loadManifest, saveManifest } from "./utils/manifest"; import { env, parseEnv } from "./utils/env"; @@ -17,6 +17,7 @@ import { PackageReference, splitPackageReference, } from "./types/package-reference"; +import { scopedRegistry, ScopedRegistry } from "./types/scoped-registry"; export type AddOptions = { test?: boolean; @@ -223,11 +224,7 @@ const _add = async function ({ if (manifest.scopedRegistries.filter(filterEntry).length <= 0) { const name = url.parse(env.registry).hostname; if (name === null) throw new Error("Could not resolve registry name"); - manifest.scopedRegistries.push({ - name, - url: env.registry, - scopes: [], - }); + manifest.scopedRegistries.push(scopedRegistry(name, env.registry)); dirty = true; } const entry = manifest.scopedRegistries.filter(filterEntry)[0]; diff --git a/src/cmd-remove.ts b/src/cmd-remove.ts index b6c93c93..4c6cb77c 100644 --- a/src/cmd-remove.ts +++ b/src/cmd-remove.ts @@ -1,5 +1,5 @@ import log from "./logger"; -import { GlobalOptions, ScopedRegistry } from "./types/global"; +import { GlobalOptions } from "./types/global"; import { loadManifest, saveManifest } from "./utils/manifest"; import { env, parseEnv } from "./utils/env"; import { isDomainName } from "./types/domain-name"; @@ -8,6 +8,7 @@ import { PackageReference, splitPackageReference, } from "./types/package-reference"; +import { hasScope, removeScope, ScopedRegistry } from "./types/scoped-registry"; export type RemoveOptions = { _global: GlobalOptions; @@ -72,9 +73,8 @@ const _remove = async function (pkg: PackageReference) { const entires = manifest.scopedRegistries.filter(filterEntry); if (entires.length > 0) { const entry = entires[0]; - const index = entry.scopes.indexOf(name); - if (index > -1) { - entry.scopes.splice(index, 1); + if (hasScope(entry, name)) { + removeScope(entry, name); const scopesSet = new Set(entry.scopes); if (isDomainName(env.namespace)) scopesSet.add(env.namespace); entry.scopes = Array.from(scopesSet).sort(); diff --git a/src/types/global.ts b/src/types/global.ts index eaaeaf0f..e4eaa4e0 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -2,7 +2,7 @@ import { DomainName } from "./domain-name"; import { PackageUrl } from "./package-url"; import { SemanticVersion } from "./semantic-version"; import { PackageId } from "./package-id"; -import { RegistryUrl } from "./registry-url"; +import { ScopedRegistry } from "./scoped-registry"; export type Region = "us" | "cn"; @@ -56,12 +56,6 @@ export type Dependency = { resolved?: boolean; }; -export type ScopedRegistry = { - name: string; - url: RegistryUrl; - scopes: DomainName[]; -}; - export type PkgManifest = { dependencies: Record; scopedRegistries?: ScopedRegistry[]; diff --git a/src/types/scoped-registry.ts b/src/types/scoped-registry.ts new file mode 100644 index 00000000..bd5ccd81 --- /dev/null +++ b/src/types/scoped-registry.ts @@ -0,0 +1,65 @@ +import { RegistryUrl } from "./registry-url"; +import { DomainName } from "./domain-name"; + +/** + * Contains information about a scoped registry + * @see https://docs.unity3d.com/Manual/upm-scoped.html + */ +export type ScopedRegistry = { + /** + * The scope name as it appears in the user interface + */ + name: string; + /** + * The url to the npm-compatible registry server + */ + url: RegistryUrl; + /** + * Array of scopes that you can map to a package name, either as an exact match + * on the package name, or as a namespace + */ + scopes: DomainName[]; +}; + +/** + * Constructs a scoped registry + * @param name The name + * @param url The url + * @param scopes The scopes. If not specified defaults to empty array + */ +export function scopedRegistry( + name: string, + url: RegistryUrl, + scopes?: DomainName[] +): ScopedRegistry { + return { name, url, scopes: scopes ?? [] }; +} + +/** + * Adds a scope to a registry. The list will be sorted alphabetically + * @param registry The registry + * @param scope The scope + */ +export function addScope(registry: ScopedRegistry, scope: DomainName) { + registry.scopes.push(scope); + registry.scopes.sort(); +} + +/** + * Checks if a registry has a specific scope + * @param registry The registry + * @param scope The scope + */ +export function hasScope(registry: ScopedRegistry, scope: DomainName): boolean { + return registry.scopes.includes(scope); +} + +/** + * Removes a scope from a registry + * @param registry The registry + * @param scope The scope + */ +export function removeScope(registry: ScopedRegistry, scope: DomainName) { + const index = registry.scopes.indexOf(scope); + if (index >= 0) registry.scopes.splice(index, 1); +} diff --git a/test/data-pkg-manifest.ts b/test/data-pkg-manifest.ts index ea6404fe..0a0a33fc 100644 --- a/test/data-pkg-manifest.ts +++ b/test/data-pkg-manifest.ts @@ -3,6 +3,7 @@ import assert from "assert"; import { domainName, isDomainName } from "../src/types/domain-name"; import { exampleRegistryUrl } from "./mock-registry"; import { isSemanticVersion } from "../src/types/semantic-version"; +import { addScope, scopedRegistry } from "../src/types/scoped-registry"; /** * Builder class for {@link PkgManifest} @@ -25,16 +26,13 @@ class PkgManifestBuilder { if (this.manifest.scopedRegistries === undefined) this.manifest.scopedRegistries = [ - { - name: "example.com", - scopes: [domainName("com.example")], - url: exampleRegistryUrl, - }, + scopedRegistry("example.com", exampleRegistryUrl, [ + domainName("com.example"), + ]), ]; const registry = this.manifest.scopedRegistries![0]; - registry.scopes = [name, ...registry.scopes]; - registry.scopes.sort(); + addScope(registry, name); return this; } diff --git a/test/manifest-assertions.ts b/test/manifest-assertions.ts index 9cbbd2c6..a5783a63 100644 --- a/test/manifest-assertions.ts +++ b/test/manifest-assertions.ts @@ -4,6 +4,7 @@ import should from "should"; import { DomainName } from "../src/types/domain-name"; import { SemanticVersion } from "../src/types/semantic-version"; import { PackageUrl } from "../src/types/package-url"; +import { hasScope } from "../src/types/scoped-registry"; export function shouldHaveManifest(): PkgManifest { const manifest = loadManifest(); @@ -42,7 +43,7 @@ export function shouldHaveRegistryWithScopes( should(manifest.scopedRegistries).not.be.undefined(); manifest .scopedRegistries!.some((registry) => - scopes.every((scope) => registry.scopes.includes(scope)) + scopes.every((scope) => hasScope(registry, scope)) ) .should.be.true("At least one scope was missing"); } diff --git a/test/test-scoped-registry.ts b/test/test-scoped-registry.ts new file mode 100644 index 00000000..0a9fc7ac --- /dev/null +++ b/test/test-scoped-registry.ts @@ -0,0 +1,47 @@ +import { describe } from "mocha"; +import { + addScope, + hasScope, + removeScope, + scopedRegistry, +} from "../src/types/scoped-registry"; +import { exampleRegistryUrl } from "./mock-registry"; +import should from "should"; +import { domainName } from "../src/types/domain-name"; + +describe("scoped-registry", function () { + describe("construction", function () { + it("should have empty scopes list if scopes are not specified", () => { + const registry = scopedRegistry("test", exampleRegistryUrl); + should(registry.scopes).be.empty(); + }); + }); + describe("add scope", function () { + it("should keep scope-list alphabetical", () => { + const registry = scopedRegistry("test", exampleRegistryUrl); + addScope(registry, domainName("b")); + addScope(registry, domainName("a")); + should(registry.scopes).be.deepEqual(["a", "b"]); + }); + }); + describe("has scope", function () { + it("should have scope that was added", () => { + const registry = scopedRegistry("test", exampleRegistryUrl); + addScope(registry, domainName("a")); + should(hasScope(registry, domainName("a"))).be.true(); + }); + it("should not have scope that was not added", () => { + const registry = scopedRegistry("test", exampleRegistryUrl); + should(hasScope(registry, domainName("a"))).be.false(); + }); + }); + describe("remove scope", function () { + it("should not have scope after removing it", () => { + const registry = scopedRegistry("test", exampleRegistryUrl, [ + domainName("a"), + ]); + removeScope(registry, domainName("a")); + should(hasScope(registry, domainName("a"))).be.false(); + }); + }); +}); From 20ccac63cb57128554a074c15b8dfe07cd36d5d7 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:35:20 +0100 Subject: [PATCH 18/27] refactor: make type local --- src/registry-client.ts | 7 ++++++- src/types/global.ts | 5 +---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/registry-client.ts b/src/registry-client.ts index 8452bc75..df76b9dc 100644 --- a/src/registry-client.ts +++ b/src/registry-client.ts @@ -8,7 +8,7 @@ import RegClient, { import log from "./logger"; import request from "request"; import assert, { AssertionError } from "assert"; -import { Dependency, NameVersionPair } from "./types/global"; +import { Dependency } from "./types/global"; import { env } from "./utils/env"; import _ from "lodash"; import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; @@ -44,6 +44,11 @@ export class NpmClientError extends Error { } } +type NameVersionPair = { + name: DomainName; + version: SemanticVersion | "latest" | undefined; +}; + export function assertIsNpmClientError( x: unknown ): asserts x is NpmClientError { diff --git a/src/types/global.ts b/src/types/global.ts index e4eaa4e0..91b000ba 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -41,10 +41,7 @@ export type PkgVersionInfo = { dist?: Dist; }; -export type NameVersionPair = { - name: DomainName; - version: SemanticVersion | "latest" | undefined; -}; + export type Dependency = { name: DomainName; From aa5b7765d6dead5dd2bab8d4f6595b6755462a40 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:37:18 +0100 Subject: [PATCH 19/27] refactor: make type local --- src/registry-client.ts | 12 +++++++++++- src/types/global.ts | 10 ---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/registry-client.ts b/src/registry-client.ts index df76b9dc..5cbf9208 100644 --- a/src/registry-client.ts +++ b/src/registry-client.ts @@ -8,7 +8,6 @@ import RegClient, { import log from "./logger"; import request from "request"; import assert, { AssertionError } from "assert"; -import { Dependency } from "./types/global"; import { env } from "./utils/env"; import _ from "lodash"; import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; @@ -44,6 +43,16 @@ export class NpmClientError extends Error { } } +export type Dependency = { + name: DomainName; + version?: SemanticVersion; + upstream: boolean; + self: boolean; + internal: boolean; + reason: string | null; + resolved?: boolean; +}; + type NameVersionPair = { name: DomainName; version: SemanticVersion | "latest" | undefined; @@ -108,6 +117,7 @@ export const fetchPackageInfo = async function ( // eslint-disable-next-line no-empty } catch (err) {} }; + /* Fetch package [valid dependencies, invalid dependencies] with a structure of [ { diff --git a/src/types/global.ts b/src/types/global.ts index 91b000ba..bd398d47 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -43,16 +43,6 @@ export type PkgVersionInfo = { -export type Dependency = { - name: DomainName; - version?: SemanticVersion; - upstream: boolean; - self: boolean; - internal: boolean; - reason: string | null; - resolved?: boolean; -}; - export type PkgManifest = { dependencies: Record; scopedRegistries?: ScopedRegistry[]; From d69ab34c8a126471dbb6872ef989da66b282e46c Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 14:39:50 +0100 Subject: [PATCH 20/27] refactor: make type local --- src/types/global.ts | 4 ---- src/utils/env.ts | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/types/global.ts b/src/types/global.ts index bd398d47..053d8cde 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -4,8 +4,6 @@ import { SemanticVersion } from "./semantic-version"; import { PackageId } from "./package-id"; import { ScopedRegistry } from "./scoped-registry"; -export type Region = "us" | "cn"; - export type Dist = { tarball: string; shasum: string; @@ -41,8 +39,6 @@ export type PkgVersionInfo = { dist?: Dist; }; - - export type PkgManifest = { dependencies: Record; scopedRegistries?: ScopedRegistry[]; diff --git a/src/utils/env.ts b/src/utils/env.ts index c7a5ef4a..87d60a2a 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,4 +1,4 @@ -import { GlobalOptions, Region } from "../types/global"; +import { GlobalOptions } from "../types/global"; import log from "../logger"; import chalk from "chalk"; import { loadUpmConfig } from "./upm-config-io"; @@ -27,6 +27,8 @@ import { import { encodeBase64 } from "../types/base64"; import { NpmAuth } from "another-npm-registry-client"; +type Region = "us" | "cn"; + export type Env = { cwd: string; color: boolean; From 7d4ffbc780f35bb1792496a225e1ff9d99d18d27 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sat, 25 Nov 2023 15:13:58 +0100 Subject: [PATCH 21/27] refactor: extract module Move PkgManifest type to own module and create helper functions with tests. Also rename the manifest file and corresponding test file to pkg-manifest-io since that is what the module is there for --- src/cmd-add.ts | 37 +++---- src/cmd-remove.ts | 47 ++++----- src/types/global.ts | 8 -- src/types/pkg-manifest.ts | 98 +++++++++++++++++++ src/utils/{manifest.ts => pkg-manifest-io.ts} | 2 +- test/data-pkg-manifest.ts | 17 ++-- test/manifest-assertions.ts | 4 +- test/mock-work-dir.ts | 4 +- ...st-manifest.ts => test-pkg-manifest-io.ts} | 7 +- test/test-pkg-manifest.ts | 71 ++++++++++++++ 10 files changed, 221 insertions(+), 74 deletions(-) create mode 100644 src/types/pkg-manifest.ts rename src/utils/{manifest.ts => pkg-manifest-io.ts} (95%) rename test/{test-manifest.ts => test-pkg-manifest-io.ts} (91%) create mode 100644 test/test-pkg-manifest.ts diff --git a/src/cmd-add.ts b/src/cmd-add.ts index 363c7856..bd2a438d 100644 --- a/src/cmd-add.ts +++ b/src/cmd-add.ts @@ -3,7 +3,7 @@ import url from "url"; import { isPackageUrl } from "./types/package-url"; import { GlobalOptions } from "./types/global"; import { tryGetLatestVersion } from "./types/pkg-info"; -import { loadManifest, saveManifest } from "./utils/manifest"; +import { loadManifest, saveManifest } from "./utils/pkg-manifest-io"; import { env, parseEnv } from "./utils/env"; import { compareEditorVersion, @@ -17,7 +17,13 @@ import { PackageReference, splitPackageReference, } from "./types/package-reference"; -import { scopedRegistry, ScopedRegistry } from "./types/scoped-registry"; +import { scopedRegistry } from "./types/scoped-registry"; +import { + addDependency, + addScopedRegistry, + addTestable, + tryGetScopedRegistryByUrl, +} from "./types/pkg-manifest"; export type AddOptions = { test?: boolean; @@ -77,10 +83,6 @@ const _add = async function ({ // load manifest const manifest = loadManifest(); if (manifest === null) return { code: 1, dirty }; - // ensure manifest.dependencies - if (!manifest.dependencies) { - manifest.dependencies = {}; - } // packages that added to scope registry const pkgsInScope: DomainName[] = []; if (version === undefined || !isPackageUrl(version)) { @@ -197,7 +199,7 @@ const _add = async function ({ } // add to dependencies const oldVersion = manifest.dependencies[name]; - manifest.dependencies[name] = version; + addDependency(manifest, name, version); if (!oldVersion) { // Log the added package log.notice("manifest", `added ${packageReference(name, version)}`); @@ -216,18 +218,14 @@ const _add = async function ({ manifest.scopedRegistries = []; dirty = true; } - const filterEntry = (x: ScopedRegistry): boolean => { - let addr = x.url || ""; - if (addr.endsWith("/")) addr = addr.slice(0, -1); - return addr == env.registry; - }; - if (manifest.scopedRegistries.filter(filterEntry).length <= 0) { + let entry = tryGetScopedRegistryByUrl(manifest, env.registry); + if (entry === null) { const name = url.parse(env.registry).hostname; if (name === null) throw new Error("Could not resolve registry name"); - manifest.scopedRegistries.push(scopedRegistry(name, env.registry)); + entry = scopedRegistry(name, env.registry); + addScopedRegistry(manifest, entry); dirty = true; } - const entry = manifest.scopedRegistries.filter(filterEntry)[0]; // apply pkgsInScope const scopesSet = new Set(entry.scopes || []); if (isDomainName(env.namespace)) pkgsInScope.push(env.namespace); @@ -239,14 +237,7 @@ const _add = async function ({ }); entry.scopes = Array.from(scopesSet).sort(); } - if (testables) { - if (!manifest.testables) { - manifest.testables = []; - } - if (manifest.testables.indexOf(name) === -1) { - manifest.testables.push(name); - } - } + if (testables) addTestable(manifest, name); // save manifest if (dirty) { if (!saveManifest(manifest)) return { code: 1, dirty }; diff --git a/src/cmd-remove.ts b/src/cmd-remove.ts index 4c6cb77c..dfe7793c 100644 --- a/src/cmd-remove.ts +++ b/src/cmd-remove.ts @@ -1,6 +1,6 @@ import log from "./logger"; import { GlobalOptions } from "./types/global"; -import { loadManifest, saveManifest } from "./utils/manifest"; +import { loadManifest, saveManifest } from "./utils/pkg-manifest-io"; import { env, parseEnv } from "./utils/env"; import { isDomainName } from "./types/domain-name"; import { @@ -8,7 +8,11 @@ import { PackageReference, splitPackageReference, } from "./types/package-reference"; -import { hasScope, removeScope, ScopedRegistry } from "./types/scoped-registry"; +import { hasScope, removeScope } from "./types/scoped-registry"; +import { + removeDependency, + tryGetScopedRegistryByUrl, +} from "./types/pkg-manifest"; export type RemoveOptions = { _global: GlobalOptions; @@ -54,32 +58,21 @@ const _remove = async function (pkg: PackageReference) { if (manifest === null) return { code: 1, dirty }; // not found array const pkgsNotFound = []; - // remove from dependencies - if (manifest.dependencies) { - version = manifest.dependencies[name]; - if (version) { - log.notice("manifest", `removed ${packageReference(name, version)}`); - delete manifest.dependencies[name]; + version = manifest.dependencies[name]; + if (version) { + log.notice("manifest", `removed ${packageReference(name, version)}`); + removeDependency(manifest, name); + dirty = true; + } else pkgsNotFound.push(pkg); + + const entry = tryGetScopedRegistryByUrl(manifest, env.registry); + if (entry !== null) { + if (hasScope(entry, name)) { + removeScope(entry, name); + const scopesSet = new Set(entry.scopes); + if (isDomainName(env.namespace)) scopesSet.add(env.namespace); + entry.scopes = Array.from(scopesSet).sort(); dirty = true; - } else pkgsNotFound.push(pkg); - } - // remove from scopedRegistries - if (manifest.scopedRegistries) { - const filterEntry = (x: ScopedRegistry) => { - let url = x.url || ""; - if (url.endsWith("/")) url = url.slice(0, -1); - return url == env.registry; - }; - const entires = manifest.scopedRegistries.filter(filterEntry); - if (entires.length > 0) { - const entry = entires[0]; - if (hasScope(entry, name)) { - removeScope(entry, name); - const scopesSet = new Set(entry.scopes); - if (isDomainName(env.namespace)) scopesSet.add(env.namespace); - entry.scopes = Array.from(scopesSet).sort(); - dirty = true; - } } } // save manifest diff --git a/src/types/global.ts b/src/types/global.ts index 053d8cde..ea78a25a 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -1,8 +1,6 @@ import { DomainName } from "./domain-name"; -import { PackageUrl } from "./package-url"; import { SemanticVersion } from "./semantic-version"; import { PackageId } from "./package-id"; -import { ScopedRegistry } from "./scoped-registry"; export type Dist = { tarball: string; @@ -39,12 +37,6 @@ export type PkgVersionInfo = { dist?: Dist; }; -export type PkgManifest = { - dependencies: Record; - scopedRegistries?: ScopedRegistry[]; - testables?: string[]; -}; - export type GlobalOptions = { registry?: string; verbose?: boolean; diff --git a/src/types/pkg-manifest.ts b/src/types/pkg-manifest.ts new file mode 100644 index 00000000..54d99295 --- /dev/null +++ b/src/types/pkg-manifest.ts @@ -0,0 +1,98 @@ +import { DomainName } from "./domain-name"; +import { SemanticVersion } from "./semantic-version"; +import { PackageUrl } from "./package-url"; +import { ScopedRegistry } from "./scoped-registry"; +import { RegistryUrl, removeTrailingSlash } from "./registry-url"; + +/** + * The content of the package-manifest (manifest.json) of a Unity project + * @see https://docs.unity3d.com/Manual/upm-manifestPrj.html + */ +export type PkgManifest = { + /** + * Direct dependencies, keyed by their name. Version can be either a + * semantic version or package-url + */ + dependencies: Record; + /** + * Scoped-registries for this project + */ + scopedRegistries?: ScopedRegistry[]; + /** + * Testable package-names + */ + testables?: DomainName[]; +}; + +/** + * Constructs an empty package-manifest + */ +export function emptyPackageManifest(): PkgManifest { + return { dependencies: {} }; +} + +/** + * Adds a dependency to the manifest. If a dependency with that name already + * exists, the version is overwritten + * @param manifest The manifest + * @param name The dependency name + * @param version The dependency version or url + */ +export function addDependency( + manifest: PkgManifest, + name: DomainName, + version: SemanticVersion | PackageUrl +) { + manifest.dependencies[name] = version; +} + +/** + * Removes a dependency from a manifest + * @param manifest The manifest + * @param name The dependency name + */ +export function removeDependency(manifest: PkgManifest, name: DomainName) { + delete manifest.dependencies[name]; +} + +/** + * Attempts to get a scoped-registry with a specific url from the manifest + * @param manifest The manifest + * @param url The url + * @returns The scoped-registry or null if not found + */ +export function tryGetScopedRegistryByUrl( + manifest: PkgManifest, + url: RegistryUrl +): ScopedRegistry | null { + function hasCorrectUrl(registry: ScopedRegistry): boolean { + return removeTrailingSlash(registry.url) === url; + } + + return manifest.scopedRegistries?.find(hasCorrectUrl) ?? null; +} + +/** + * Adds a scoped-registry to the manifest. + * NOTE: Does not check if a scoped-registry with the same name already exists + * @param manifest The manifest + * @param scopedRegistry The scoped-registry + */ +export function addScopedRegistry( + manifest: PkgManifest, + scopedRegistry: ScopedRegistry +) { + if (manifest.scopedRegistries === undefined) manifest.scopedRegistries = []; + manifest.scopedRegistries.push(scopedRegistry); +} + +/** + * Adds a testable to the manifest, if it is not already added + * @param manifest The manifest + * @param name The testable name + */ +export function addTestable(manifest: PkgManifest, name: DomainName) { + if (!manifest.testables) manifest.testables = []; + if (manifest.testables.indexOf(name) === -1) manifest.testables.push(name); + manifest.testables.sort(); +} diff --git a/src/utils/manifest.ts b/src/utils/pkg-manifest-io.ts similarity index 95% rename from src/utils/manifest.ts rename to src/utils/pkg-manifest-io.ts index 25fa3ed8..8941ab61 100644 --- a/src/utils/manifest.ts +++ b/src/utils/pkg-manifest-io.ts @@ -1,8 +1,8 @@ -import { PkgManifest } from "../types/global"; import fs from "fs"; import { assertIsError } from "./error-type-guards"; import log from "../logger"; import { env } from "./env"; +import { PkgManifest } from "../types/pkg-manifest"; /** * Attempts to load the manifest from the path specified in env diff --git a/test/data-pkg-manifest.ts b/test/data-pkg-manifest.ts index 0a0a33fc..20151b8f 100644 --- a/test/data-pkg-manifest.ts +++ b/test/data-pkg-manifest.ts @@ -1,9 +1,14 @@ -import { PkgManifest } from "../src/types/global"; import assert from "assert"; import { domainName, isDomainName } from "../src/types/domain-name"; import { exampleRegistryUrl } from "./mock-registry"; import { isSemanticVersion } from "../src/types/semantic-version"; import { addScope, scopedRegistry } from "../src/types/scoped-registry"; +import { + addDependency, + addTestable, + emptyPackageManifest, + PkgManifest, +} from "../src/types/pkg-manifest"; /** * Builder class for {@link PkgManifest} @@ -12,9 +17,7 @@ class PkgManifestBuilder { readonly manifest: PkgManifest; constructor() { - this.manifest = { - dependencies: {}, - }; + this.manifest = emptyPackageManifest(); } /** @@ -43,9 +46,7 @@ class PkgManifestBuilder { */ addTestable(name: string): PkgManifestBuilder { assert(isDomainName(name), `${name} is domain name`); - if (this.manifest.testables === undefined) this.manifest.testables = []; - this.manifest.testables.push(name); - this.manifest.testables.sort(); + addTestable(this.manifest, name); return this; } @@ -66,7 +67,7 @@ class PkgManifestBuilder { assert(isSemanticVersion(version), `${version} is semantic version`); if (withScope) this.addScope(name); if (testable) this.addTestable(name); - this.manifest.dependencies[name] = version; + addDependency(this.manifest, name, version); return this; } } diff --git a/test/manifest-assertions.ts b/test/manifest-assertions.ts index a5783a63..b10794ba 100644 --- a/test/manifest-assertions.ts +++ b/test/manifest-assertions.ts @@ -1,10 +1,10 @@ -import { PkgManifest } from "../src/types/global"; -import { loadManifest } from "../src/utils/manifest"; +import { loadManifest } from "../src/utils/pkg-manifest-io"; import should from "should"; import { DomainName } from "../src/types/domain-name"; import { SemanticVersion } from "../src/types/semantic-version"; import { PackageUrl } from "../src/types/package-url"; import { hasScope } from "../src/types/scoped-registry"; +import { PkgManifest } from "../src/types/pkg-manifest"; export function shouldHaveManifest(): PkgManifest { const manifest = loadManifest(); diff --git a/test/mock-work-dir.ts b/test/mock-work-dir.ts index acc8e39c..fd795ea5 100644 --- a/test/mock-work-dir.ts +++ b/test/mock-work-dir.ts @@ -1,8 +1,8 @@ import path from "path"; import os from "os"; -import { PkgManifest } from "../src/types/global"; import fse from "fs-extra"; import _ from "lodash"; +import { emptyPackageManifest, PkgManifest } from "../src/types/pkg-manifest"; export type ManifestCreationOptions = { manifest: boolean | PkgManifest; @@ -18,7 +18,7 @@ export const createWorkDir = function ( const workDir = getWorkDir(pathToTmp); fse.mkdirpSync(workDir); if (manifest) { - if (!_.isObjectLike(manifest)) manifest = { dependencies: {} }; + if (!_.isObjectLike(manifest)) manifest = emptyPackageManifest(); const manifestDir = path.join(workDir, "Packages"); fse.mkdirpSync(manifestDir); const data = JSON.stringify(manifest); diff --git a/test/test-manifest.ts b/test/test-pkg-manifest-io.ts similarity index 91% rename from test/test-manifest.ts rename to test/test-pkg-manifest-io.ts index 8ab18eb4..2f020b8c 100644 --- a/test/test-manifest.ts +++ b/test/test-pkg-manifest-io.ts @@ -2,7 +2,7 @@ import { attachMockConsole, MockConsole } from "./mock-console"; import fs from "fs"; import "should"; import path from "path"; -import { saveManifest } from "../src/utils/manifest"; +import { saveManifest } from "../src/utils/pkg-manifest-io"; import { describe } from "mocha"; import { parseEnv } from "../src/utils/env"; import { createWorkDir, getWorkDir, removeWorkDir } from "./mock-work-dir"; @@ -13,8 +13,9 @@ import { } from "./manifest-assertions"; import { domainName } from "../src/types/domain-name"; import { semanticVersion } from "../src/types/semantic-version"; +import { addDependency } from "../src/types/pkg-manifest"; -describe("manifest", function () { +describe("pkg-manifest io", function () { let mockConsole: MockConsole = null!; beforeEach(function () { removeWorkDir("test-openupm-cli"); @@ -75,7 +76,7 @@ describe("manifest", function () { ).should.be.ok(); const manifest = shouldHaveManifest(); shouldNotHaveAnyDependencies(manifest); - manifest.dependencies[domainName("some-pack")] = semanticVersion("1.0.0"); + addDependency(manifest, domainName("some-pack"), semanticVersion("1.0.0")); saveManifest(manifest).should.be.ok(); const manifest2 = shouldHaveManifest(); manifest2.should.be.deepEqual(manifest); diff --git a/test/test-pkg-manifest.ts b/test/test-pkg-manifest.ts new file mode 100644 index 00000000..0ed6340a --- /dev/null +++ b/test/test-pkg-manifest.ts @@ -0,0 +1,71 @@ +import { describe } from "mocha"; +import { + addDependency, + addScopedRegistry, + addTestable, + emptyPackageManifest, + removeDependency, + tryGetScopedRegistryByUrl, +} from "../src/types/pkg-manifest"; +import { domainName } from "../src/types/domain-name"; +import { semanticVersion } from "../src/types/semantic-version"; +import should from "should"; +import { scopedRegistry } from "../src/types/scoped-registry"; +import { registryUrl } from "../src/types/registry-url"; + +describe("pkg-manifest", function () { + describe("dependency", function () { + it("should add dependency when adding first time", () => { + const manifest = emptyPackageManifest(); + addDependency(manifest, domainName("test"), semanticVersion("1.2.3")); + should(manifest.dependencies).deepEqual({ test: "1.2.3" }); + }); + it("should overwrite dependency when adding second time", () => { + const manifest = emptyPackageManifest(); + addDependency(manifest, domainName("test"), semanticVersion("1.2.3")); + addDependency(manifest, domainName("test"), semanticVersion("2.3.4")); + should(manifest.dependencies).deepEqual({ test: "2.3.4" }); + }); + it("should remove existing dependency", () => { + const manifest = emptyPackageManifest(); + addDependency(manifest, domainName("test"), semanticVersion("1.2.3")); + removeDependency(manifest, domainName("test")); + should(manifest.dependencies).deepEqual({}); + }); + it("should do nothing when dependency does not exist", () => { + const manifest = emptyPackageManifest(); + removeDependency(manifest, domainName("test")); + should(manifest.dependencies).deepEqual({}); + }); + }); + describe("scoped-registry", function () { + it("should should find scoped-registry with url if present", () => { + const manifest = emptyPackageManifest(); + const url = registryUrl("https://test.com"); + const expected = scopedRegistry("test", url); + addScopedRegistry(manifest, expected); + should(tryGetScopedRegistryByUrl(manifest, url)).be.deepEqual(expected); + }); + it("should should not find scoped-registry with incorrect url", () => { + const manifest = emptyPackageManifest(); + const url = registryUrl("https://test.com"); + const expected = scopedRegistry("test", registryUrl("https://test2.com")); + addScopedRegistry(manifest, expected); + should(tryGetScopedRegistryByUrl(manifest, url)).be.null(); + }); + }); + describe("testables", function () { + it("should not add testables which already exist", () => { + const manifest = emptyPackageManifest(); + addTestable(manifest, domainName("a")); + addTestable(manifest, domainName("a")); + should(manifest.testables).deepEqual(["a"]); + }); + it("should add testables in alphabetical order", () => { + const manifest = emptyPackageManifest(); + addTestable(manifest, domainName("b")); + addTestable(manifest, domainName("a")); + should(manifest.testables).deepEqual(["a", "b"]); + }); + }); +}); From 85729679bde2052e2e3da66cba541009647360af Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sun, 26 Nov 2023 17:29:19 +0100 Subject: [PATCH 22/27] refactor: move type to own module Also add type documentation where I knew what to write --- src/types/global.ts | 33 -------------- src/types/pkg-info.ts | 2 +- src/types/pkg-version-info.ts | 81 +++++++++++++++++++++++++++++++++++ test/data-pkg-info.ts | 2 +- 4 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 src/types/pkg-version-info.ts diff --git a/src/types/global.ts b/src/types/global.ts index ea78a25a..df3bccbf 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -1,42 +1,9 @@ -import { DomainName } from "./domain-name"; -import { SemanticVersion } from "./semantic-version"; -import { PackageId } from "./package-id"; - -export type Dist = { - tarball: string; - shasum: string; - integrity: string; -}; - export type Contact = { name: string; email?: string; url?: string; }; -export type PkgVersionInfo = { - _id?: PackageId; - _nodeVersion?: string; - _npmVersion?: string; - _rev?: string; - name: string; - version: SemanticVersion; - unity?: string; - unityRelease?: string; - dependencies?: Record; - license?: string; - displayName?: string; - description?: string; - keywords?: string[]; - homepage?: string; - category?: string; - gitHead?: string; - readmeFilename?: string; - author?: Contact; - contributors?: Contact[]; - dist?: Dist; -}; - export type GlobalOptions = { registry?: string; verbose?: boolean; diff --git a/src/types/pkg-info.ts b/src/types/pkg-info.ts index 851f9a8f..57bba4e4 100644 --- a/src/types/pkg-info.ts +++ b/src/types/pkg-info.ts @@ -1,6 +1,6 @@ import { SemanticVersion } from "./semantic-version"; import { DomainName } from "./domain-name"; -import { PkgVersionInfo } from "./global"; +import { PkgVersionInfo } from "./pkg-version-info"; /** * Describes a package diff --git a/src/types/pkg-version-info.ts b/src/types/pkg-version-info.ts new file mode 100644 index 00000000..410d9b94 --- /dev/null +++ b/src/types/pkg-version-info.ts @@ -0,0 +1,81 @@ +import { PackageId } from "./package-id"; +import { SemanticVersion } from "./semantic-version"; +import { DomainName } from "./domain-name"; +import { Contact } from "./global"; + +/** + * Distribution information + */ +type Dist = { + tarball: string; + shasum: string; + integrity: string; +}; + +/** + * Contains information about a specific version of a package. This is based on + * the information contained inside a Unity package manifest, with some + * additions. + * @see https://docs.unity3d.com/Manual/upm-manifestPkg.html + */ +export type PkgVersionInfo = { + /** + * Same as {@link name} + */ + _id?: PackageId; + _nodeVersion?: string; + _npmVersion?: string; + _rev?: string; + /** + * The package name + */ + name: string; + /** + * The version + */ + version: SemanticVersion; + /** + * Indicates the lowest Unity version the package is compatible with. + * The expected format is ".". + * @example 2020.2 + */ + unity?: `${number}.${number}`; + /** + * Part of a Unity version indicating the specific release of Unity that the + * package is compatible with. + * The expected format is "". + * @example 0b4 + */ + unityRelease?: string; + /** + * A map of package dependencies. Keys are package names, and values are + * specific versions. + */ + dependencies?: Record; + /** + * Identifier for an OSS license using the SPDX identifier format. + */ + license?: string; + /** + * A user-friendly name to appear in the Unity Editor. + */ + displayName?: string; + /** + * A brief description of the package. + */ + description?: string; + /** + * An array of keywords used by the Package Manager search APIs. + */ + keywords?: string[]; + homepage?: string; + category?: string; + gitHead?: string; + readmeFilename?: string; + /** + * The author of the package. + */ + author?: Contact; + contributors?: Contact[]; + dist?: Dist; +}; diff --git a/test/data-pkg-info.ts b/test/data-pkg-info.ts index c3eda776..d18ebc1f 100644 --- a/test/data-pkg-info.ts +++ b/test/data-pkg-info.ts @@ -6,7 +6,7 @@ import { } from "../src/types/semantic-version"; import { packageId } from "../src/types/package-id"; import { PkgInfo } from "../src/types/pkg-info"; -import { PkgVersionInfo } from "../src/types/global"; +import { PkgVersionInfo } from "../src/types/pkg-version-info"; /** * Builder class for {@link PkgVersionInfo} From ecc5aebf51a6e3a7ffe2ba21402a71bbfa629a0e Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sun, 26 Nov 2023 18:23:53 +0100 Subject: [PATCH 23/27] refactor: add prompt utilities --- src/cmd-login.ts | 26 +++++++++++--------------- src/utils/prompts.ts | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 src/utils/prompts.ts diff --git a/src/cmd-login.ts b/src/cmd-login.ts index 7592b1bd..68bdbd2c 100644 --- a/src/cmd-login.ts +++ b/src/cmd-login.ts @@ -1,11 +1,8 @@ import fs from "fs"; import path from "path"; import _ from "lodash"; -import promptly from "promptly"; import { assertIsNpmClientError, getNpmClient } from "./registry-client"; - import log from "./logger"; - import { GlobalOptions } from "./types/global"; import { getUpmConfigDir, @@ -13,13 +10,15 @@ import { saveUpmConfig, } from "./utils/upm-config-io"; import { parseEnv } from "./utils/env"; -import { - RegistryUrl, - registryUrl, - removeTrailingSlash, -} from "./types/registry-url"; import { encodeBasicAuth } from "./types/upm-config"; import { Base64 } from "./types/base64"; +import { RegistryUrl, removeTrailingSlash } from "./types/registry-url"; +import { + promptEmail, + promptPassword, + promptRegistryUrl, + promptUsername, +} from "./utils/prompts"; export type LoginOptions = { username?: string; @@ -35,14 +34,11 @@ export const login = async function (options: LoginOptions) { const envOk = await parseEnv(options, { checkPath: false }); if (!envOk) return 1; // query parameters - if (!options.username) options.username = await promptly.prompt("Username: "); - if (!options.password) - options.password = await promptly.password("Password: "); - if (!options.email) options.email = await promptly.prompt("Email: "); + if (!options.username) options.username = await promptUsername(); + if (!options.password) options.password = await promptPassword(); + if (!options.email) options.email = await promptEmail(); if (!options._global.registry) - options._global.registry = (await promptly.prompt("Registry: ", { - validator: [registryUrl], - })) as RegistryUrl; + options._global.registry = await promptRegistryUrl(); let token: string | null = null; let _auth: Base64 | null = null; if (options.basicAuth) { diff --git a/src/utils/prompts.ts b/src/utils/prompts.ts new file mode 100644 index 00000000..b966f2e2 --- /dev/null +++ b/src/utils/prompts.ts @@ -0,0 +1,20 @@ +import promptly from "promptly"; +import { registryUrl, RegistryUrl } from "../types/registry-url"; + +export function promptUsername(): Promise { + return promptly.prompt("Username: "); +} + +export function promptPassword(): Promise { + return promptly.password("Password: "); +} + +export function promptEmail(): Promise { + return promptly.prompt("Email: "); +} + +export function promptRegistryUrl(): Promise { + return promptly.prompt("Registry: ", { + validator: [registryUrl], + }) as Promise; +} From 4acba700fd0c24f75e2bf35de9eb7e7e60e4490a Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sun, 26 Nov 2023 18:23:58 +0100 Subject: [PATCH 24/27] fix: type warning --- test/test-cmd-add.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/test-cmd-add.ts b/test/test-cmd-add.ts index ab5910da..b58c690b 100644 --- a/test/test-cmd-add.ts +++ b/test/test-cmd-add.ts @@ -101,10 +101,14 @@ describe("cmd-add.ts", function () { (pkg) => pkg.addVersion("1.0.0", (version) => version.set("unity", "2020.2")) ); + const remotePkgInfoWithWrongEditorVersion = buildPackageInfo( packageWrongEditor, - (pkg) => - pkg.addVersion("1.0.0", (version) => version.set("unity", "2020")) + ( + pkg + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore 2020 is not a valid major.minor version, but this is on purpose for this test + ) => pkg.addVersion("1.0.0", (version) => version.set("unity", "2020")) ); const remotePkgInfoUp = buildPackageInfo(packageUp, (pkg) => pkg.addVersion("1.0.0") From a0ab467573135e88d513fde36e6693eaf4fffc21 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Sun, 26 Nov 2023 18:24:05 +0100 Subject: [PATCH 25/27] fix: outdated type --- test/test-upm-config.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test-upm-config.ts b/test/test-upm-config.ts index 9d9e0a45..48d8b25b 100644 --- a/test/test-upm-config.ts +++ b/test/test-upm-config.ts @@ -1,6 +1,5 @@ import { describe } from "mocha"; import { - Base64AuthData, decodeBasicAuth, encodeBasicAuth, isBasicAuth, @@ -9,6 +8,7 @@ import { UpmAuth, } from "../src/types/upm-config"; import should from "should"; +import { Base64 } from "../src/types/base64"; describe("upm-config", function () { describe("auth", function () { @@ -18,7 +18,7 @@ describe("upm-config", function () { email: "real@email.com", alwaysAuth: true, // Not a real base64 string, but we don't care in this test - _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + _auth: "h8gz8s9zgseihgisejf" as Base64, }; should(isBasicAuth(auth)).be.true(); }); @@ -48,7 +48,7 @@ describe("upm-config", function () { email: "real@email.com", alwaysAuth: true, // Not a real base64 string, but we don't care in this test - _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + _auth: "h8gz8s9zgseihgisejf" as Base64, }; should(shouldAlwaysAuth(auth)).be.true(); }); @@ -57,7 +57,7 @@ describe("upm-config", function () { email: "real@email.com", alwaysAuth: false, // Not a real base64 string, but we don't care in this test - _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + _auth: "h8gz8s9zgseihgisejf" as Base64, }; should(shouldAlwaysAuth(auth)).be.false(); }); @@ -65,7 +65,7 @@ describe("upm-config", function () { const auth: UpmAuth = { email: "real@email.com", // Not a real base64 string, but we don't care in this test - _auth: "h8gz8s9zgseihgisejf" as Base64AuthData, + _auth: "h8gz8s9zgseihgisejf" as Base64, }; should(shouldAlwaysAuth(auth)).be.false(); }); From 885207138878fa81b345ee66c254b1c258e44786 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Mon, 27 Nov 2023 15:14:31 +0100 Subject: [PATCH 26/27] refactor: cmd-option utility type --- src/cmd-add.ts | 7 +++---- src/cmd-deps.ts | 7 +++---- src/cmd-login.ts | 7 +++---- src/cmd-remove.ts | 6 ++---- src/cmd-search.ts | 6 ++---- src/cmd-view.ts | 6 ++---- src/types/global.ts | 11 ----------- src/types/options.ts | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/utils/env.ts | 6 ++++-- test/test-env.ts | 23 ++++++++++++++++++---- 10 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 src/types/options.ts diff --git a/src/cmd-add.ts b/src/cmd-add.ts index bd2a438d..24cf4119 100644 --- a/src/cmd-add.ts +++ b/src/cmd-add.ts @@ -1,7 +1,6 @@ import log from "./logger"; import url from "url"; import { isPackageUrl } from "./types/package-url"; -import { GlobalOptions } from "./types/global"; import { tryGetLatestVersion } from "./types/pkg-info"; import { loadManifest, saveManifest } from "./utils/pkg-manifest-io"; import { env, parseEnv } from "./utils/env"; @@ -24,12 +23,12 @@ import { addTestable, tryGetScopedRegistryByUrl, } from "./types/pkg-manifest"; +import { CmdOptions } from "./types/options"; -export type AddOptions = { +export type AddOptions = CmdOptions<{ test?: boolean; force?: boolean; - _global: GlobalOptions; -}; +}>; type ResultCode = 0 | 1; diff --git a/src/cmd-deps.ts b/src/cmd-deps.ts index 0ab8fd37..660031ae 100644 --- a/src/cmd-deps.ts +++ b/src/cmd-deps.ts @@ -1,5 +1,4 @@ import log from "./logger"; -import { GlobalOptions } from "./types/global"; import { parseEnv } from "./utils/env"; import { fetchPackageDependencies } from "./registry-client"; import { DomainName } from "./types/domain-name"; @@ -10,11 +9,11 @@ import { splitPackageReference, VersionReference, } from "./types/package-reference"; +import { CmdOptions } from "./types/options"; -export type DepsOptions = { +export type DepsOptions = CmdOptions<{ deep?: boolean; - _global: GlobalOptions; -}; +}>; export const deps = async function ( pkg: PackageReference, diff --git a/src/cmd-login.ts b/src/cmd-login.ts index 68bdbd2c..f0ff06fa 100644 --- a/src/cmd-login.ts +++ b/src/cmd-login.ts @@ -3,7 +3,6 @@ import path from "path"; import _ from "lodash"; import { assertIsNpmClientError, getNpmClient } from "./registry-client"; import log from "./logger"; -import { GlobalOptions } from "./types/global"; import { getUpmConfigDir, loadUpmConfig, @@ -19,15 +18,15 @@ import { promptRegistryUrl, promptUsername, } from "./utils/prompts"; +import { CmdOptions } from "./types/options"; -export type LoginOptions = { +export type LoginOptions = CmdOptions<{ username?: string; password?: string; email?: string; basicAuth?: boolean; alwaysAuth?: boolean; - _global: GlobalOptions; -}; +}>; export const login = async function (options: LoginOptions) { // parse env diff --git a/src/cmd-remove.ts b/src/cmd-remove.ts index dfe7793c..ac24679e 100644 --- a/src/cmd-remove.ts +++ b/src/cmd-remove.ts @@ -1,5 +1,4 @@ import log from "./logger"; -import { GlobalOptions } from "./types/global"; import { loadManifest, saveManifest } from "./utils/pkg-manifest-io"; import { env, parseEnv } from "./utils/env"; import { isDomainName } from "./types/domain-name"; @@ -13,10 +12,9 @@ import { removeDependency, tryGetScopedRegistryByUrl, } from "./types/pkg-manifest"; +import { CmdOptions } from "./types/options"; -export type RemoveOptions = { - _global: GlobalOptions; -}; +export type RemoveOptions = CmdOptions; export const remove = async function ( pkgs: PackageReference[] | PackageReference, diff --git a/src/cmd-search.ts b/src/cmd-search.ts index 0ae06d0c..9890cab3 100644 --- a/src/cmd-search.ts +++ b/src/cmd-search.ts @@ -5,20 +5,18 @@ import log from "./logger"; import { is404Error, isHttpError } from "./utils/error-type-guards"; import * as os from "os"; import assert from "assert"; -import { GlobalOptions } from "./types/global"; import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; import { env, parseEnv } from "./utils/env"; import { DomainName } from "./types/domain-name"; import { SemanticVersion } from "./types/semantic-version"; import { RegistryUrl } from "./types/registry-url"; +import { CmdOptions } from "./types/options"; type DateString = string; type TableRow = [DomainName, SemanticVersion, DateString, ""]; -export type SearchOptions = { - _global: GlobalOptions; -}; +export type SearchOptions = CmdOptions; export type SearchedPkgInfo = Omit & { versions: Record; diff --git a/src/cmd-view.ts b/src/cmd-view.ts index ceb5bade..9c7f7dd8 100644 --- a/src/cmd-view.ts +++ b/src/cmd-view.ts @@ -1,7 +1,6 @@ import chalk from "chalk"; import log from "./logger"; import assert from "assert"; -import { GlobalOptions } from "./types/global"; import { PkgInfo, tryGetLatestVersion } from "./types/pkg-info"; import { env, parseEnv } from "./utils/env"; import { fetchPackageInfo } from "./registry-client"; @@ -11,10 +10,9 @@ import { PackageReference, splitPackageReference, } from "./types/package-reference"; +import { CmdOptions } from "./types/options"; -export type ViewOptions = { - _global: GlobalOptions; -}; +export type ViewOptions = CmdOptions; export const view = async function ( pkg: PackageReference, diff --git a/src/types/global.ts b/src/types/global.ts index df3bccbf..4dfc7a09 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -3,14 +3,3 @@ export type Contact = { email?: string; url?: string; }; - -export type GlobalOptions = { - registry?: string; - verbose?: boolean; - color?: boolean; - upstream?: boolean; - cn?: boolean; - systemUser?: boolean; - wsl?: boolean; - chdir?: string; -}; diff --git a/src/types/options.ts b/src/types/options.ts new file mode 100644 index 00000000..52e3d066 --- /dev/null +++ b/src/types/options.ts @@ -0,0 +1,47 @@ +/** + * Options which are shared between commands + */ +type GlobalOptions = { + /** + * Override package registry to use + */ + registry?: string; + /** + * Whether to print logs + */ + verbose?: boolean; + /** + * Whether to use color in the console + */ + color?: boolean; + /** + * Whether to fall back to the Unity registry + */ + upstream?: boolean; + /** + * Whether to run commands for the chinese locale + */ + cn?: boolean; + /** + * Whether to authenticate as a Windows system-user + */ + systemUser?: boolean; + /** + * Whether WSL should be treated as Windows + */ + wsl?: boolean; + /** + * Override working directory + */ + chdir?: string; +}; + +/** + * Command-options. Extends the given record with a _global property + * containing {@link GlobalOptions}. + */ +export type CmdOptions< + TOptions extends Record = Record +> = TOptions & { + _global: GlobalOptions; +}; diff --git a/src/utils/env.ts b/src/utils/env.ts index 87d60a2a..066ef666 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,4 +1,3 @@ -import { GlobalOptions } from "../types/global"; import log from "../logger"; import chalk from "chalk"; import { loadUpmConfig } from "./upm-config-io"; @@ -26,6 +25,9 @@ import { } from "../types/upm-config"; import { encodeBase64 } from "../types/base64"; import { NpmAuth } from "another-npm-registry-client"; +import { + CmdOptions, +} from "../types/options"; type Region = "us" | "cn"; @@ -49,7 +51,7 @@ export const env: Env = {}; // Parse env export const parseEnv = async function ( - options: { _global: GlobalOptions } & Record, + options: CmdOptions, { checkPath }: { checkPath: unknown } ) { // set defaults diff --git a/test/test-env.ts b/test/test-env.ts index 56622839..803d392e 100644 --- a/test/test-env.ts +++ b/test/test-env.ts @@ -97,7 +97,11 @@ describe("env", function () { it("custom registry with extra path", async function () { ( await parseEnv( - { _global: { registry: "https://registry.npmjs.org/some" } }, + { + _global: { + registry: "https://registry.npmjs.org/some", + }, + }, { checkPath: false } ) ).should.be.ok(); @@ -107,7 +111,11 @@ describe("env", function () { it("custom registry with extra path and splash", async function () { ( await parseEnv( - { _global: { registry: "https://registry.npmjs.org/some/" } }, + { + _global: { + registry: "https://registry.npmjs.org/some/", + }, + }, { checkPath: false } ) ).should.be.ok(); @@ -137,7 +145,9 @@ describe("env", function () { it("custom registry with ipv6+port", async function () { ( await parseEnv( - { _global: { registry: "http://[1:2:3:4:5:6:7:8]:4873" } }, + { + _global: { registry: "http://[1:2:3:4:5:6:7:8]:4873" }, + }, { checkPath: false } ) ).should.be.ok(); @@ -170,7 +180,12 @@ describe("env", function () { it("region cn with a custom registry", async function () { ( await parseEnv( - { _global: { cn: true, registry: "https://reg.custom-package.com" } }, + { + _global: { + cn: true, + registry: "https://reg.custom-package.com", + }, + }, { checkPath: false } ) ).should.be.ok(); From 5c6e64d28ee7ffad6029ebb4cc329c70ba9331d2 Mon Sep 17 00:00:00 2001 From: Ramon Brullo Date: Mon, 27 Nov 2023 15:15:03 +0100 Subject: [PATCH 27/27] refactor: rename file --- src/types/{global.ts => contact.ts} | 0 src/types/pkg-version-info.ts | 2 +- src/utils/env.ts | 4 +--- test/types.ts | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) rename src/types/{global.ts => contact.ts} (100%) diff --git a/src/types/global.ts b/src/types/contact.ts similarity index 100% rename from src/types/global.ts rename to src/types/contact.ts diff --git a/src/types/pkg-version-info.ts b/src/types/pkg-version-info.ts index 410d9b94..2a806739 100644 --- a/src/types/pkg-version-info.ts +++ b/src/types/pkg-version-info.ts @@ -1,7 +1,7 @@ import { PackageId } from "./package-id"; import { SemanticVersion } from "./semantic-version"; import { DomainName } from "./domain-name"; -import { Contact } from "./global"; +import { Contact } from "./contact"; /** * Distribution information diff --git a/src/utils/env.ts b/src/utils/env.ts index 066ef666..46128ae1 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -25,9 +25,7 @@ import { } from "../types/upm-config"; import { encodeBase64 } from "../types/base64"; import { NpmAuth } from "another-npm-registry-client"; -import { - CmdOptions, -} from "../types/options"; +import { CmdOptions } from "../types/options"; type Region = "us" | "cn"; diff --git a/test/types.ts b/test/types.ts index e2863c7c..7f61ce04 100644 --- a/test/types.ts +++ b/test/types.ts @@ -1,4 +1,4 @@ -import { Contact } from "../src/types/global"; +import { Contact } from "../src/types/contact"; import { DomainName } from "../src/types/domain-name"; import { SemanticVersion } from "../src/types/semantic-version";