refactor: misc. clean ups (removing unnecessary comments, improving variable names)

This commit is contained in:
Johann Schopplich
2025-11-10 13:19:33 +01:00
parent 5873c5828f
commit ac17a8d260
8 changed files with 74 additions and 75 deletions

View File

@@ -18,9 +18,6 @@ export interface ObjectWithQuotedKeys extends JsonObject {
[QUOTED_KEY_MARKER]?: Set<string>
}
/**
* Checks if two values can be merged (both are plain objects).
*/
function canMerge(a: JsonValue, b: JsonValue): a is JsonObject {
return isJsonObject(a) && isJsonObject(b)
}
@@ -140,13 +137,13 @@ function insertPathSafe(
// Walk to the penultimate segment, creating objects as needed
for (let i = 0; i < segments.length - 1; i++) {
const seg = segments[i]!
const segmentValue = currentNode[seg]
const currentSegment = segments[i]!
const segmentValue = currentNode[currentSegment]
if (segmentValue === undefined) {
// Create new intermediate object
const newObj: JsonObject = {}
currentNode[seg] = newObj
currentNode[currentSegment] = newObj
currentNode = newObj
}
else if (isJsonObject(segmentValue)) {
@@ -157,12 +154,12 @@ function insertPathSafe(
// Conflict: existing value is not an object
if (strict) {
throw new TypeError(
`Path expansion conflict at segment "${seg}": expected object but found ${typeof segmentValue}`,
`Path expansion conflict at segment "${currentSegment}": expected object but found ${typeof segmentValue}`,
)
}
// Non-strict: overwrite with new object
const newObj: JsonObject = {}
currentNode[seg] = newObj
currentNode[currentSegment] = newObj
currentNode = newObj
}
}

View File

@@ -144,6 +144,15 @@ export function parseBracketSegment(
// #region Delimited value parsing
/**
* Parses a delimited string into values, respecting quoted strings and escape sequences.
*
* @remarks
* Uses a state machine that tracks:
* - `inQuotes`: Whether we're inside a quoted string (to ignore delimiters)
* - `valueBuffer`: Accumulates characters for the current value
* - Escape sequences: Handled within quoted strings
*/
export function parseDelimitedValues(input: string, delimiter: Delimiter): string[] {
const values: string[] = []
let valueBuffer = ''
@@ -252,22 +261,22 @@ export function parseStringLiteral(token: string): string {
}
export function parseUnquotedKey(content: string, start: number): { key: string, end: number } {
let end = start
while (end < content.length && content[end] !== COLON) {
end++
let parsePosition = start
while (parsePosition < content.length && content[parsePosition] !== COLON) {
parsePosition++
}
// Validate that a colon was found
if (end >= content.length || content[end] !== COLON) {
if (parsePosition >= content.length || content[parsePosition] !== COLON) {
throw new SyntaxError('Missing colon after key')
}
const key = content.slice(start, end).trim()
const key = content.slice(start, parsePosition).trim()
// Skip the colon
end++
parsePosition++
return { key, end }
return { key, end: parsePosition }
}
export function parseQuotedKey(content: string, start: number): { key: string, end: number } {
@@ -281,15 +290,15 @@ export function parseQuotedKey(content: string, start: number): { key: string, e
// Extract and unescape the key content
const keyContent = content.slice(start + 1, closingQuoteIndex)
const key = unescapeString(keyContent)
let end = closingQuoteIndex + 1
let parsePosition = closingQuoteIndex + 1
// Validate and skip colon after quoted key
if (end >= content.length || content[end] !== COLON) {
if (parsePosition >= content.length || content[parsePosition] !== COLON) {
throw new SyntaxError('Missing colon after key')
}
end++
parsePosition++
return { key, end }
return { key, end: parsePosition }
}
export function parseKeyToken(content: string, start: number): { key: string, end: number, isQuoted: boolean } {

View File

@@ -92,13 +92,13 @@ export function toParsedLines(source: string, indentSize: number, strict: boolea
// Strict mode validation
if (strict) {
// Find the full leading whitespace region (spaces and tabs)
let wsEnd = 0
while (wsEnd < raw.length && (raw[wsEnd] === SPACE || raw[wsEnd] === TAB)) {
wsEnd++
let whitespaceEndIndex = 0
while (whitespaceEndIndex < raw.length && (raw[whitespaceEndIndex] === SPACE || raw[whitespaceEndIndex] === TAB)) {
whitespaceEndIndex++
}
// Check for tabs in leading whitespace (before actual content)
if (raw.slice(0, wsEnd).includes(TAB)) {
if (raw.slice(0, whitespaceEndIndex).includes(TAB)) {
throw new SyntaxError(`Line ${lineNumber}: Tabs are not allowed in indentation in strict mode`)
}

View File

@@ -4,12 +4,6 @@ import { COLON, LIST_ITEM_PREFIX } from '../constants'
/**
* Asserts that the actual count matches the expected count in strict mode.
*
* @param actual The actual count
* @param expected The expected count
* @param itemType The type of items being counted (e.g., `list array items`, `tabular rows`)
* @param options Decode options
* @throws RangeError if counts don't match in strict mode
*/
export function assertExpectedCount(
actual: number,
@@ -24,11 +18,6 @@ export function assertExpectedCount(
/**
* Validates that there are no extra list items beyond the expected count.
*
* @param cursor The line cursor
* @param itemDepth The expected depth of items
* @param expectedCount The expected number of items
* @throws RangeError if extra items are found
*/
export function validateNoExtraListItems(
cursor: LineCursor,
@@ -46,11 +35,6 @@ export function validateNoExtraListItems(
/**
* Validates that there are no extra tabular rows beyond the expected count.
*
* @param cursor The line cursor
* @param rowDepth The expected depth of rows
* @param header The array header info containing length and delimiter
* @throws RangeError if extra rows are found
*/
export function validateNoExtraTabularRows(
cursor: LineCursor,
@@ -72,17 +56,7 @@ export function validateNoExtraTabularRows(
}
/**
* Validates that there are no blank lines within a specific line range and depth.
*
* @remarks
* In strict mode, blank lines inside arrays/tabular rows are not allowed.
*
* @param startLine The starting line number (inclusive)
* @param endLine The ending line number (inclusive)
* @param blankLines Array of blank line information
* @param strict Whether strict mode is enabled
* @param context Description of the context (e.g., "list array", "tabular array")
* @throws SyntaxError if blank lines are found in strict mode
* Validates that there are no blank lines within a specific line range in strict mode.
*/
export function validateNoBlankLinesInRange(
startLine: number,
@@ -110,11 +84,7 @@ export function validateNoBlankLinesInRange(
}
/**
* Checks if a line represents a data row (as opposed to a key-value pair) in a tabular array.
*
* @param content The line content
* @param delimiter The delimiter used in the table
* @returns true if the line is a data row, false if it's a key-value pair
* Checks if a line is a data row (vs a key-value pair) in a tabular array.
*/
function isDataRow(content: string, delimiter: Delimiter): boolean {
const colonPos = content.indexOf(COLON)

View File

@@ -138,6 +138,8 @@ function collectSingleKeyChain(
const segments: string[] = [startKey]
let currentValue = startValue
// Traverse nested single-key objects, collecting each key into segments array
// Stop when we encounter: multi-key object, array, primitive, or depth limit
while (segments.length < maxDepth) {
// Must be an object to continue
if (!isJsonObject(currentValue)) {
@@ -180,12 +182,6 @@ function collectSingleKeyChain(
return { segments, tail: currentValue, leafValue: currentValue }
}
/**
* Builds a folded key from segments.
*
* @param segments - Array of key segments
* @returns Dot-separated key string
*/
function buildFoldedKey(segments: readonly string[]): string {
return segments.join(DOT)
}

View File

@@ -20,12 +20,51 @@ export type {
ResolvedEncodeOptions,
} from './types'
/**
* Encodes a JavaScript value into TOON format string.
*
* @param input - Any JavaScript value (objects, arrays, primitives)
* @param options - Optional encoding configuration
* @returns TOON formatted string
*
* @example
* ```ts
* encode({ name: 'Alice', age: 30 })
* // name: Alice
* // age: 30
*
* encode({ users: [{ id: 1 }, { id: 2 }] })
* // users[]:
* // - id: 1
* // - id: 2
*
* encode(data, { indent: 4, keyFolding: 'safe' })
* ```
*/
export function encode(input: unknown, options?: EncodeOptions): string {
const normalizedValue = normalizeValue(input)
const resolvedOptions = resolveOptions(options)
return encodeValue(normalizedValue, resolvedOptions)
}
/**
* Decodes a TOON format string into a JavaScript value.
*
* @param input - TOON formatted string
* @param options - Optional decoding configuration
* @returns Parsed JavaScript value (object, array, or primitive)
*
* @example
* ```ts
* decode('name: Alice\nage: 30')
* // { name: 'Alice', age: 30 }
*
* decode('users[]:\n - id: 1\n - id: 2')
* // { users: [{ id: 1 }, { id: 2 }] }
*
* decode(toonString, { strict: false, expandPaths: 'safe' })
* ```
*/
export function decode(input: string, options?: DecodeOptions): JsonValue {
const resolvedOptions = resolveDecodeOptions(options)
const scanResult = toParsedLines(input, resolvedOptions.indent, resolvedOptions.strict)

View File

@@ -1,8 +1,5 @@
import { FALSE_LITERAL, NULL_LITERAL, TRUE_LITERAL } from '../constants'
/**
* Checks if a token is a boolean or null literal (`true`, `false`, `null`).
*/
export function isBooleanOrNullLiteral(token: string): boolean {
return token === TRUE_LITERAL || token === FALSE_LITERAL || token === NULL_LITERAL
}

View File

@@ -69,11 +69,7 @@ export function unescapeString(value: string): string {
}
/**
* Finds the index of the closing double quote in a string, accounting for escape sequences.
*
* @param content The string to search in
* @param start The index of the opening quote
* @returns The index of the closing quote, or -1 if not found
* Finds the index of the closing double quote, accounting for escape sequences.
*/
export function findClosingQuote(content: string, start: number): number {
let i = start + 1
@@ -92,12 +88,7 @@ export function findClosingQuote(content: string, start: number): number {
}
/**
* Finds the index of a specific character outside of quoted sections.
*
* @param content The string to search in
* @param char The character to look for
* @param start Optional starting index (defaults to 0)
* @returns The index of the character, or -1 if not found outside quotes
* Finds the index of a character outside of quoted sections.
*/
export function findUnquotedChar(content: string, char: string, start = 0): number {
let inQuotes = false