Files
pnpm/pnpm11/text/comments-parser/src/insertComments.ts
Zoltan Kochan 28814c603e refactor(ts): meet size and shape limits in 10 packages (#16440)
* refactor(ts): meet size and shape limits in 5 packages

Meet size and shape limits in modules-yaml, projects-reader,
property-path, path-extender-posix, and workspace/commands.
Graduate them from PENDING_SIZE_AND_SHAPE_REFACTOR.

* refactor(ts): meet size and shape limits in 5 more packages

Meet size and shape limits in text/comments-parser,
text/tree-renderer, yaml/document-sync,
workspace/workspace-manifest-reader, and
workspace/injected-deps-syncer.
Graduate them from PENDING_SIZE_AND_SHAPE_REFACTOR.
2026-09-30 17:04:54 +02:00

127 lines
3.5 KiB
TypeScript

import type { CommentSpecifier } from './CommentSpecifier.js'
const CANONICALIZER = /[\s'"]/g
function canonicalize (text: string): string {
return text.replace(CANONICALIZER, '')
}
export function insertComments (json: string, comments: CommentSpecifier[]): string {
const jsonLines = json.split('\n')
const index = buildLineIndex(jsonLines)
const jsonPrefix: Record<string, string> = {}
for (const comment of comments) {
placeComment(comment, jsonLines, index, jsonPrefix)
}
prependPrefixes(jsonLines, jsonPrefix)
return jsonLines.join('\n')
}
function buildLineIndex (jsonLines: string[]): Record<string, number> {
const index: Record<string, number> = {}
for (let lineIndex = 0; lineIndex < jsonLines.length; ++lineIndex) {
const key = canonicalize(jsonLines[lineIndex])
if (key in index) {
index[key] = -1
} else {
index[key] = lineIndex
}
}
return index
}
function placeComment (
comment: CommentSpecifier,
jsonLines: string[],
index: Record<string, number>,
jsonPrefix: Record<string, string>
): void {
if (tryPlaceOnLine(comment, jsonLines, index)) return
if (tryPlaceAtEnd(comment, jsonLines)) return
if (tryPlaceBefore(comment, index, jsonPrefix)) return
if (tryPlaceAfter(comment, jsonLines, index)) return
placeByLineNumber(comment, jsonLines)
}
function tryPlaceOnLine (
comment: CommentSpecifier,
jsonLines: string[],
index: Record<string, number>
): boolean {
const key = canonicalize(comment.on)
if (key && index[key] !== undefined && index[key] >= 0) {
jsonLines[index[key]] += ' ' + comment.content
return true
}
return false
}
function tryPlaceAtEnd (comment: CommentSpecifier, jsonLines: string[]): boolean {
if (comment.before === undefined) {
jsonLines[jsonLines.length - 1] += comment.whitespace + comment.content
return true
}
return false
}
function tryPlaceBefore (
comment: CommentSpecifier,
index: Record<string, number>,
jsonPrefix: Record<string, string>
): boolean {
let location = comment.lineNumber === 0 ? 0 : -1
if (location < 0) {
const key = canonicalize(comment.before!)
if (key && index[key] !== undefined) {
location = index[key]
}
}
if (location < 0) return false
if (jsonPrefix[location]) {
jsonPrefix[location] += ' ' + comment.content
} else {
const inlineWhitespace = comment.whitespace[0] === '\n'
? comment.whitespace.slice(1)
: comment.whitespace
jsonPrefix[location] = inlineWhitespace + comment.content
}
return true
}
function tryPlaceAfter (
comment: CommentSpecifier,
jsonLines: string[],
index: Record<string, number>
): boolean {
if (!comment.after) return false
const key = canonicalize(comment.after)
if (key && index[key] !== undefined && index[key] >= 0) {
jsonLines[index[key]] += comment.whitespace + comment.content
return true
}
return false
}
function placeByLineNumber (comment: CommentSpecifier, jsonLines: string[]): void {
let location = comment.lineNumber - 1
let separator = ' '
if (location >= jsonLines.length) {
location = jsonLines.length - 1
separator = '\n'
}
jsonLines[location] += separator + comment.content +
' /* [comment possibly relocated by pnpm] */'
}
function prependPrefixes (jsonLines: string[], jsonPrefix: Record<string, string>): void {
for (let lineIndex = 0; lineIndex < jsonLines.length; ++lineIndex) {
if (jsonPrefix[lineIndex]) {
jsonLines[lineIndex] = jsonPrefix[lineIndex] + '\n' + jsonLines[lineIndex]
}
}
}