Repository: microsoft/TypeScript
File: src/compiler/utilities.ts (TypeScript)

Code before:
        const ch3 = base64Digits.indexOf(input[i + 2]);
        const ch4 = base64Digits.indexOf(input[i + 3]);

        const code1 = ((ch1 & 0B00111111) << 2) | ((ch2 >> 4) & 0B00000011);
        const code2 = ((ch2 & 0B00001111) << 4) | ((ch3 >> 2) & 0B00001111);
        const code3 = ((ch3 & 0B00000011) << 6) | (ch4 & 0B00111111);

        if (code2 === 0 && ch3 !== 0) { // code2 decoded to zero, but ch3 was padding - elide code2 and code3
            expandedCharCodes.push(code1);
        }
        else if (code3 === 0 && ch4 !== 0) { // code3 decoded to zero, but ch4 was padding, elide code3
            expandedCharCodes.push(code1, code2);
        }
        else {
            expandedCharCodes.push(code1, code2, code3);
        }
        i += 4;
    }
    return getStringFromExpandedCharCodes(expandedCharCodes);
}

/** @internal */
export function readJsonOrUndefined(path: string, hostOrText: { readFile(fileName: string): string | undefined; } | string): object | undefined {
    const jsonText = isString(hostOrText) ? hostOrText : hostOrText.readFile(path);
    if (!jsonText) return undefined;
    return tryParseJson(jsonText);
}

/** @internal */
export function readJson(path: string, host: { readFile(fileName: string): string | undefined; }): object {
    return readJsonOrUndefined(path, host) || {};
}

/** @internal */
export function tryParseJson(text: string): any {
    try {
        return JSON.parse(text);
    }
    catch {
        return undefined;
    }
}

/** @internal */
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean; }): boolean {
    // if host does not support 'directoryExists' assume that directory will exist
    return !host.directoryExists || host.directoryExists(directoryName);
}

const carriageReturnLineFeed = "\r\n";
const lineFeed = "\n";

Review comment (bug):
Maybe I'm missing something, but wouldn't it be better to strictly parse, and if that fails, use our parser to report errors and work resiliently? It's better for the language service to still do _something_ right if you're in the middle of editing `package.json`.


Code after:
        const ch2 = base64Digits.indexOf(input[i + 1]);
        const ch3 = base64Digits.indexOf(input[i + 2]);
        const ch4 = base64Digits.indexOf(input[i + 3]);

        const code1 = ((ch1 & 0B00111111) << 2) | ((ch2 >> 4) & 0B00000011);
        const code2 = ((ch2 & 0B00001111) << 4) | ((ch3 >> 2) & 0B00001111);
        const code3 = ((ch3 & 0B00000011) << 6) | (ch4 & 0B00111111);

        if (code2 === 0 && ch3 !== 0) { // code2 decoded to zero, but ch3 was padding - elide code2 and code3
            expandedCharCodes.push(code1);
        }
        else if (code3 === 0 && ch4 !== 0) { // code3 decoded to zero, but ch4 was padding, elide code3
            expandedCharCodes.push(code1, code2);
        }
        else {
            expandedCharCodes.push(code1, code2, code3);
        }
        i += 4;
    }
    return getStringFromExpandedCharCodes(expandedCharCodes);
}

/** @internal */
export function readJsonOrUndefined(path: string, hostOrText: { readFile(fileName: string): string | undefined; } | string): object | undefined {
    const jsonText = isString(hostOrText) ? hostOrText : hostOrText.readFile(path);
    if (!jsonText) return undefined;
    // Try strictly parsing first, then fall back to our (slower)
    // parser that is resilient to comments/trailing commas.
    // package.json files should never have these, but we
    // have no way to communicate these issues in the first place.
    let result = tryParseJson(jsonText);
    if (result === undefined) {
        const looseResult = parseConfigFileTextToJson(path, jsonText);
        if (!looseResult.error) {
            result = looseResult.config;
        }
    }
    return result;
}

/** @internal */
export function readJson(path: string, host: { readFile(fileName: string): string | undefined; }): object {
    return readJsonOrUndefined(path, host) || {};
}

/** @internal */
export function tryParseJson(text: string): any {
    try {
        return JSON.parse(text);
    }
    catch {