diff --git a/modules/desktop/electron/libs/initialize.ts b/modules/desktop/electron/libs/initialize.ts index efced0d..c3d5b9b 100644 --- a/modules/desktop/electron/libs/initialize.ts +++ b/modules/desktop/electron/libs/initialize.ts @@ -4,7 +4,7 @@ import { authFileState } from "./auth"; import * as https from "https"; import { spawn } from "child_process"; import path from "path"; -import { parse as semverParse } from "@tea/libtea"; +import { semver } from "@teaxyz/lib"; type InitState = "NOT_INITIALIZED" | "PENDING" | "INITIALIZED"; @@ -72,7 +72,7 @@ export const cliInitializationState = new InitWatcher(async () => { return installTeaCli(); } else { const dir = fs.readlinkSync(teaCliPrefix); - const v = semverParse(dir)?.toString(); + const v = semver.parse(dir)?.toString(); if (!v) throw new Error(`couldn't parse to semver: ${dir}`); return v; } diff --git a/modules/desktop/electron/libs/tea-dir.ts b/modules/desktop/electron/libs/tea-dir.ts index ff07eea..809031c 100644 --- a/modules/desktop/electron/libs/tea-dir.ts +++ b/modules/desktop/electron/libs/tea-dir.ts @@ -5,7 +5,7 @@ import log from "./logger"; import type { InstalledPackage } from "../../src/libs/types"; import { mkdirp } from "mkdirp"; import fetch from "node-fetch"; -import { SemVer, isValidSemVer } from "@tea/libtea"; +import { SemVer, semver } from "@teaxyz/lib"; import { execSync } from "child_process"; import chokidar from "chokidar"; import { MainWindowNotifier } from "./types"; @@ -53,8 +53,8 @@ async function findInstalledVersions(pkgsPath: string): Promise !isValidSemVer(name) && name !== ".tea", - filter: (name: string) => !!isValidSemVer(name) && name !== ".tea" + continueDeeper: (name: string) => !semver.isValid(name) && name !== ".tea", + filter: (name: string) => semver.isValid(name) && name !== ".tea" }); const bottles = folders @@ -218,7 +218,7 @@ export async function startMonitoringTeaDir(mainWindowNotifier: MainWindowNotifi .on("addDir", (pth) => { const dir = path.dirname(pth); const version = path.basename(pth); - if (isValidSemVer(version) && !fs.lstatSync(pth).isSymbolicLink()) { + if (semver.isValid(version) && !fs.lstatSync(pth).isSymbolicLink()) { const full_name = dir.split(".tea/")[1]; log.info(`Monitor - Added Package: ${full_name} v${version}`); mainWindowNotifier("pkg-modified", { full_name, version, type: "add" }); @@ -228,7 +228,7 @@ export async function startMonitoringTeaDir(mainWindowNotifier: MainWindowNotifi // FIXME: unlinkDir does not always fire, this is a bug in chokidar const dir = path.dirname(pth); const version = path.basename(pth); - if (isValidSemVer(version)) { + if (semver.isValid(version)) { const full_name = dir.split(".tea/")[1]; log.info(`Monitor - Removed Package: ${full_name} v${version}`); mainWindowNotifier("pkg-modified", { full_name, version, type: "remove" }); diff --git a/modules/desktop/package.json b/modules/desktop/package.json index 45e9c15..ab4e41a 100644 --- a/modules/desktop/package.json +++ b/modules/desktop/package.json @@ -39,7 +39,6 @@ "@sveltejs/adapter-node": "^1.0.0-next.101", "@sveltejs/adapter-static": "^1.0.0-next.48", "@sveltejs/kit": "^1.15.9", - "@tea/libtea": "workspace:*", "@tea/ui": "workspace:*", "@testing-library/jest-dom": "^5.16.5", "@testing-library/svelte": "^3.2.2", @@ -89,7 +88,7 @@ "@sentry/electron": "^4.4.0", "@sentry/svelte": "^7.47.0", "@sentry/vite-plugin": "^0.7.2", - "@teaxyz/lib": "^0.1.9", + "@teaxyz/lib": "^0.2.2", "@types/electron": "^1.6.10", "@types/mousetrap": "^1.6.11", "@vitest/coverage-c8": "^0.27.1", @@ -126,8 +125,7 @@ }, "pnpm": { "onlyBuiltDependencies": [ - "@tea/ui", - "@tea/libtea" + "@tea/ui" ] }, "homepage": "https://tea.xyz", diff --git a/modules/desktop/src/libs/packages/pkg-utils.ts b/modules/desktop/src/libs/packages/pkg-utils.ts index ba8e6e0..8fb4791 100644 --- a/modules/desktop/src/libs/packages/pkg-utils.ts +++ b/modules/desktop/src/libs/packages/pkg-utils.ts @@ -1,6 +1,6 @@ import log from "$libs/logger"; import type { GUIPackage } from "$libs/types"; -import { SemVer } from "@tea/libtea"; +import SemVer from "@teaxyz/lib/semver"; // Find a list of available versions for a package based on the bottles export const findAvailableVersions = (pkg: Pick) => { diff --git a/modules/desktop/tsconfig.json b/modules/desktop/tsconfig.json index ce95db7..2d0a7d6 100644 --- a/modules/desktop/tsconfig.json +++ b/modules/desktop/tsconfig.json @@ -18,7 +18,8 @@ "@native": ["./src/libs/native-electron.ts"], "$components/*": ["./src/components/*"], "@tea/ui/*": ["../ui/src/*"], - "@tea/libtea/*": ["../libtea/src/*"] + // FIXME: Ideally we don't have to do this, but something is wrong with module resolution + "@teaxyz/lib/semver": ["./../../node_modules/@teaxyz/lib/esm/src/utils/semver.d.ts"] }, "typeRoots": ["./node_modules/@types", "./types"] }, diff --git a/modules/desktop/vite.config.ts b/modules/desktop/vite.config.ts index 5c2b010..8d52230 100644 --- a/modules/desktop/vite.config.ts +++ b/modules/desktop/vite.config.ts @@ -26,7 +26,6 @@ const config: UserConfig = { resolve: { alias: { "@tea/ui/*": path.resolve("../ui/src/*"), - "@tea/libtea/*": path.resolve("../libtea/src/*"), // this dynamic-ish static importing is followed by the svelte build // but for vscode editing intellisense tsconfig.json is being used "@native": isMock diff --git a/modules/libtea/.eslintignore b/modules/libtea/.eslintignore deleted file mode 100644 index ac538c3..0000000 --- a/modules/libtea/.eslintignore +++ /dev/null @@ -1,17 +0,0 @@ -.DS_Store -node_modules -/build -/.svelte-kit -/package -.env -.env.* -!.env.example - -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock -coverage/* -build/* -dist/* -electron/dist/* \ No newline at end of file diff --git a/modules/libtea/.eslintrc.cjs b/modules/libtea/.eslintrc.cjs deleted file mode 100644 index 8fe7c97..0000000 --- a/modules/libtea/.eslintrc.cjs +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - root: true, - globals: { - NodeJS: true - }, - parser: "@typescript-eslint/parser", - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], - plugins: ["@typescript-eslint"], - ignorePatterns: ["*.cjs"], - parserOptions: { - sourceType: "module", - ecmaVersion: 2020 - }, - env: { - browser: true, - es2017: true, - node: true - }, - rules: { - "@typescript-eslint/ban-ts-comment": ["error", { "ts-ignore": "allow-with-description" }] - } -}; diff --git a/modules/libtea/.gitignore b/modules/libtea/.gitignore deleted file mode 100644 index b0fb09f..0000000 --- a/modules/libtea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -dist/* diff --git a/modules/libtea/.prettierignore b/modules/libtea/.prettierignore deleted file mode 100644 index a261f29..0000000 --- a/modules/libtea/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -dist/* diff --git a/modules/libtea/.prettierrc b/modules/libtea/.prettierrc deleted file mode 100644 index 8645bdf..0000000 --- a/modules/libtea/.prettierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "singleQuote": false, - "trailingComma": "none", - "printWidth": 100, - "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], - "pluginSearchDirs": ["../../node_modules"], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] -} diff --git a/modules/libtea/package.json b/modules/libtea/package.json deleted file mode 100644 index 30e7236..0000000 --- a/modules/libtea/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@tea/libtea", - "version": "0.0.1", - "description": "library of tea utilities", - "author": "tea.xyz", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "devDependencies": { - "typescript": "^4.7.4" - }, - "scripts": { - "build": "tsc --build", - "postinstall": "tsc --build", - "lint": "prettier --check . && eslint .", - "format": "prettier --write ." - } -} diff --git a/modules/libtea/src/index.ts b/modules/libtea/src/index.ts deleted file mode 100644 index 20d06fc..0000000 --- a/modules/libtea/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SemVer, isValidSemVer, parse } from "./semver"; diff --git a/modules/libtea/src/semver.ts b/modules/libtea/src/semver.ts deleted file mode 100644 index 807ed90..0000000 --- a/modules/libtea/src/semver.ts +++ /dev/null @@ -1,376 +0,0 @@ -// -// This is a copy from tea/cli 0.31.2 -// https://github.com/teaxyz/cli/blob/31c2fc0bbddc41cbd63d9ee14593efe3f9b09301/src/utils/semver.ts -// - -/** - * we have our own implementation because open source is full of weird - * but *almost* valid semver schemes, eg: - * openssl 1.1.1q - * ghc 5.64.3.2 - * it also allows us to implement semver_intersection without hating our lives - */ -export default class SemVer { - readonly components: number[]; - - major: number; - minor: number; - patch: number; - - //FIXME parse these - readonly prerelease: string[] = []; - readonly build: string[] = []; - - readonly raw: string; - readonly pretty?: string; - - constructor( - input: string | number[] | Range | SemVer, - { tolerant }: { tolerant: boolean } = { tolerant: false } - ) { - if (typeof input == "string") { - const vprefix = input.startsWith("v"); - const raw = vprefix ? input.slice(1) : input; - const parts = raw.split("."); - if (parts.length < 3 && !vprefix && !tolerant) - throw new Error(`too short to parse without a \`v\` prefix: ${input}`); - let pretty_is_raw = false; - this.components = parts.flatMap((x, index) => { - const match = x.match(/^(\d+)([a-z])$/); - if (match) { - if (index != parts.length - 1) throw new Error(`invalid version: ${input}`); - const n = parseInt(match[1]); - if (isNaN(n)) throw new Error(`invalid version: ${input}`); - pretty_is_raw = true; - return [n, char_to_num(match[2])]; - } else if (/^\d+$/.test(x)) { - const n = parseInt(x); // parseInt will parse eg. `5-start` to `5` - if (isNaN(n)) throw new Error(`invalid version: ${input}`); - return [n]; - } else { - throw new Error(`invalid version: ${input}`); - } - }); - this.raw = raw; - if (pretty_is_raw) this.pretty = raw; - } else if (input instanceof Range || input instanceof SemVer) { - const v = input instanceof Range ? input.single() : input; - if (!v) throw new Error(`range represents more than a single version: ${input}`); - this.components = v.components; - this.raw = v.raw; - this.pretty = v.pretty; - } else { - this.components = input; - this.raw = input.join("."); - } - - this.major = this.components[0]; - this.minor = this.components[1] ?? 0; - this.patch = this.components[2] ?? 0; - - function char_to_num(c: string) { - return c.charCodeAt(0) - "a".charCodeAt(0) + 1; - } - } - - toString(): string { - return ( - this.pretty ?? - (this.components.length <= 3 - ? `${this.major}.${this.minor}.${this.patch}` - : this.components.join(".")) - ); - } - - eq(that: SemVer): boolean { - return this.compare(that) == 0; - } - - neq(that: SemVer): boolean { - return this.compare(that) != 0; - } - - gt(that: SemVer): boolean { - return this.compare(that) > 0; - } - - lt(that: SemVer): boolean { - return this.compare(that) < 0; - } - - compare(that: SemVer): number { - return _compare(this, that); - } - - [Symbol.for("Deno.customInspect")]() { - return this.toString(); - } -} - -/// the same as the constructor but swallows the error returning undefined instead -/// also slightly more tolerant parsing -export function parse(input: string, tolerant = true) { - try { - return new SemVer(input, { tolerant }); - } catch { - return undefined; - } -} - -export function isValidSemVer(input: string, tolerant = false) { - return parse(input, tolerant) != undefined; -} - -/// we don’t support as much as node-semver but we refuse to do so because it is badness -export class Range { - // contract [0, 1] where 0 != 1 and 0 < 1 - readonly set: ([SemVer, SemVer] | SemVer)[] | "*"; - - constructor(input: string | ([SemVer, SemVer] | SemVer)[]) { - if (input === "*") { - this.set = "*"; - } else if (!isString(input)) { - this.set = input; - } else { - input = input.trim(); - - const err = () => new Error(`invalid semver range: ${input}`); - - this.set = input.split(/(?:,|\s*\|\|\s*)/).map((input) => { - let match = input.match(/^>=((\d+\.)*\d+)\s*(<((\d+\.)*\d+))?$/); - if (match) { - const v1 = new SemVer(match[1], { tolerant: true }); - const v2 = match[3] - ? new SemVer(match[4], { tolerant: true }) - : new SemVer([Infinity, Infinity, Infinity]); - return [v1, v2]; - } else if ((match = input.match(/^([~=<^])(.+)$/))) { - let v1: SemVer | undefined, v2: SemVer | undefined; - switch (match[1]) { - case "^": - v1 = new SemVer(match[2], { tolerant: true }); - // eslint-disable-next-line no-case-declarations - const parts: number[] = []; - for (let i = 0; i < v1.components.length; i++) { - if (v1.components[i] === 0 && i < v1.components.length - 1) { - parts.push(0); - } else { - parts.push(v1.components[i] + 1); - break; - } - } - v2 = new SemVer(parts, { tolerant: true }); - return [v1, v2]; - case "~": - { - v1 = new SemVer(match[2], { tolerant: true }); - if (v1.components.length == 1) { - // yep this is the official policy - v2 = new SemVer([v1.major + 1], { tolerant: true }); - } else { - v2 = new SemVer([v1.major, v1.minor + 1], { tolerant: true }); - } - } - return [v1, v2]; - case "<": - v1 = new SemVer([0], { tolerant: true }); - v2 = new SemVer(match[2], { tolerant: true }); - return [v1, v2]; - case "=": - return new SemVer(match[2], { tolerant: true }); - } - } - throw err(); - }); - - if (this.set.length == 0) { - throw err(); - } - - for (const i of this.set) { - if (isArray(i) && !i[0].lt(i[1])) throw err(); - } - } - } - - toString(): string { - if (this.set === "*") { - return "*"; - } else { - return this.set - .map((v) => { - if (!isArray(v)) return `=${v.toString()}`; - const [v1, v2] = v; - if (v1.major > 0 && v2.major == v1.major + 1 && v2.minor == 0 && v2.patch == 0) { - const v = chomp(v1); - return `^${v}`; - } else if (v2.major == v1.major && v2.minor == v1.minor + 1 && v2.patch == 0) { - const v = chomp(v1); - return `~${v}`; - } else if (v2.major == Infinity) { - const v = chomp(v1); - return `>=${v}`; - } else { - return `>=${chomp(v1)}<${chomp(v2)}`; - } - }) - .join(","); - } - } - - // eq(that: Range): boolean { - // if (this.set.length !== that.set.length) return false - // for (let i = 0; i < this.set.length; i++) { - // const [a,b] = [this.set[i], that.set[i]] - // if (typeof a !== 'string' && typeof b !== 'string') { - // if (a[0].neq(b[0])) return false - // if (a[1].neq(b[1])) return false - // } else if (a != b) { - // return false - // } - // } - // return true - // } - - /// tolerant to stuff in the wild that hasn’t semver specifiers - static parse(input: string): Range | undefined { - try { - return new Range(input); - } catch { - if (!/^(\d+\.)*\d+$/.test(input)) return; - - // AFAICT this is what people expect - // verified via https://jubianchi.github.io/semver-check/ - - const parts = input.split("."); - if (parts.length < 3) { - return new Range(`^${input}`); - } else { - return new Range(`~${input}`); - } - } - } - - satisfies(version: SemVer): boolean { - if (this.set === "*") { - return true; - } else { - return this.set.some((v) => { - if (isArray(v)) { - const [v1, v2] = v; - return version.compare(v1) >= 0 && version.compare(v2) < 0; - } else { - return version.eq(v); - } - }); - } - } - - max(versions: SemVer[]): SemVer | undefined { - return versions - .filter((x) => this.satisfies(x)) - .sort((a, b) => a.compare(b)) - .pop(); - } - - single(): SemVer | undefined { - if (this.set === "*") return; - if (this.set.length > 1) return; - return isArray(this.set[0]) ? undefined : this.set[0]; - } - - [Symbol.for("Deno.customInspect")]() { - return this.toString(); - } -} - -function zip(a: T[], b: U[]) { - const N = Math.max(a.length, b.length); - const rv: [T | undefined, U | undefined][] = []; - for (let i = 0; i < N; ++i) { - rv.push([a[i], b[i]]); - } - return rv; -} - -function _compare(a: SemVer, b: SemVer): number { - for (const [c, d] of zip(a.components, b.components)) { - if (c != d) return (c ?? 0) - (d ?? 0); - } - return 0; -} -export { _compare as compare }; - -export function intersect(a: Range, b: Range): Range { - if (b.set === "*") return a; - if (a.set === "*") return b; - - // calculate the intersection between two semver.Ranges - const set: ([SemVer, SemVer] | SemVer)[] = []; - - for (const aa of a.set) { - for (const bb of b.set) { - if (!isArray(aa) && !isArray(bb)) { - if (aa.eq(bb)) set.push(aa); - } else if (!isArray(aa)) { - const bbb = bb as [SemVer, SemVer]; - if (aa.compare(bbb[0]) >= 0 && aa.lt(bbb[1])) set.push(aa); - } else if (!isArray(bb)) { - const aaa = aa as [SemVer, SemVer]; - if (bb.compare(aaa[0]) >= 0 && bb.lt(aaa[1])) set.push(bb); - } else { - const a1 = aa[0]; - const a2 = aa[1]; - const b1 = bb[0]; - const b2 = bb[1]; - - if (a1.compare(b2) >= 0 || b1.compare(a2) >= 0) { - continue; - } - - set.push([a1.compare(b1) > 0 ? a1 : b1, a2.compare(b2) < 0 ? a2 : b2]); - } - } - } - - if (set.length <= 0) throw new Error(`cannot intersect: ${a} && ${b}`); - - return new Range(set); -} - -//FIXME yes yes this is not sufficient -export const regex = /\d+\.\d+\.\d+/; - -function chomp(v: SemVer) { - return v.toString().replace(/(\.0)+$/g, "") || "0"; -} - -/** - * Returns whether the payload is an array - * - * @param {any} payload - * @returns {payload is any[]} - */ -export function isArray(payload: unknown): payload is unknown[] { - return getType(payload) === "Array"; -} - -/** - * Returns whether the payload is a string - * - * @param {*} payload - * @returns {payload is string} - */ -export function isString(payload: unknown): payload is string { - return getType(payload) === "String"; -} - -/** - * Returns the object type of the given payload - * - * @param {*} payload - * @returns {string} - */ -export function getType(payload: unknown): string { - return Object.prototype.toString.call(payload).slice(8, -1); -} diff --git a/modules/libtea/tsconfig.json b/modules/libtea/tsconfig.json deleted file mode 100644 index 4b1f628..0000000 --- a/modules/libtea/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "declaration": true, - "module": "ES6", - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "importHelpers": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "strict": true, - "lib": ["es2019"], - "outDir": "./dist" - }, - "include": ["./src/**/*.ts"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 363957c..f492738 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,9 +29,8 @@ importers: '@sveltejs/adapter-node': ^1.0.0-next.101 '@sveltejs/adapter-static': ^1.0.0-next.48 '@sveltejs/kit': ^1.15.9 - '@tea/libtea': workspace:* '@tea/ui': workspace:* - '@teaxyz/lib': ^0.1.9 + '@teaxyz/lib': ^0.2.2 '@testing-library/jest-dom': ^5.16.5 '@testing-library/svelte': ^3.2.2 '@testing-library/webdriverio': ^3.2.1 @@ -111,7 +110,7 @@ importers: '@sentry/electron': 4.5.0 '@sentry/svelte': 7.51.2_svelte@3.59.1 '@sentry/vite-plugin': 0.7.2 - '@teaxyz/lib': 0.1.9 + '@teaxyz/lib': 0.2.2 '@types/electron': 1.6.10 '@types/mousetrap': 1.6.11 '@vitest/coverage-c8': 0.27.3_jsdom@21.1.2 @@ -153,7 +152,6 @@ importers: '@sveltejs/adapter-node': 1.2.4_@sveltejs+kit@1.16.2 '@sveltejs/adapter-static': 1.0.6_@sveltejs+kit@1.16.2 '@sveltejs/kit': 1.16.2_svelte@3.59.1+vite@4.3.5 - '@tea/libtea': link:../libtea '@tea/ui': link:../ui '@testing-library/jest-dom': 5.16.5 '@testing-library/svelte': 3.2.2_svelte@3.59.1 @@ -195,12 +193,6 @@ importers: vitest: 0.28.5_jsdom@21.1.2 wdio-electron-service: 4.0.2_qkoyiluaudwk5orvhjdvg63jhu - modules/libtea: - specifiers: - typescript: ^4.7.4 - devDependencies: - typescript: 4.9.5 - modules/ui: specifiers: '@magidoc/plugin-svelte-prismjs': ^3.0.6 @@ -3645,8 +3637,8 @@ packages: tailwindcss: 3.3.2 dev: false - /@teaxyz/lib/0.1.9: - resolution: {integrity: sha512-LukZXiLo22bq5P81O4rvUPLpqvTt+aNwn73tUN3Fd2QLtPfsh70qBy/uHM1B5y0+IDfWjn/mvCXra6ZARA+VRA==} + /@teaxyz/lib/0.2.2: + resolution: {integrity: sha512-xChLHuuwbUXZcHMmqMsGIB6RbXqEb1hXgRYJk4Zg3KfozhRllXuiZ6VkUZYPib66ygMjPlndclG7tj2cDlsLkg==} dependencies: '@deno/shim-crypto': 0.3.1 '@deno/shim-deno': 0.16.1