mirror of
https://github.com/pnpm/pnpm.git
synced 2026-02-26 12:07:17 -05:00
84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
import { type CommentSpecifier } from './CommentSpecifier'
|
|
|
|
export function insertComments (json: string, comments: CommentSpecifier[]): string {
|
|
// We need to reintroduce the comments. So create an index of
|
|
// the lines of the manifest so we can try to match them up.
|
|
// We eliminate whitespace and quotes in the index entries,
|
|
// because pnpm may have changed them.
|
|
const jsonLines = json.split('\n')
|
|
const index: Record<string, number> = {}
|
|
const canonicalizer = /[\s'"]/g
|
|
for (let i = 0; i < jsonLines.length; ++i) {
|
|
const key = jsonLines[i].replace(canonicalizer, '')
|
|
if (key in index) {
|
|
index[key] = -1 // Mark this line as occurring twice
|
|
} else {
|
|
index[key] = i
|
|
}
|
|
}
|
|
|
|
// A place to put comments that come _before_ the lines they are
|
|
// anchored to:
|
|
const jsonPrefix: Record<string, string> = {}
|
|
for (const comment of comments) {
|
|
// First if we can find the line the comment was on, that is
|
|
// the most reliable locator:
|
|
let key = comment.on.replace(canonicalizer, '')
|
|
if (key && index[key] !== undefined && index[key] >= 0) {
|
|
jsonLines[index[key]] += ' ' + comment.content
|
|
continue
|
|
}
|
|
// Next, if it's not before anything, it must have been at the very end:
|
|
if (comment.before === undefined) {
|
|
jsonLines[jsonLines.length - 1] += comment.whitespace + comment.content
|
|
continue
|
|
}
|
|
// Next, try to put it before something; note the comment extractor
|
|
// used the convention that position 0 is before the first line:
|
|
let location = (comment.lineNumber === 0) ? 0 : -1
|
|
if (location < 0) {
|
|
key = comment.before.replace(canonicalizer, '')
|
|
if (key && index[key] !== undefined) {
|
|
location = index[key]
|
|
}
|
|
}
|
|
if (location >= 0) {
|
|
if (jsonPrefix[location]) {
|
|
jsonPrefix[location] += ' ' + comment.content
|
|
} else {
|
|
const inlineWhitespace = comment.whitespace.startsWith('\n')
|
|
? comment.whitespace.slice(1)
|
|
: comment.whitespace
|
|
jsonPrefix[location] = inlineWhitespace + comment.content
|
|
}
|
|
continue
|
|
}
|
|
// The last definite indicator we can use is that it is after something:
|
|
if (comment.after) {
|
|
key = comment.after.replace(canonicalizer, '')
|
|
if (key && index[key] !== undefined && index[key] >= 0) {
|
|
jsonLines[index[key]] += comment.whitespace + comment.content
|
|
continue
|
|
}
|
|
}
|
|
// Finally, try to get it in the right general location by using the
|
|
// line number, but warn the user the comment may have been relocated:
|
|
location = comment.lineNumber - 1 // 0 was handled above
|
|
let separator = ' '
|
|
if (location >= jsonLines.length) {
|
|
location = jsonLines.length - 1
|
|
separator = '\n'
|
|
}
|
|
jsonLines[location] += separator + comment.content +
|
|
' /* [comment possibly relocated by pnpm] */'
|
|
}
|
|
// Insert the accumulated prefixes:
|
|
for (let i = 0; i < jsonLines.length; ++i) {
|
|
if (jsonPrefix[i]) {
|
|
jsonLines[i] = jsonPrefix[i] + '\n' + jsonLines[i]
|
|
}
|
|
}
|
|
// And reassemble the manifest:
|
|
return jsonLines.join('\n')
|
|
}
|