Skip to content

Commit 0007488

Browse files
authored
Fix blessed-contrib inlining (#464)
1 parent 757d90e commit 0007488

File tree

8 files changed

+736
-266
lines changed

8 files changed

+736
-266
lines changed

.config/rollup.base.config.mjs

Lines changed: 88 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import typescriptPlugin from '@rollup/plugin-typescript'
1111
import { purgePolyfills } from 'unplugin-purge-polyfills'
1212

1313
import { readPackageJsonSync } from '@socketsecurity/registry/lib/packages'
14+
import { escapeRegExp } from '@socketsecurity/registry/lib/regexps'
1415
import { spawnSync } from '@socketsecurity/registry/lib/spawn'
1516

1617
import constants from '../scripts/constants.js'
@@ -42,7 +43,11 @@ const {
4243
VITEST
4344
} = constants
4445

45-
export const EXTERNAL_PACKAGES = ['@socketsecurity/registry', 'blessed']
46+
export const EXTERNAL_PACKAGES = [
47+
'@socketsecurity/registry',
48+
'blessed',
49+
'blessed-contrib'
50+
]
4651

4752
const builtinAliases = builtinModules.reduce((o, n) => {
4853
o[n] = `node:${n}`
@@ -51,10 +56,6 @@ const builtinAliases = builtinModules.reduce((o, n) => {
5156

5257
const danglingRequiresRegExp = /^\s*require\(["'].+?["']\);?\r?\n/gm
5358

54-
// eslint-disable-next-line no-unused-vars
55-
const blessedRequiresRegExp =
56-
/(?<=require\(["'])blessed(?:\/[^"']+)?(?=["']\))/g
57-
5859
const requireTinyColorsRegExp = /require\(["']tiny-colors["']\)/g
5960

6061
const requireUrlAssignmentRegExp =
@@ -101,8 +102,31 @@ export default function baseConfig(extendConfig = {}) {
101102
const shadowNpmInjectSrcPath = path.join(rootSrcPath, 'shadow/npm/inject.ts')
102103
const shadowNpmPathsSrcPath = path.join(rootSrcPath, 'shadow/npm/paths.ts')
103104

104-
const extendPlugins = extendConfig.plugins ?? []
105-
const hasPlugin = name => !!extendPlugins.find(p => p.name === name)
105+
const extendPlugins = Array.isArray(extendConfig.plugins)
106+
? extendConfig.plugins.slice()
107+
: []
108+
const extractedPlugins = { __proto__: null }
109+
if (extendPlugins.length) {
110+
for (const pluginName of [
111+
'babel',
112+
'commonjs',
113+
'json',
114+
'node-resolve',
115+
'typescript',
116+
'unplugin-purge-polyfills'
117+
]) {
118+
for (let i = 0, { length } = extendPlugins; i < length; i += 1) {
119+
const p = extendPlugins[i]
120+
if (p?.name === pluginName) {
121+
extractedPlugins[pluginName] = p
122+
// Remove from extendPlugins array.
123+
extendPlugins.splice(i, 1)
124+
length -= 1
125+
i -= 1
126+
}
127+
}
128+
}
129+
}
106130

107131
const config = {
108132
input: {
@@ -118,10 +142,17 @@ export default function baseConfig(extendConfig = {}) {
118142
: {})
119143
},
120144
external(id_) {
145+
const id = normalizeId(id_)
146+
if (id.includes('blessed')) {
147+
console.log(
148+
id,
149+
getPackageName(id),
150+
EXTERNAL_PACKAGES.includes(getPackageName(id))
151+
)
152+
}
121153
if (id_.endsWith(ROLLUP_EXTERNAL_SUFFIX) || isBuiltin(id_)) {
122154
return true
123155
}
124-
const id = normalizeId(id_)
125156
return (
126157
id.endsWith('.d.cts') ||
127158
id.endsWith('.d.mts') ||
@@ -142,63 +173,42 @@ export default function baseConfig(extendConfig = {}) {
142173
},
143174
...extendConfig,
144175
plugins: [
145-
...(hasPlugin('node-resolve')
146-
? []
147-
: [
148-
nodeResolve({
149-
exportConditions: ['node'],
150-
extensions: ['.mjs', '.js', '.json', '.ts'],
151-
preferBuiltins: true
152-
})
153-
]),
154-
...(hasPlugin('json') ? [] : [jsonPlugin()]),
155-
...(hasPlugin('typescript')
156-
? []
157-
: [
158-
typescriptPlugin({
159-
include: ['src/**/*.ts'],
160-
noForceEmit: true,
161-
outputToFilesystem: true,
162-
// Lazily access constants.rootConfigPath.
163-
tsconfig: path.join(
164-
constants.rootConfigPath,
165-
'tsconfig.rollup.json'
166-
)
167-
})
168-
]),
169-
...(hasPlugin('commonjs')
170-
? []
171-
: [
172-
commonjsPlugin({
173-
defaultIsModuleExports: true,
174-
extensions: ['.cjs', '.js'],
175-
ignoreDynamicRequires: true,
176-
ignoreGlobal: true,
177-
ignoreTryCatch: true,
178-
strictRequires: true
179-
})
180-
]),
181-
...(hasPlugin('babel')
182-
? []
183-
: [
184-
babelPlugin({
185-
babelHelpers: 'runtime',
186-
babelrc: false,
187-
// Lazily access constants.rootConfigPath.
188-
configFile: path.join(
189-
constants.rootConfigPath,
190-
'babel.config.js'
191-
),
192-
extensions: ['.ts', '.js', '.cjs', '.mjs']
193-
})
194-
]),
195-
...(hasPlugin('unplugin-purge-polyfills')
196-
? []
197-
: [
198-
purgePolyfills.rollup({
199-
replacements: {}
200-
})
201-
]),
176+
extractedPlugins['node-resolve'] ??
177+
nodeResolve({
178+
exportConditions: ['node'],
179+
extensions: ['.mjs', '.js', '.json', '.ts'],
180+
preferBuiltins: true
181+
}),
182+
extractedPlugins['json'] ?? jsonPlugin(),
183+
extractedPlugins['typescript'] ??
184+
typescriptPlugin({
185+
include: ['src/**/*.ts'],
186+
noForceEmit: true,
187+
outputToFilesystem: true,
188+
// Lazily access constants.rootConfigPath.
189+
tsconfig: path.join(constants.rootConfigPath, 'tsconfig.rollup.json')
190+
}),
191+
extractedPlugins['commonjs'] ??
192+
commonjsPlugin({
193+
defaultIsModuleExports: true,
194+
extensions: ['.cjs', '.js'],
195+
ignoreDynamicRequires: true,
196+
ignoreGlobal: true,
197+
ignoreTryCatch: true,
198+
strictRequires: true
199+
}),
200+
extractedPlugins['babel'] ??
201+
babelPlugin({
202+
babelHelpers: 'runtime',
203+
babelrc: false,
204+
// Lazily access constants.rootConfigPath.
205+
configFile: path.join(constants.rootConfigPath, 'babel.config.js'),
206+
extensions: ['.ts', '.js', '.cjs', '.mjs']
207+
}),
208+
extractedPlugins['unplugin-purge-polyfills'] ??
209+
purgePolyfills.rollup({
210+
replacements: {}
211+
}),
202212
// Inline process.env values.
203213
replacePlugin({
204214
delimiters: ['(?<![\'"])\\b', '(?![\'"])'],
@@ -297,12 +307,19 @@ export default function baseConfig(extendConfig = {}) {
297307
find: danglingRequiresRegExp,
298308
replace: ''
299309
}),
300-
// Replace require('blessed/lib/widgets/xyz') with require('../blessed/lib/widgets/xyz').
301-
// socketModifyPlugin({
302-
// find: blessedRequiresRegExp,
303-
// replace: (id) => `./${id}`
304-
// }),
305-
...(extendConfig.plugins ?? [])
310+
// Replace requires like require('blessed/lib/widgets/screen') with
311+
// require('../blessed/lib/widgets/screen').
312+
...[/*'@socketsecurity/registry',*/ 'blessed', 'blessed-contrib'].map(n => {
313+
const requiresRegExp = new RegExp(
314+
`(?<=require\\(["'])${escapeRegExp(n)}(?:=(?:\\/[^"']+)?["']\\))`,
315+
'g'
316+
)
317+
return socketModifyPlugin({
318+
find: requiresRegExp,
319+
replace: id => `./${id}`
320+
})
321+
}),
322+
...extendPlugins
306323
]
307324
}
308325

.config/rollup.dist.config.mjs

Lines changed: 108 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import assert from 'node:assert'
22
import { existsSync, promises as fs } from 'node:fs'
3+
import os from 'node:os'
34
import path from 'node:path'
45
import util from 'node:util'
56

67
import { glob as tinyGlob } from 'tinyglobby'
78

8-
import { readJson, writeJson } from '@socketsecurity/registry/lib/fs'
9+
import { readJson, remove, writeJson } from '@socketsecurity/registry/lib/fs'
910
import { toSortedObject } from '@socketsecurity/registry/lib/objects'
1011
import {
1112
fetchPackageManifest,
@@ -40,38 +41,38 @@ const SENTRY_NODE = '@sentry/node'
4041
const SOCKET_DESCRIPTION = 'CLI tool for Socket.dev'
4142
const SOCKET_DESCRIPTION_WITH_SENTRY = `${SOCKET_DESCRIPTION}, includes Sentry error handling, otherwise identical to the regular \`${SOCKET_CLI_BIN_NAME}\` package`
4243

43-
// eslint-disable-next-line no-unused-vars
44-
async function copyBlessedWidgets() {
45-
// Copy blessed package files to dist.
46-
const blessedDestPath = path.join(rootDistPath, 'blessed')
47-
const blessedNmPath = path.join(rootPath, 'node_modules/blessed')
48-
const folders = ['lib', 'usr', 'vendor']
49-
await Promise.all(
50-
folders.map(f =>
51-
fs.cp(path.join(blessedNmPath, f), path.join(blessedDestPath, f), {
52-
recursive: true
53-
})
54-
)
55-
)
44+
async function copyInitGradle() {
45+
const filepath = path.join(rootSrcPath, 'commands/manifest/init.gradle')
46+
const destPath = path.join(rootDistPath, 'init.gradle')
47+
await fs.copyFile(filepath, destPath)
48+
}
49+
50+
async function copyPackage(pkgName) {
51+
const pkgDestPath = path.join(rootDistPath, pkgName)
52+
const pkgNmPath = path.join(rootPath, `node_modules/${pkgName}`)
53+
// Copy entire package folder over to dist.
54+
await fs.cp(pkgNmPath, pkgDestPath, { recursive: true })
5655
// Add 'use strict' directive to js files.
5756
const jsFiles = await tinyGlob(['**/*.js'], {
5857
absolute: true,
59-
cwd: blessedDestPath
58+
cwd: pkgDestPath
6059
})
6160
await Promise.all(
6261
jsFiles.map(async p => {
6362
const content = await fs.readFile(p, 'utf8')
64-
await fs.writeFile(p, `'use strict'\n\n${content}`, 'utf8')
63+
// Start by trimming the hashbang.
64+
const hashbang = /^#!.*(?=\r?\n|$)/.exec(content)?.[0] ?? ''
65+
let trimmed = content.slice(hashbang.length).trimStart()
66+
// Then, trim "use strict" directive.
67+
const useStrict = /^(['"])use strict\1/.exec(trimmed)?.[0] ?? ''
68+
trimmed = trimmed.slice(useStrict.length).trimStart()
69+
// Add back hashbang and add "use strict" directive.
70+
const modded = `${hashbang}${os.EOL}${useStrict ?? "'use strict'"}${os.EOL}${trimmed}`
71+
await fs.writeFile(p, modded, 'utf8')
6572
})
6673
)
6774
}
6875

69-
async function copyInitGradle() {
70-
const filepath = path.join(rootSrcPath, 'commands/manifest/init.gradle')
71-
const destPath = path.join(rootDistPath, 'init.gradle')
72-
await fs.copyFile(filepath, destPath)
73-
}
74-
7576
let _sentryManifest
7677
async function getSentryManifest() {
7778
if (_sentryManifest === undefined) {
@@ -215,9 +216,93 @@ export default () =>
215216
async writeBundle() {
216217
await Promise.all([
217218
copyInitGradle(),
218-
// copyBlessedWidgets(),
219+
// copyPackage('@socketsecurity/registry'),
220+
copyPackage('blessed'),
221+
copyPackage('blessed-contrib'),
219222
updatePackageJson()
220223
])
224+
225+
const blessedDestPath = path.join(rootDistPath, 'blessed')
226+
const blessedIgnore = [
227+
'lib/**',
228+
'node_modules/**',
229+
'usr/**',
230+
'vendor/**',
231+
'LICENSE*'
232+
]
233+
234+
const blessedContribDestPath = path.join(
235+
rootDistPath,
236+
'blessed-contrib'
237+
)
238+
const blessedContribIgnore = ['lib/**', 'node_modules/**', 'LICENSE*']
239+
240+
// Remove directories.
241+
await Promise.all([
242+
// Remove directories from 'blessed'.
243+
...(
244+
await tinyGlob(['**/*'], {
245+
absolute: true,
246+
onlyDirectories: true,
247+
cwd: blessedDestPath,
248+
dot: true,
249+
ignore: blessedIgnore
250+
})
251+
).map(p => remove(p)),
252+
// Remove directories from 'contrib'.
253+
...(
254+
await tinyGlob(['**/*'], {
255+
absolute: true,
256+
onlyDirectories: true,
257+
cwd: blessedContribDestPath,
258+
dot: true,
259+
ignore: blessedContribIgnore
260+
})
261+
).map(p => remove(p))
262+
])
263+
264+
// Remove files.
265+
await Promise.all([
266+
// Remove files from 'blessed'.
267+
...(
268+
await tinyGlob(['**/*'], {
269+
absolute: true,
270+
cwd: blessedDestPath,
271+
dot: true,
272+
ignore: blessedIgnore
273+
})
274+
).map(p => remove(p)),
275+
// Remove files from 'blessed-contrib'.
276+
...(
277+
await tinyGlob(['**/*'], {
278+
absolute: true,
279+
cwd: blessedContribDestPath,
280+
dot: true,
281+
ignore: blessedContribIgnore
282+
})
283+
).map(p => remove(p))
284+
])
285+
286+
await Promise.all([])
287+
// Rewire 'blessed' inside 'blessed-contrib'.
288+
await Promise.all([
289+
...(
290+
await tinyGlob(['**/*.js'], {
291+
absolute: true,
292+
cwd: blessedContribDestPath,
293+
ignore: ['node_modules/**']
294+
})
295+
).map(async p => {
296+
const relPath = path.relative(path.dirname(p), blessedDestPath)
297+
const content = await fs.readFile(p, 'utf8')
298+
const modded = content.replace(
299+
/(?<=require\(["'])blessed(?=(?:\/[^"']+)?["']\))/g,
300+
() => relPath
301+
)
302+
await fs.writeFile(p, modded, 'utf8')
303+
})
304+
])
305+
221306
// Update package-lock.json AFTER package.json.
222307
await updatePackageLockFile()
223308
}

0 commit comments

Comments
 (0)