@@ -12,9 +12,158 @@ const rootPath = path.join(__dirname, '..')
1212const srcPath = path . join ( rootPath , 'src' )
1313const distPath = path . join ( rootPath , 'dist' )
1414
15+ /**
16+ * Plugin to shorten module paths in bundled output with conflict detection.
17+ * Uses @babel/parser and magic-string for precise AST-based modifications.
18+ */
19+ function createPathShorteningPlugin ( ) {
20+ return {
21+ name : 'shorten-module-paths' ,
22+ setup ( build ) {
23+ build . onEnd ( async result => {
24+ if ( ! result . outputFiles && result . metafile ) {
25+ // Dynamic imports to avoid adding to production dependencies
26+ const fs = await import ( 'node:fs/promises' )
27+ const { parse } = await import ( '@babel/parser' )
28+ const MagicString = ( await import ( 'magic-string' ) ) . default
29+
30+ const outputs = Object . keys ( result . metafile . outputs ) . filter ( f =>
31+ f . endsWith ( '.js' ) || f . endsWith ( '.mjs' ) ,
32+ )
33+
34+ for ( const outputPath of outputs ) {
35+ const content = await fs . readFile ( outputPath , 'utf8' )
36+ const magicString = new MagicString ( content )
37+
38+ // Track module paths and their shortened versions
39+ const pathMap = new Map ( )
40+ const conflictDetector = new Map ( )
41+
42+ function shortenPath ( longPath ) {
43+ if ( pathMap . has ( longPath ) ) {
44+ return pathMap . get ( longPath )
45+ }
46+
47+ let shortPath = longPath
48+
49+ // Handle pnpm scoped packages
50+ const scopedPnpmMatch = longPath . match (
51+ / n o d e _ m o d u l e s \/ \. p n p m \/ @ ( [ ^ + / ] + ) \+ ( [ ^ @ / ] + ) @ [ ^ / ] + \/ n o d e _ m o d u l e s \/ ( @ [ ^ / ] + \/ [ ^ / ] + ) \/ ( .+ ) / ,
52+ )
53+ if ( scopedPnpmMatch ) {
54+ const [ , _scope , _pkg , packageName , subpath ] = scopedPnpmMatch
55+ shortPath = `${ packageName } /${ subpath } `
56+ } else {
57+ // Handle pnpm non-scoped packages
58+ const pnpmMatch = longPath . match (
59+ / n o d e _ m o d u l e s \/ \. p n p m \/ ( [ ^ @ / ] + ) @ [ ^ / ] + \/ n o d e _ m o d u l e s \/ ( [ ^ / ] + ) \/ ( .+ ) / ,
60+ )
61+ if ( pnpmMatch ) {
62+ const [ , _pkgName , packageName , subpath ] = pnpmMatch
63+ shortPath = `${ packageName } /${ subpath } `
64+ }
65+ }
66+
67+ // Detect conflicts
68+ if ( conflictDetector . has ( shortPath ) ) {
69+ const existingPath = conflictDetector . get ( shortPath )
70+ if ( existingPath !== longPath ) {
71+ console . warn (
72+ `⚠ Path conflict detected:\n "${ shortPath } "\n Maps to: "${ existingPath } "\n Also from: "${ longPath } "\n Keeping original paths to avoid conflict.` ,
73+ )
74+ shortPath = longPath
75+ }
76+ } else {
77+ conflictDetector . set ( shortPath , longPath )
78+ }
79+
80+ pathMap . set ( longPath , shortPath )
81+ return shortPath
82+ }
83+
84+ // Parse AST to find all string literals containing module paths
85+ try {
86+ const ast = parse ( content , {
87+ sourceType : 'module' ,
88+ plugins : [ ] ,
89+ } )
90+
91+ // Walk through all comments
92+ for ( const comment of ast . comments || [ ] ) {
93+ if (
94+ comment . type === 'CommentLine' &&
95+ comment . value . includes ( 'node_modules' )
96+ ) {
97+ const originalPath = comment . value . trim ( )
98+ const shortPath = shortenPath ( originalPath )
99+
100+ if ( shortPath !== originalPath ) {
101+ magicString . overwrite (
102+ comment . start ,
103+ comment . end ,
104+ `// ${ shortPath } ` ,
105+ )
106+ }
107+ }
108+ }
109+
110+ // Walk through all string literals
111+ function walk ( node ) {
112+ if ( ! node || typeof node !== 'object' ) {
113+ return
114+ }
115+
116+ if (
117+ node . type === 'StringLiteral' &&
118+ node . value &&
119+ node . value . includes ( 'node_modules' )
120+ ) {
121+ const originalPath = node . value
122+ const shortPath = shortenPath ( originalPath )
123+
124+ if ( shortPath !== originalPath ) {
125+ magicString . overwrite (
126+ node . start + 1 ,
127+ node . end - 1 ,
128+ shortPath ,
129+ )
130+ }
131+ }
132+
133+ for ( const key of Object . keys ( node ) ) {
134+ if ( key === 'start' || key === 'end' || key === 'loc' ) {
135+ continue
136+ }
137+ const value = node [ key ]
138+ if ( Array . isArray ( value ) ) {
139+ for ( const item of value ) {
140+ walk ( item )
141+ }
142+ } else {
143+ walk ( value )
144+ }
145+ }
146+ }
147+
148+ walk ( ast . program )
149+ await fs . writeFile ( outputPath , magicString . toString ( ) , 'utf8' )
150+ } catch ( error ) {
151+ console . error (
152+ `Failed to shorten paths in ${ outputPath } :` ,
153+ error . message ,
154+ )
155+ }
156+ }
157+ }
158+ } )
159+ } ,
160+ }
161+ }
162+
15163/**
16164 * Plugin to handle local package aliases.
17165 * Provides consistent alias resolution across all Socket repos.
166+ * Note: Does not externalize @socketsecurity/lib - that should be bundled.
18167 */
19168function createAliasPlugin ( ) {
20169 const aliases = getLocalPackageAliases ( rootPath )
@@ -27,8 +176,13 @@ function createAliasPlugin() {
27176 return {
28177 name : 'local-package-aliases' ,
29178 setup ( build ) {
30- // Intercept imports for aliased packages.
179+ // Intercept imports for aliased packages (except @socketsecurity/lib which should be bundled)
31180 for ( const [ packageName , _aliasPath ] of Object . entries ( aliases ) ) {
181+ // Skip @socketsecurity /lib - it should be bundled, not externalized
182+ if ( packageName === '@socketsecurity/lib' ) {
183+ continue
184+ }
185+
32186 // Match both exact package name and subpath imports.
33187 build . onResolve (
34188 { filter : new RegExp ( `^${ packageName } (/|$)` ) } ,
@@ -47,6 +201,7 @@ function createAliasPlugin() {
47201export const buildConfig = {
48202 entryPoints : [ `${ srcPath } /index.ts` , `${ srcPath } /testing.ts` ] ,
49203 outdir : distPath ,
204+ outbase : srcPath ,
50205 bundle : true ,
51206 format : 'esm' ,
52207 // Target Node.js environment (not browser).
@@ -62,16 +217,14 @@ export const buildConfig = {
62217 outExtension : { '.js' : '.mjs' } ,
63218
64219 // Use plugin for local package aliases (consistent across all Socket repos)
65- plugins : [ createAliasPlugin ( ) ] . filter ( Boolean ) ,
220+ plugins : [ createPathShorteningPlugin ( ) , createAliasPlugin ( ) ] . filter ( Boolean ) ,
66221
67222 // External dependencies.
68223 // With platform: 'node', esbuild automatically externalizes all Node.js
69224 // built-ins. The explicit external array with builtinModules is redundant
70225 // (but doesn't hurt as extra safety).
71- external : [
72- // External dependencies that shouldn't be bundled.
73- '@socketsecurity/lib' ,
74- ] ,
226+ // Note: @socketsecurity /lib is bundled (not external) to reduce consumer dependencies
227+ external : [ ] ,
75228
76229 // Banner for generated code
77230 banner : {
0 commit comments