diff --git a/package.json b/package.json index d6bb1a8..8812a22 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,7 @@ "url": "git+https://github.com/e18e/cli.git" }, "keywords": [ - "e18e", - "attw", + "e18e", "dependencies", "dependency", "publint" diff --git a/src/analyze/publint.ts b/src/analyze/publint.ts index e960908..5425b4f 100644 --- a/src/analyze/publint.ts +++ b/src/analyze/publint.ts @@ -1,39 +1,16 @@ import {publint} from 'publint'; import {formatMessage} from 'publint/utils'; -import type {ReportPluginResult, Options, AnalysisContext} from '../types.js'; -import fs from 'node:fs/promises'; -import path from 'node:path'; +import type {ReportPluginResult, AnalysisContext} from '../types.js'; export async function runPublint( context: AnalysisContext -): Promise { - const targetTarballs = context.options?.targetTarball; - - if (targetTarballs && targetTarballs.length > 0) { - return runPublintWithTarballs(targetTarballs, context.options); - } - - return {messages: []}; -} - -export async function runPublintWithTarballs( - targetTarballs: string[], - options?: Options ): Promise { const result: ReportPluginResult = { messages: [] }; - const root = options?.root || process.cwd(); - for (const targetTarball of targetTarballs) { - const targetTarballPath = path.resolve(root, targetTarball); - // TODO (jg): handle failed reads gracefully - const buffer = await fs.readFile(targetTarballPath); - const tarball = buffer.buffer.slice( - buffer.byteOffset, - buffer.byteOffset + buffer.byteLength - ) as ArrayBuffer; - const publintResult = await publint({pack: {tarball}}); + try { + const publintResult = await publint({pack: 'auto', pkgDir: context.root}); for (const problem of publintResult.messages) { result.messages.push({ severity: problem.type, @@ -41,6 +18,8 @@ export async function runPublintWithTarballs( message: formatMessage(problem, publintResult.pkg) ?? '' }); } + } catch (error) { + console.error(`Failed to run publint: ${error}`); } return result; diff --git a/src/commands/analyze.meta.ts b/src/commands/analyze.meta.ts index 68c98f2..b955ee5 100644 --- a/src/commands/analyze.meta.ts +++ b/src/commands/analyze.meta.ts @@ -2,18 +2,6 @@ export const meta = { name: 'analyze', description: 'Analyze the project for any warnings or errors', args: { - 'base-tarball': { - type: 'string', - multiple: true, - description: - 'Path to base tarball file(s) (e.g. main) to analyze (globs supported)' - }, - 'target-tarball': { - type: 'string', - multiple: true, - description: - 'Path to target tarball file(s) (e.g. PR branch) to analyze (globs supported)' - }, 'log-level': { type: 'enum', choices: ['debug', 'info', 'warn', 'error'], diff --git a/src/commands/analyze.ts b/src/commands/analyze.ts index 1dc4080..555b137 100644 --- a/src/commands/analyze.ts +++ b/src/commands/analyze.ts @@ -21,8 +21,6 @@ function formatBytes(bytes: number) { export async function run(ctx: CommandContext) { const [_commandName, providedPath] = ctx.positionals; - const baseTarball = ctx.values['base-tarball']; - const targetTarball = ctx.values['target-tarball']; const logLevel = ctx.values['log-level']; let root: string | undefined = undefined; @@ -33,7 +31,7 @@ export async function run(ctx: CommandContext) { prompts.intro('Analyzing...'); - // Path can be a directory (analyze project) or a tarball file (analyze tarball) + // Path can be a directory (analyze project) if (providedPath) { let stat: Stats | null = null; try { @@ -50,14 +48,12 @@ export async function run(ctx: CommandContext) { root = providedPath; } - // Then analyze the tarball + // Then read the manifest const customManifests = ctx.values['manifest']; const {stats, messages} = await report({ root, - manifest: customManifests, - baseTarball, - targetTarball + manifest: customManifests }); prompts.log.info('Summary'); diff --git a/src/tarball-file-system.ts b/src/tarball-file-system.ts deleted file mode 100644 index 67ba590..0000000 --- a/src/tarball-file-system.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {unpack, type UnpackResult} from '@publint/pack'; -import type {FileSystem} from './file-system.js'; -import path from 'node:path'; - -export class TarballFileSystem implements FileSystem { - #tarball: ArrayBuffer; - #unpackResult?: UnpackResult; - - public get tarball(): ArrayBuffer { - return this.#tarball; - } - - constructor(tarball: ArrayBuffer) { - this.#tarball = tarball; - } - - async #getUnpackResult(): Promise { - if (!this.#unpackResult) { - this.#unpackResult = await unpack(this.#tarball); - } - return this.#unpackResult; - } - - async getRootDir(): Promise { - const {rootDir} = await this.#getUnpackResult(); - return rootDir; - } - - async listPackageFiles(): Promise { - const {files} = await this.#getUnpackResult(); - - return files - .filter((file) => file.name.endsWith('/package.json')) - .map((file) => file.name); - } - - async readFile(filePath: string): Promise { - const {files} = await this.#getUnpackResult(); - const fullPath = path.posix.join(await this.getRootDir(), filePath); - const file = files.find((f) => f.name === fullPath); - if (!file) { - throw new Error(`File not found: ${filePath}`); - } - return new TextDecoder().decode(file.data); - } - - async getInstallSize(): Promise { - const {files} = await this.#getUnpackResult(); - return files.reduce((acc, file) => acc + file.data.byteLength, 0); - } - - async fileExists(filePath: string): Promise { - const {files} = await this.#getUnpackResult(); - const rootDir = await this.getRootDir(); - const fullPath = path.posix.join(rootDir, filePath); - return files.some((file) => file.name === fullPath); - } -} diff --git a/src/test/analyze/__snapshots__/dependencies.test.ts.snap b/src/test/analyze/__snapshots__/dependencies.test.ts.snap index 20de710..87613df 100644 --- a/src/test/analyze/__snapshots__/dependencies.test.ts.snap +++ b/src/test/analyze/__snapshots__/dependencies.test.ts.snap @@ -71,21 +71,3 @@ exports[`analyzeDependencies (local) > should handle symlinks 1`] = ` }, } `; - -exports[`analyzeDependencies (tarball) > should analyze a real tarball fixture 1`] = ` -{ - "messages": [], - "stats": { - "dependencyCount": { - "cjs": 0, - "development": 0, - "duplicate": 0, - "esm": 0, - "production": 0, - }, - "installSize": 226, - "name": "test-package", - "version": "1.0.0", - }, -} -`; diff --git a/src/test/analyze/dependencies.test.ts b/src/test/analyze/dependencies.test.ts index 4e0016e..c49fdfc 100644 --- a/src/test/analyze/dependencies.test.ts +++ b/src/test/analyze/dependencies.test.ts @@ -1,6 +1,5 @@ import {describe, it, expect, beforeEach, afterEach} from 'vitest'; import {runDependencyAnalysis} from '../../analyze/dependencies.js'; -import {TarballFileSystem} from '../../tarball-file-system.js'; import {LocalFileSystem} from '../../local-file-system.js'; import { createTempDir, @@ -12,59 +11,6 @@ import { import type {AnalysisContext} from '../../types.js'; import fs from 'node:fs/promises'; import path from 'node:path'; -import {fileURLToPath} from 'node:url'; - -const FIXTURE_DIR = path.join( - path.dirname(fileURLToPath(import.meta.url)), - '../../../test/fixtures' -); - -// Integration test using a real tarball fixture - -describe('analyzeDependencies (tarball)', () => { - it('should analyze a real tarball fixture', async () => { - const tarballPath = path.join(FIXTURE_DIR, 'test-package.tgz'); - const tarballBuffer = await fs.readFile(tarballPath); - const fileSystem = new TarballFileSystem( - tarballBuffer.buffer as ArrayBuffer - ); - const context: AnalysisContext = { - fs: fileSystem, - root: '.', - messages: [], - stats: { - name: 'unknown', - version: 'unknown', - dependencyCount: { - cjs: 0, - esm: 0, - duplicate: 0, - production: 0, - development: 0 - }, - extraStats: [] - }, - lockfile: { - type: 'npm', - packages: [], - root: { - name: 'test-package', - version: '1.0.0', - dependencies: [], - devDependencies: [], - optionalDependencies: [], - peerDependencies: [] - } - }, - packageFile: { - name: 'test-package', - version: '1.0.0' - } - }; - const result = await runDependencyAnalysis(context); - expect(result).toMatchSnapshot(); - }); -}); describe('analyzeDependencies (local)', () => { let tempDir: string; diff --git a/src/test/tarball-file-system.test.ts b/src/test/tarball-file-system.test.ts deleted file mode 100644 index ecbcf41..0000000 --- a/src/test/tarball-file-system.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import {describe, it, expect, beforeEach, afterEach} from 'vitest'; -import {TarballFileSystem} from '../tarball-file-system.js'; -import * as fs from 'node:fs/promises'; -import * as path from 'node:path'; -import {tmpdir} from 'node:os'; -import {spawn} from 'node:child_process'; - -async function runNpmPack(cwd: string): Promise { - return new Promise((resolve, reject) => { - const proc = spawn('npm', ['pack'], {cwd}); - - proc.on('close', (code) => { - if (code !== 0) { - reject(new Error(`npm pack failed with code ${code}`)); - } else { - resolve(); - } - }); - }); -} - -async function createTarballBuffer(cwd: string): Promise { - await runNpmPack(cwd); - - // Find the generated .tgz file - const files = await fs.readdir(cwd); - const tgzFile = files.find((f) => f.endsWith('.tgz')); - if (!tgzFile) { - throw new Error('No .tgz file found after npm pack'); - } - - // Read the tarball as ArrayBuffer - const tgzPath = path.join(cwd, tgzFile); - const buffer = await fs.readFile(tgzPath); - return buffer.buffer.slice( - buffer.byteOffset, - buffer.byteOffset + buffer.byteLength - ); -} - -describe('TarballFileSystem', () => { - let tempDir: string; - - beforeEach(async () => { - tempDir = await fs.mkdtemp(path.join(tmpdir(), 'reporter-test-')); - }); - - afterEach(async () => { - await fs.rm(tempDir, {recursive: true, force: true}); - }); - - describe('fileExists', () => { - it('should return false when file does not exist in tarball', async () => { - // Create a minimal package.json for the tarball - await fs.writeFile( - path.join(tempDir, 'package.json'), - JSON.stringify({ - name: 'test-package', - version: '1.0.0' - }) - ); - - const tarball = await createTarballBuffer(tempDir); - const fileSystem = new TarballFileSystem(tarball); - const hasConfig = await fileSystem.fileExists('/tsconfig.json'); - expect(hasConfig).toBe(false); - }); - - it('should return true when file exists in tarball', async () => { - // Create a minimal package.json for the tarball - await fs.writeFile( - path.join(tempDir, 'package.json'), - JSON.stringify({ - name: 'test-package', - version: '1.0.0' - }) - ); - - await fs.writeFile(path.join(tempDir, 'tsconfig.json'), '{}'); - const tarball = await createTarballBuffer(tempDir); - const fileSystem = new TarballFileSystem(tarball); - const hasConfig = await fileSystem.fileExists('/tsconfig.json'); - expect(hasConfig).toBe(true); - }); - }); -}); diff --git a/src/test/utils.ts b/src/test/utils.ts index 72a7d18..62bcbc8 100644 --- a/src/test/utils.ts +++ b/src/test/utils.ts @@ -97,17 +97,3 @@ export async function createTestPackageWithDependencies( await createTestPackage(depDir, dep); } } - -export function createMockTarball(files: Array<{name: string; content: any}>) { - return { - files: files.map((file) => ({ - name: file.name, - data: new TextEncoder().encode( - typeof file.content === 'string' - ? file.content - : JSON.stringify(file.content) - ) - })), - rootDir: 'package' - }; -} diff --git a/src/types.ts b/src/types.ts index 9f9d2e3..c0a1f27 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,8 +5,6 @@ import type {ParsedLockFile} from 'lockparse'; export interface Options { root?: string; manifest?: string[]; - baseTarball?: string[]; - targetTarball?: string[]; } export interface StatLike {