Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/archives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,26 @@ import { pipeline } from 'node:stream/promises'
import { createGunzip } from 'node:zlib'
import process from 'node:process'

import AdmZip from './external/adm-zip.js'
import tarFs from './external/tar-fs.js'
import type AdmZipType from './external/adm-zip.js'
import type tarFsType from './external/tar-fs.js'

let _AdmZip: typeof AdmZipType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getAdmZip() {
if (_AdmZip === undefined) {
_AdmZip = /*@__PURE__*/ require('./external/adm-zip.js')
}
return _AdmZip!
}

let _tarFs: typeof tarFsType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getTarFs() {
if (_tarFs === undefined) {
_tarFs = /*@__PURE__*/ require('./external/tar-fs.js')
}
return _tarFs!
}

import { safeMkdir } from './fs.js'
import { normalizePath } from './paths/normalize.js'
Expand Down Expand Up @@ -142,6 +160,7 @@ export async function extractTar(

let destroyScheduled = false

const tarFs = getTarFs()
const extractStream = tarFs.extract(normalizedOutputDir, {
map: (header: { name: string; size?: number; type?: string }) => {
// Skip if destroy already scheduled
Expand Down Expand Up @@ -267,6 +286,7 @@ export async function extractTarGz(

let destroyScheduled = false

const tarFs = getTarFs()
const extractStream = tarFs.extract(normalizedOutputDir, {
map: (header: { name: string; size?: number; type?: string }) => {
// Skip if destroy already scheduled
Expand Down Expand Up @@ -387,6 +407,7 @@ export async function extractZip(
const normalizedOutputDir = normalizePath(outputDir)
await safeMkdir(normalizedOutputDir)

const AdmZip = getAdmZip()
const zip = new AdmZip(archivePath)
const path = getPath()

Expand Down
26 changes: 21 additions & 5 deletions src/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,21 @@ import type {
import { getAbortSignal } from './constants/process'

import { isArray } from './arrays'
import { deleteAsync, deleteSync } from './external/del'
import type {
deleteAsync as deleteAsyncType,
deleteSync as deleteSyncType,
} from './external/del'

let _del:
| { deleteAsync: typeof deleteAsyncType; deleteSync: typeof deleteSyncType }
| undefined
/*@__NO_SIDE_EFFECTS__*/
function getDel() {
if (_del === undefined) {
_del = /*@__PURE__*/ require('./external/del')
}
return _del!
}
import { pRetry } from './promises'
import { defaultIgnore, getGlobMatcher } from './globs'
import type { JsonReviver } from './json/types'
Expand Down Expand Up @@ -1235,7 +1249,7 @@ export async function safeDelete(
filepath: PathLike | PathLike[],
options?: RemoveOptions | undefined,
) {
// deleteAsync is imported at the top
// deleteAsync is lazily loaded via getDel()
const opts = { __proto__: null, ...options } as RemoveOptions
const patterns = isArray(filepath)
? filepath.map(pathLikeToString)
Expand Down Expand Up @@ -1276,9 +1290,10 @@ export async function safeDelete(
const retryDelay = opts.retryDelay ?? defaultRemoveOptions.retryDelay

/* c8 ignore start - External del call */
const del = getDel()
await pRetry(
async () => {
await deleteAsync(patterns, {
await del.deleteAsync(patterns, {
dryRun: false,
force: shouldForce,
onlyFiles: false,
Expand Down Expand Up @@ -1328,7 +1343,7 @@ export function safeDeleteSync(
filepath: PathLike | PathLike[],
options?: RemoveOptions | undefined,
) {
// deleteSync is imported at the top
// deleteSync is lazily loaded via getDel()
const opts = { __proto__: null, ...options } as RemoveOptions
const patterns = isArray(filepath)
? filepath.map(pathLikeToString)
Expand Down Expand Up @@ -1369,11 +1384,12 @@ export function safeDeleteSync(
const retryDelay = opts.retryDelay ?? defaultRemoveOptions.retryDelay

/* c8 ignore start - External del call */
const del = getDel()
let lastError: Error | undefined
let delay = retryDelay
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
deleteSync(patterns, {
del.deleteSync(patterns, {
dryRun: false,
force: shouldForce,
onlyFiles: false,
Expand Down
29 changes: 25 additions & 4 deletions src/globs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,26 @@
* Provides file filtering and glob matcher functions for npm-like behavior.
*/

// IMPORTANT: Do not use destructuring here - use direct assignment instead.
import * as fastGlob from './external/fast-glob.js'
import picomatch from './external/picomatch.js'
import type * as fastGlobType from './external/fast-glob.js'
import type picomatchType from './external/picomatch.js'

let _fastGlob: typeof fastGlobType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getFastGlob() {
if (_fastGlob === undefined) {
_fastGlob = /*@__PURE__*/ require('./external/fast-glob.js')
}
return _fastGlob!
}

let _picomatch: typeof picomatchType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getPicomatch() {
if (_picomatch === undefined) {
_picomatch = /*@__PURE__*/ require('./external/picomatch.js')
}
return _picomatch!
}

import { objectFreeze as ObjectFreeze } from './objects'
import {
Expand Down Expand Up @@ -112,6 +129,7 @@ export function globStreamLicenses(
ignore.push(LICENSE_ORIGINAL_GLOB_RECURSIVE)
}
/* c8 ignore start - External fast-glob call */
const fastGlob = getFastGlob()
return fastGlob.globStream(
[recursive ? LICENSE_GLOB_RECURSIVE : LICENSE_GLOB],
{
Expand Down Expand Up @@ -188,7 +206,8 @@ export function getGlobMatcher(
...(negativePatterns.length > 0 ? { ignore: negativePatterns } : {}),
}

/* c8 ignore next 4 - External picomatch call */
/* c8 ignore next 5 - External picomatch call */
const picomatch = getPicomatch()
matcher = picomatch(
positivePatterns.length > 0 ? positivePatterns : patterns,
matchOptions,
Expand All @@ -209,6 +228,7 @@ export function glob(
options?: FastGlobOptions,
): Promise<string[]> {
/* c8 ignore next - External fast-glob call */
const fastGlob = getFastGlob()
return fastGlob.glob(patterns, options as import('fast-glob').Options)
}

Expand All @@ -222,5 +242,6 @@ export function globSync(
options?: FastGlobOptions,
): string[] {
/* c8 ignore next - External fast-glob call */
const fastGlob = getFastGlob()
return fastGlob.globSync(patterns, options as import('fast-glob').Options)
}
24 changes: 21 additions & 3 deletions src/sorts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,32 @@
* Provides various comparison utilities for arrays and collections.
*/

import * as fastSort from './external/fast-sort.js'
import * as semver from './external/semver.js'
import type * as fastSortType from './external/fast-sort.js'
import type * as semverType from './external/semver.js'

let _semver: typeof semverType | undefined
function getSemver() {
if (_semver === undefined) {
_semver = require('./external/semver.js')
}
return _semver!
}

let _fastSort: typeof fastSortType | undefined
function getFastSort() {
if (_fastSort === undefined) {
_fastSort = require('./external/fast-sort.js')
}
return _fastSort!
}

/**
* Compare semantic versions.
*/
/*@__NO_SIDE_EFFECTS__*/
export function compareSemver(a: string, b: string): number {
/* c8 ignore next 2 - External semver calls */
const semver = getSemver()
const validA: string | null = semver.valid(a)
const validB: string | null = semver.valid(b)

Expand Down Expand Up @@ -89,7 +106,8 @@ export function naturalSorter<T>(
arrayToSort: T[],
): ReturnType<FastSortFunction> {
if (_naturalSorter === undefined) {
/* c8 ignore next 3 - External fast-sort call */
/* c8 ignore next 4 - External fast-sort call */
const fastSort = getFastSort()
_naturalSorter = fastSort.createNewSortInstance({
comparer: naturalCompare,
}) as FastSortFunction
Expand Down
16 changes: 13 additions & 3 deletions src/spawn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,16 @@ import process from 'node:process'
import { getAbortSignal } from './constants/process'
import { stackWithCauses } from './errors'

import npmCliPromiseSpawn from './external/@npmcli/promise-spawn'
import type npmCliPromiseSpawnType from './external/@npmcli/promise-spawn'

let _npmCliPromiseSpawn: typeof npmCliPromiseSpawnType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getNpmCliPromiseSpawn() {
if (_npmCliPromiseSpawn === undefined) {
_npmCliPromiseSpawn = /*@__PURE__*/ require('./external/@npmcli/promise-spawn')
}
return _npmCliPromiseSpawn!
}

let _path: typeof import('node:path') | undefined
/**
Expand Down Expand Up @@ -738,7 +747,7 @@ export function spawn(
if (shouldStopSpinner) {
spinnerInstance.stop()
}
// npmCliPromiseSpawn is imported at the top
// npmCliPromiseSpawn is lazily loaded via getNpmCliPromiseSpawn()
// Use __proto__: null to prevent prototype pollution when passing to
// third-party code, Node.js built-ins, or JavaScript built-in methods.
// https://github.com/npm/promise-spawn
Expand Down Expand Up @@ -769,10 +778,11 @@ export function spawn(
gid: spawnOptions.gid,
} as unknown as PromiseSpawnOptions
/* c8 ignore start - External npmCliPromiseSpawn call */
const npmCliPromiseSpawn = getNpmCliPromiseSpawn()
const spawnPromise = npmCliPromiseSpawn(
actualCmd,
args ? [...args] : [],
promiseSpawnOpts as Parameters<typeof npmCliPromiseSpawn>[2],
promiseSpawnOpts as Parameters<typeof npmCliPromiseSpawnType>[2],
extra,
)
/* c8 ignore stop */
Expand Down
16 changes: 15 additions & 1 deletion src/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@
*/

import { ansiRegex, stripAnsi } from './ansi'
import { eastAsianWidth } from './external/get-east-asian-width'
import type { eastAsianWidth as eastAsianWidthType } from './external/get-east-asian-width'

let _eastAsianWidth: typeof eastAsianWidthType | undefined
/*@__NO_SIDE_EFFECTS__*/
function getEastAsianWidth() {
if (_eastAsianWidth === undefined) {
_eastAsianWidth = /*@__PURE__*/ (
require('./external/get-east-asian-width') as {
eastAsianWidth: typeof eastAsianWidthType
}
).eastAsianWidth
}
return _eastAsianWidth!
}
// Import get-east-asian-width from external wrapper.
// This library implements Unicode Standard Annex #11 (East Asian Width).
// https://www.unicode.org/reports/tr11/
Expand Down Expand Up @@ -668,6 +681,7 @@ export function stringWidth(text: string): number {
// - Most terminal emulators default to narrow for ambiguous characters
// - Consistent with string-width's default behavior
const eastAsianWidthOptions = { ambiguousAsWide: false }
const eastAsianWidth = getEastAsianWidth()

// KEY IMPROVEMENT #3: Comprehensive Width Calculation
//
Expand Down
Loading
Loading