diff --git a/package.json b/package.json index 170bd38..98d6c1d 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ }, "devDependencies": { "@changesets/changelog-github": "0.5.0", - "@dovenv/core": "1.2.0", - "@dovenv/theme-pigeonposse": "1.2.0", + "@dovenv/core": "1.1.5", + "@dovenv/theme-pigeonposse": "1.1.5", "@playwright/test": "1.49.1", "@types/node": "22.10.5", "binarium": "2.0.5", diff --git a/packages/cli/src/help.ts b/packages/cli/src/help.ts index d9f053f..95f2b5b 100644 --- a/packages/cli/src/help.ts +++ b/packages/cli/src/help.ts @@ -26,7 +26,7 @@ ${bold( 'Usage:' )} ${cyan( name )} ${green( '' )} ${yellow( '[...flags ${bold( 'Options:' )} - ${yellow( '-i, --input' )} ${dim( 'Library input. Accepted:' )} + ${yellow( '-i, --input' )} ${dim( 'Library input. Accepted:' )} ${dim( ' - libraryID (name@version)' )} ${dim( ' - path (dir to project / file to package.json)' )} ${dim( ' - URL (to https://www.npmjs.com/package/${name} or link to package.json)' )} diff --git a/packages/cli/src/main.ts b/packages/cli/src/main.ts index 2972084..1b3fc9a 100644 --- a/packages/cli/src/main.ts +++ b/packages/cli/src/main.ts @@ -35,8 +35,8 @@ const run = async () => { const size = new Sizium( FLAGS.INPUT ) const data = await size.get() - if ( FLAGS.RES === RES_TYPE.SIZE ) console.log( `${data.size} bytes | ${data.size / 1000000} megabytes` ) - else if ( FLAGS.RES === RES_TYPE.INFO ) console.log( `Name: ${data.id}\nPackages: ${data.packageNum}\nSize: ${data.size} bytes | ${data.size / 1000000} megabytes` ) + if ( FLAGS.RES === RES_TYPE.SIZE ) console.log( `${data.sizeKB}kb | ${data.sizeMB}mb` ) + else if ( FLAGS.RES === RES_TYPE.INFO ) console.log( `Name: ${data.id}\nPackages: ${data.packageNum}\nSize: ${data.sizeKB}kb | ${data.sizeMB}mb` ) else if ( FLAGS.RES === RES_TYPE.JSON ) console.log( JSON.stringify( data ) ) else console.dir( data, { depth: Infinity } ) diff --git a/packages/core/src/_shared/url.ts b/packages/core/src/_shared/url.ts new file mode 100644 index 0000000..f646276 --- /dev/null +++ b/packages/core/src/_shared/url.ts @@ -0,0 +1,22 @@ +export const normalizeRepositoryUrl = ( url?: string ): string | undefined => { + + if ( !url ) return undefined + + try { + + const parsedUrl = new URL( url ) + parsedUrl.protocol = 'https:' // force https + + if ( parsedUrl.pathname.endsWith( '.git' ) ) + parsedUrl.pathname = parsedUrl.pathname.slice( 0, -4 ) + + return parsedUrl.toString() + + } + catch ( _error ) { + + return undefined + + } + +} diff --git a/packages/core/src/search/const.ts b/packages/core/src/search/const.ts index ac21039..8fedb1c 100644 --- a/packages/core/src/search/const.ts +++ b/packages/core/src/search/const.ts @@ -5,3 +5,12 @@ export const ERROR_ID = { GETTING_LOCAL_DATA : 'GETTING_LOCAL_DATA', } as const +export const LIFE_CYCLE_SCRIPTS = [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', + 'preprepare', + 'prepare', + 'postprepare', +] as const diff --git a/packages/core/src/search/local.ts b/packages/core/src/search/local.ts index 438b60a..99109b2 100644 --- a/packages/core/src/search/local.ts +++ b/packages/core/src/search/local.ts @@ -37,19 +37,13 @@ import type { */ export class SiziumLocal extends PackageSuper { - constructor( public packagePath: string ) { - - super() - - } - async #getPackage(): Promise { try { - if ( isUrl( this.packagePath ) ) { + if ( isUrl( this.input ) ) { - const response = await fetch( this.packagePath ) + const response = await fetch( this.input ) if ( !response.ok ) throw new Error( `Failed to fetch package file from URL: ${response.statusText}` ) @@ -57,14 +51,14 @@ export class SiziumLocal extends PackageSuper { return JSON.parse( content ) } - else if ( isJsonString( this.packagePath ) ) { + else if ( isJsonString( this.input ) ) { - return JSON.parse( this.packagePath ) + return JSON.parse( this.input ) } else { - let filePath = path.resolve( this.packagePath ) + let filePath = path.resolve( this.input ) const stats = await stat( filePath ) if ( stats.isDirectory() ) filePath = path.join( filePath, 'package.json' ) @@ -93,19 +87,7 @@ export class SiziumLocal extends PackageSuper { const mainPackage = await this.getPkgData( packageData, 0 ) const allPackages = await this.getPackagesData( mainPackage ) - const totalSize = allPackages.reduce( ( sum, pkg ) => { - - const size = pkg.unpackedSize ?? 0 - return sum + size - - }, 0 ) - - return { - id : packageData.name, - packageNum : allPackages.length, - size : totalSize, - packages : allPackages, - } + return this.getMainPkgData( allPackages ) } diff --git a/packages/core/src/search/registry.ts b/packages/core/src/search/registry.ts index 85db3e2..40cda41 100644 --- a/packages/core/src/search/registry.ts +++ b/packages/core/src/search/registry.ts @@ -13,14 +13,6 @@ import type { SiziumResponse } from './types' */ export class SiziumRegistry extends PackageSuper { - constructor( - public name: string, - ) { - - super() - - } - #parseName( input: string ) { try { @@ -60,22 +52,11 @@ export class SiziumRegistry extends PackageSuper { async get(): Promise { - const data = this.#parseName( this.name ) + const data = this.#parseName( this.input ) const mainPackage = await this.getRegistryData( data.name, data.version, 0 ) const allPackages = await this.getPackagesData( mainPackage ) - const totalSize = allPackages.reduce( ( sum, pkg ) => { - const size = pkg.unpackedSize ?? 0 - return sum + size - - }, 0 ) - - return { - id : this.name, - packageNum : allPackages.length, - size : totalSize, - packages : allPackages, - } + return this.getMainPkgData( allPackages ) } diff --git a/packages/core/src/search/super.ts b/packages/core/src/search/super.ts index 6bd4ddd..5148be6 100644 --- a/packages/core/src/search/super.ts +++ b/packages/core/src/search/super.ts @@ -1,7 +1,12 @@ +/* eslint-disable @stylistic/object-curly-newline */ import semver from 'semver' -import { ERROR_ID } from './const' -import { TypedError } from '../_shared/error' +import { + ERROR_ID, + LIFE_CYCLE_SCRIPTS, +} from './const' +import { TypedError } from '../_shared/error' +import { normalizeRepositoryUrl } from '../_shared/url' import type { PackageJSON, @@ -20,32 +25,55 @@ export class PackageSuper { ERROR_ID = ERROR_ID Error = SiziumError + constructor( + public input: string, + public opts?: { + /** Skip error on package dependence and return undefined */ + skipError : boolean + }, + ) { + + } + private processedPackages : Set = new Set() + protected LIFE_CYCLE_SCRIPTS = LIFE_CYCLE_SCRIPTS - protected getPkgData( data: PackageJSON, level = 0, unpackedSize?: number, installedBy?: string | string[] ): PackageInfo { + protected getMainPkgData( allPackages: PackageInfo[] ) { - const normalizeRepositoryUrl = ( url?: string ): string | undefined => { + const totalSize = allPackages.reduce( ( sum, pkg ) => { - if ( !url ) return undefined + const size = pkg.unpackedSize ?? 0 + return sum + size - try { + }, 0 ) - const parsedUrl = new URL( url ) - parsedUrl.protocol = 'https:' // force https + return { + id : allPackages[0].name, + packageNum : allPackages.length, + size : totalSize, + sizeKB : totalSize / 1000, + sizeMB : totalSize / 1000000, + packages : allPackages, + } - if ( parsedUrl.pathname.endsWith( '.git' ) ) - parsedUrl.pathname = parsedUrl.pathname.slice( 0, -4 ) + } - return parsedUrl.toString() + protected getPkgData( data: PackageJSON, level = 0, unpackedSize?: number, installedBy?: string | string[] ): PackageInfo { - } - catch ( _error ) { + const lcScripts = {} as NonNullable + if ( data.scripts ) { - return undefined + const scripts = Object.keys( data.scripts ) + scripts.forEach( script => { - } + if ( this.LIFE_CYCLE_SCRIPTS.includes( script as keyof typeof lcScripts ) ) + // @ts-ignore + lcScripts[script] = data.scripts[script] + + } ) } + const size = unpackedSize ?? 0 return { name : data.name, version : data.version, @@ -74,12 +102,16 @@ export class PackageSuper { : typeof data.funding === 'string' ? data.funding : data.funding?.url, + npm : `https://www.npmjs.com/package/${data.name}/v/${data.version}`, unpkg : `https://unpkg.com/${data.name}@${data.version}/`, }, - unpackedSize : unpackedSize ?? 0, - dependencies : data.dependencies, - devDependencies : data.devDependencies, - installedBy : installedBy === undefined + unpackedSize : size, + unpackedSizeKB : size / 1000, + unpackedSizeMB : size / 1000000, + dependencies : data.dependencies, + devDependencies : data.devDependencies, + lifeCycleScripts : Object.keys( lcScripts ).length ? lcScripts : undefined, + installedBy : installedBy === undefined ? undefined : Array.isArray( installedBy ) ? installedBy @@ -151,20 +183,30 @@ export class PackageSuper { for ( const [ depName, depVersion ] of Object.entries( dependencies ) ) { - const packageKey = `${depName}@${depVersion}` - if ( !depVersion ) continue - if ( this.processedPackages.has( packageKey ) ) continue + try { + + const packageKey = `${depName}@${depVersion}` + if ( !depVersion ) continue + if ( this.processedPackages.has( packageKey ) ) continue + + this.processedPackages.add( packageKey ) - this.processedPackages.add( packageKey ) + const depData = await this.getRegistryData( depName, depVersion, level, parentName ) - const depData = await this.getRegistryData( depName, depVersion, level, parentName ) + packages.push( depData ) - packages.push( depData ) + if ( depData.dependencies ) { - if ( depData.dependencies ) { + const subDeps = await this.#processDependencies( depData.dependencies, level + 1, depName ) + packages.push( ...subDeps ) + + } + + } + catch ( e ) { - const subDeps = await this.#processDependencies( depData.dependencies, level + 1, depName ) - packages.push( ...subDeps ) + if ( this.opts?.skipError ) continue + throw e } diff --git a/packages/core/src/search/types.ts b/packages/core/src/search/types.ts index 131dc58..2694503 100644 --- a/packages/core/src/search/types.ts +++ b/packages/core/src/search/types.ts @@ -1,10 +1,11 @@ +import type { LIFE_CYCLE_SCRIPTS } from './const' import type { JSONSchemaForNPMPackageJsonFiles } from '@schemastore/package' export type PackageJSON = JSONSchemaForNPMPackageJsonFiles & { name : string version : string } - +type lifeCycleScripts = typeof LIFE_CYCLE_SCRIPTS[number] export type PackageInfo = { name : string version : string @@ -18,18 +19,22 @@ export type PackageInfo = { url : string } url: { + npm : string homepage? : string repository? : string funding? : string unpkg? : string } /** Unpacked size in bytes */ - unpackedSize : number - dependencies? : PackageJSON['dependencies'] - devDependencies? : PackageJSON['devDependencies'] - installedBy? : string[] + unpackedSize : number + unpackedSizeKB : number + unpackedSizeMB : number + dependencies? : PackageJSON['dependencies'] + devDependencies? : PackageJSON['devDependencies'] + lifeCycleScripts? : { [key in lifeCycleScripts]?: string } + installedBy? : string[] /** Level of the dependence installation. Main packages is 0 */ - level : number + level : number } export type SiziumResponse = { @@ -37,6 +42,8 @@ export type SiziumResponse = { packageNum : number /** Size in bytes */ size : number + sizeKB : number + sizeMB : number packages : PackageInfo[] } diff --git a/packages/web/src/lib/components/dep-main.svelte b/packages/web/src/lib/components/dep-main.svelte new file mode 100644 index 0000000..be0d336 --- /dev/null +++ b/packages/web/src/lib/components/dep-main.svelte @@ -0,0 +1,64 @@ + + +
+
+
+

Total Size

+

{roundToTwoDecimals(data.sizeMB)}mb ({roundToTwoDecimals(data.sizeKB)}kb)

+
+ +
+

Unpacked Size

+

{roundToTwoDecimals(data.packages[0].unpackedSizeMB)}mb ({roundToTwoDecimals(data.packages[0].unpackedSizeKB)}kb)

+
+
+ +
+
+

Packages installed

+

{data.packageNum === 1 ? 0 : data.packageNum }

+
+ +
+

Module Type

+

+ {data.packages[0].isESM ? 'ESM' : (data.packages[0].isCommonJS ? 'CommonJS' : 'Unknown')} +

+
+
+
+ + diff --git a/packages/web/src/lib/components/dependency.svelte b/packages/web/src/lib/components/dependency.svelte index b98a3aa..bb84e36 100644 --- a/packages/web/src/lib/components/dependency.svelte +++ b/packages/web/src/lib/components/dependency.svelte @@ -20,7 +20,7 @@

- {pkg.name} v{pkg.version} + {pkg.name} v{pkg.version}

{#if pkg.license} {pkg.license} diff --git a/packages/web/src/routes/+page.svelte b/packages/web/src/routes/+page.svelte index 7c9f961..1efbf0b 100644 --- a/packages/web/src/routes/+page.svelte +++ b/packages/web/src/routes/+page.svelte @@ -7,8 +7,9 @@ import { browser } from '$app/environment'; import DependencyItem from '$lib/components/dependency.svelte'; import DepLinks from '$lib/components/dep-links.svelte'; - import { roundToTwoDecimals, getPkgData, decodeQueryParam } from '$lib/utils'; + import { getPkgData, decodeQueryParam } from '$lib/utils'; import Search from '$lib/components/search.svelte'; + import DepMain from '$lib/components/dep-main.svelte'; let searchQuery = ''; @@ -133,7 +134,7 @@ -
-
-
-

Total Size

-

{roundToTwoDecimals(packageInfo.size / 1024 / 1024)}mb ({roundToTwoDecimals(packageInfo.size / 1024)}kb)

-
- -
-

Unpacked Size

-

{roundToTwoDecimals(packageInfo.packages[0].unpackedSize / 1024 / 1024)}mb ({roundToTwoDecimals(packageInfo.packages[0].unpackedSize / 1024)}kb)

-
-
- -
-
-

Packages installed

-

{packageInfo.packageNum === 1 ? 0 : packageInfo.packageNum }

-
- -
-

Module Type

-

- {packageInfo.packages[0].isESM ? 'ESM' : (packageInfo.packages[0].isCommonJS ? 'CommonJS' : 'Unknown')} -

-
-
-
+ {#if packageInfo.packages.length > 1}
@@ -218,26 +193,6 @@ .header { @apply flex sm:flex-row flex-col justify-between mb-4; } - .cards { - @apply grid grid-cols-1 md:grid-cols-2 gap-6 mb-8; - > div { - @apply space-y-4; - - > div { - @apply dark:bg-primary-800/20 p-4 rounded-lg; - - .title { - @apply text-sm; - } - .value { - @apply text-2xl font-bold; - - > span { - @apply dark:opacity-30 italic font-medium; - } - } - } - } - } + }