@@ -19,16 +19,9 @@ import {
1919 writeFileSync ,
2020} from "node:fs" ;
2121import { homedir , tmpdir } from "node:os" ;
22- import {
23- basename ,
24- dirname ,
25- isAbsolute ,
26- join ,
27- posix ,
28- relative ,
29- resolve as pathResolve ,
30- } from "node:path" ;
22+ import { basename , dirname , isAbsolute , join , relative , resolve as pathResolve } from "node:path" ;
3123import { fileURLToPath , pathToFileURL } from "node:url" ;
24+ import { expandPackageDistImportClosure } from "./lib/package-dist-imports.mjs" ;
3225
3326const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
3427const DEFAULT_PACKAGE_ROOT = join ( __dirname , ".." ) ;
@@ -400,145 +393,6 @@ export function pruneLegacyPluginRuntimeDepsState(params = {}) {
400393 return removed ;
401394}
402395
403- const JS_DIST_FILE_RE = / ^ d i s t \/ .* \. (?: c j s | j s | m j s ) $ / u;
404-
405- function stripSpecifierSuffix ( value ) {
406- return value . replace ( / [ ? # ] .* $ / u, "" ) ;
407- }
408-
409- function resolveDistImportPath ( importerPath , specifier ) {
410- if ( ! specifier . startsWith ( "." ) ) {
411- return null ;
412- }
413- const stripped = stripSpecifierSuffix ( specifier ) ;
414- if ( ! stripped ) {
415- return null ;
416- }
417- return posix . normalize ( posix . join ( posix . dirname ( importerPath ) , stripped ) ) ;
418- }
419-
420- function findStatementStart ( source , index ) {
421- return (
422- Math . max (
423- source . lastIndexOf ( ";" , index ) ,
424- source . lastIndexOf ( "{" , index ) ,
425- source . lastIndexOf ( "}" , index ) ,
426- source . lastIndexOf ( "\n" , index ) ,
427- source . lastIndexOf ( "\r" , index ) ,
428- ) + 1
429- ) ;
430- }
431-
432- function isImportSpecifierContext ( source , index ) {
433- const dynamicPrefix = source . slice ( Math . max ( 0 , index - 32 ) , index ) ;
434- if ( / \b i m p o r t \s * \( \s * $ / u. test ( dynamicPrefix ) ) {
435- return true ;
436- }
437- const statementPrefix = source . slice ( findStatementStart ( source , index ) , index ) . trimStart ( ) ;
438- return (
439- / ^ (?: i m p o r t | e x p o r t ) \b [ \s \S ] * \b f r o m \s * $ / u. test ( statementPrefix ) ||
440- / ^ i m p o r t \s * $ / u. test ( statementPrefix )
441- ) ;
442- }
443-
444- function collectImportSpecifiers ( source ) {
445- const specifiers = [ ] ;
446- let inBlockComment = false ;
447- let inLineComment = false ;
448- for ( let index = 0 ; index < source . length ; index += 1 ) {
449- if ( inBlockComment ) {
450- if ( source [ index ] === "*" && source [ index + 1 ] === "/" ) {
451- inBlockComment = false ;
452- index += 1 ;
453- }
454- continue ;
455- }
456- if ( inLineComment ) {
457- if ( source [ index ] === "\n" || source [ index ] === "\r" ) {
458- inLineComment = false ;
459- }
460- continue ;
461- }
462- if ( source [ index ] === "/" && source [ index + 1 ] === "*" ) {
463- inBlockComment = true ;
464- index += 1 ;
465- continue ;
466- }
467- if ( source [ index ] === "/" && source [ index + 1 ] === "/" ) {
468- inLineComment = true ;
469- index += 1 ;
470- continue ;
471- }
472-
473- const quote = source [ index ] ;
474- if ( quote !== '"' && quote !== "'" ) {
475- continue ;
476- }
477-
478- let cursor = index + 1 ;
479- let value = "" ;
480- while ( cursor < source . length ) {
481- const char = source [ cursor ] ;
482- if ( char === "\\" ) {
483- value += source . slice ( cursor , cursor + 2 ) ;
484- cursor += 2 ;
485- continue ;
486- }
487- if ( char === quote ) {
488- break ;
489- }
490- value += char ;
491- cursor += 1 ;
492- }
493- if ( cursor >= source . length ) {
494- break ;
495- }
496-
497- if ( value . startsWith ( "." ) && isImportSpecifierContext ( source , index ) ) {
498- specifiers . push ( value ) ;
499- }
500- index = cursor ;
501- }
502- return specifiers ;
503- }
504-
505- function expandInstalledDistImportClosure ( params ) {
506- const files = [ ...new Set ( params . files ) ] ;
507- const fileSet = new Set ( files ) ;
508- const expectedSet = new Set ( params . seedFiles ) ;
509- let changed = true ;
510-
511- while ( changed ) {
512- changed = false ;
513- for ( const importerPath of [ ...expectedSet ]
514- . filter ( ( file ) => fileSet . has ( file ) )
515- . toSorted ( ( left , right ) => left . localeCompare ( right ) ) ) {
516- if ( ! JS_DIST_FILE_RE . test ( importerPath ) || importerPath . includes ( "/node_modules/" ) ) {
517- continue ;
518- }
519- let source ;
520- try {
521- source = params . readText ( importerPath ) ;
522- } catch ( error ) {
523- if ( error ?. code === "ENOENT" ) {
524- continue ;
525- }
526- throw error ;
527- }
528- for ( const specifier of collectImportSpecifiers ( source ) ) {
529- const importedPath = resolveDistImportPath ( importerPath , specifier ) ;
530- if ( ! importedPath || ! fileSet . has ( importedPath ) || expectedSet . has ( importedPath ) ) {
531- continue ;
532- }
533- expectedSet . add ( importedPath ) ;
534- changed = true ;
535- }
536- }
537- }
538-
539- return [ ...expectedSet ] . toSorted ( ( left , right ) => left . localeCompare ( right ) ) ;
540- }
541-
542396export function pruneInstalledPackageDist ( params = { } ) {
543397 const packageRoot = params . packageRoot ?? DEFAULT_PACKAGE_ROOT ;
544398 const removeFile = params . unlinkSync ?? unlinkSync ;
@@ -569,11 +423,18 @@ export function pruneInstalledPackageDist(params = {}) {
569423 const installedFiles = listInstalledDistFiles ( params ) ;
570424 const readFile = params . readFileSync ?? readFileSync ;
571425 expectedFiles = new Set (
572- expandInstalledDistImportClosure ( {
426+ expandPackageDistImportClosure ( {
573427 files : installedFiles ,
574428 seedFiles : [ ...expectedFiles ] ,
575429 readText ( relativePath ) {
576- return readFile ( join ( packageRoot , relativePath ) , "utf8" ) ;
430+ try {
431+ return readFile ( join ( packageRoot , relativePath ) , "utf8" ) ;
432+ } catch ( error ) {
433+ if ( error ?. code === "ENOENT" ) {
434+ return "" ;
435+ }
436+ throw error ;
437+ }
577438 } ,
578439 } ) ,
579440 ) ;
0 commit comments