electron-link/lib/generate-snapshot-script.js
dependabot[bot] 5c38cb0a84
Bump indent-string from 4.0.0 to 5.0.0 (#5)
* Bump indent-string from 4.0.0 to 5.0.0

Bumps [indent-string](https://github.com/sindresorhus/indent-string) from 4.0.0 to 5.0.0.
- [Release notes](https://github.com/sindresorhus/indent-string/releases)
- [Commits](https://github.com/sindresorhus/indent-string/compare/v4.0.0...v5.0.0)

---
updated-dependencies:
- dependency-name: indent-string
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix indent-string v5 ESM compatibility

indent-string v5 is ESM-only with a default export. Use a top-level
dynamic import() promise and destructure .default inside the async
function to avoid require() incompatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Philip Peterson <1326208+philip-peterson@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 02:12:00 -07:00

151 lines
6.5 KiB
JavaScript

'use strict'
const fs = require('fs')
const path = require('path')
const FileRequireTransform = require('./file-require-transform')
const indentStringImport = import('indent-string')
const {SourceMapGenerator} = require('source-map')
module.exports = async function (cache, options) {
const {default: indentString} = await indentStringImport
// Phase 1: Starting at the main module, traverse all requires, transforming
// all module references to paths relative to the base directory path and
// collecting abstract syntax trees for use in generating the script in
// phase 2.
const moduleASTs = {}
const requiredModulePaths = [options.mainPath]
const includedFilePaths = new Set(requiredModulePaths)
while (requiredModulePaths.length > 0) {
const filePath = requiredModulePaths.shift()
let relativeFilePath = path.relative(options.baseDirPath, filePath).replace(/\\/g, '/')
if (!relativeFilePath.startsWith('.')) {
relativeFilePath = './' + relativeFilePath
}
if (!moduleASTs[relativeFilePath]) {
const source = fs.readFileSync(filePath, 'utf8')
let foundRequires = []
const transform = new FileRequireTransform({
filePath,
source,
baseDirPath: options.baseDirPath,
didFindRequire: (unresolvedPath, resolvedPath) => {
if (options.shouldExcludeModule({requiringModulePath: filePath, requiredModulePath: resolvedPath})) {
return true
} else {
foundRequires.push({unresolvedPath, resolvedPath})
return false
}
}
})
const cachedTransform = await cache.get({filePath, content: source})
const useCachedTransform =
cachedTransform ?
cachedTransform.requires.every(r => (transform.resolveModulePath(r.unresolvedPath) || r.unresolvedPath) === r.resolvedPath) :
false
let transformedSource, requires
if (useCachedTransform) {
transformedSource = cachedTransform.source
foundRequires = cachedTransform.requires
} else {
try {
transformedSource = indentString(transform.apply(), 2)
} catch (e) {
console.error(`Unable to transform source code for module ${filePath}.`)
if (e.index) {
const before = source.slice(e.index - 100, e.index)
const after = source.slice(e.index, e.index + 100)
console.error(`\n${before}==>${after}\n`)
}
throw e
}
await cache.put({filePath, original: source, transformed: transformedSource, requires: foundRequires})
}
moduleASTs[relativeFilePath] = `function (exports, module, __filename, __dirname, require, define) {\n${transformedSource}\n}`
const resolvedRequirePaths = foundRequires.map(r => r.resolvedPath)
for (let i = 0; i < foundRequires.length; i++) {
const {resolvedPath} = foundRequires[i]
requiredModulePaths.push(resolvedPath)
includedFilePaths.add(resolvedPath)
}
}
}
await cache.deleteUnusedEntries()
// Phase 2: Now use the data we gathered during phase 1 to build a snapshot
// script based on `./blueprint.js`.
let snapshotScript = fs.readFileSync(path.join(__dirname, 'blueprint.js'), 'utf8')
// Replace `require(main)` with a require of the relativized main module path.
let relativeFilePath = path.relative(options.baseDirPath, options.mainPath).replace(/\\/g, '/')
if (!relativeFilePath.startsWith('.')) {
relativeFilePath = './' + relativeFilePath
}
snapshotScript = snapshotScript.replace('mainModuleRequirePath', JSON.stringify(relativeFilePath))
// Assign the current platform to `process.platform` so that it can be used
// even while creating the snapshot.
snapshotScript = snapshotScript.replace('processPlatform', process.platform)
// Assign the current platform's path separator so that custom require works
// correctly on both Windows and Unix systems.
snapshotScript = snapshotScript.replace('const pathSeparator = null', `const pathSeparator = ${JSON.stringify(path.sep)}`)
const auxiliaryData = JSON.stringify(options.auxiliaryData || {})
const auxiliaryDataAssignment = 'var snapshotAuxiliaryData = {}'
const auxiliaryDataAssignmentStartIndex = snapshotScript.indexOf(auxiliaryDataAssignment)
const auxiliaryDataAssignmentEndIndex = auxiliaryDataAssignmentStartIndex + auxiliaryDataAssignment.length
snapshotScript =
snapshotScript.slice(0, auxiliaryDataAssignmentStartIndex) +
`var snapshotAuxiliaryData = ${auxiliaryData};` +
snapshotScript.slice(auxiliaryDataAssignmentEndIndex)
// Replace `require.definitions = {}` with an assignment of the actual definitions
// of all the modules.
const definitionsAssignment = 'customRequire.definitions = {}'
const definitionsAssignmentStartIndex = snapshotScript.indexOf(definitionsAssignment)
const definitionsAssignmentEndIndex = definitionsAssignmentStartIndex + definitionsAssignment.length
const sections = []
let sectionStartRow = getLineCount(snapshotScript.slice(0, definitionsAssignmentStartIndex)) + 1
let definitions = ''
const moduleFilePaths = Object.keys(moduleASTs)
for (let i = 0; i < moduleFilePaths.length; i++) {
const relativePath = moduleFilePaths[i]
const source = moduleASTs[relativePath]
const lineCount = getLineCount(source)
sections.push({relativePath, startRow: sectionStartRow, endRow: (sectionStartRow + lineCount) - 2})
definitions += indentString(`${JSON.stringify(relativePath)}: ${source}`, 4) + ',\n'
sectionStartRow += lineCount
}
snapshotScript =
snapshotScript.slice(0, definitionsAssignmentStartIndex) +
`customRequire.definitions = {\n${definitions}\n };` +
snapshotScript.slice(definitionsAssignmentEndIndex)
// The following code to generate metadata to map line numbers in the snapshot
// must remain at the end of this function to ensure all the embedded code is
// accounted for.
const sectionsAssignment = 'snapshotAuxiliaryData.snapshotSections = []'
const sectionsAssignmentStartIndex = snapshotScript.indexOf(sectionsAssignment)
const sectionsAssignmentEndIndex = sectionsAssignmentStartIndex + sectionsAssignment.length
snapshotScript =
snapshotScript.slice(0, sectionsAssignmentStartIndex) +
`snapshotAuxiliaryData.snapshotSections = ${JSON.stringify(sections)}` +
snapshotScript.slice(sectionsAssignmentEndIndex)
return {snapshotScript, includedFilePaths}
}
function getLineCount (text) {
let lineCount = 1
for (let i = 0; i < text.length; i++) {
if (text[i] === '\n') lineCount++
}
return lineCount
}