mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-13 03:58:33 +00:00
fix(setup): remove dead JSON.parse fallback, detect space-indent width, fix JSDoc
- Remove the semantically unreachable JSON.parse fallback branch in mergeJsoncFile (jsonc-parser's parseTree is a strict superset of JSON.parse, so the fallback can never fire for content JSON.parse would accept) - Replace binary tab/space detection with detectIndentation() that measures actual indent width from the first indented line - Fix JSDoc: 'valid JSON that is not valid JSONC' is impossible by definition - Add tests for tab indentation and 4-space indentation preservation
This commit is contained in:
parent
3c9d24ee86
commit
f504e57275
2 changed files with 40 additions and 19 deletions
|
|
@ -128,10 +128,20 @@ async function writeJsonFile(filePath: string, data: any): Promise<void> {
|
|||
await fs.writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect indentation style from file content.
|
||||
* Returns formatting options matching the file's existing style.
|
||||
*/
|
||||
function detectIndentation(raw: string): { tabSize: number; insertSpaces: boolean } {
|
||||
const firstIndented = raw.match(/^( +|\t)/m);
|
||||
if (!firstIndented) return { tabSize: 2, insertSpaces: true };
|
||||
if (firstIndented[1] === '\t') return { tabSize: 1, insertSpaces: false };
|
||||
return { tabSize: firstIndented[1].length, insertSpaces: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a key/value pair into a JSONC config file, preserving comments and formatting.
|
||||
* Falls back to JSON.parse + writeJsonFile for valid JSON that is not valid JSONC.
|
||||
* If the file is genuinely corrupt (not valid JSON or JSONC), leaves it untouched.
|
||||
* If the file is genuinely corrupt (not valid JSONC), leaves it untouched.
|
||||
*/
|
||||
async function mergeJsoncFile(
|
||||
filePath: string,
|
||||
|
|
@ -164,29 +174,14 @@ async function mergeJsoncFile(
|
|||
const tree = parseTree(raw, parseErrors);
|
||||
|
||||
if (tree && tree.type === 'object' && parseErrors.length === 0) {
|
||||
const detectedTabs = /^\t/m.test(raw);
|
||||
const formattingOptions = detectedTabs
|
||||
? { tabSize: 1, insertSpaces: false }
|
||||
: { tabSize: 2, insertSpaces: true };
|
||||
const formattingOptions = detectIndentation(raw);
|
||||
const edits = modify(raw, keyPath, value, { formattingOptions });
|
||||
const result = applyEdits(raw, edits);
|
||||
await fs.writeFile(filePath, result, 'utf-8');
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const existing = JSON.parse(raw);
|
||||
let parent = existing;
|
||||
for (let i = 0; i < keyPath.length - 1; i++) {
|
||||
if (!parent[keyPath[i]]) parent[keyPath[i]] = {};
|
||||
parent = parent[keyPath[i]];
|
||||
}
|
||||
parent[keyPath[keyPath.length - 1]] = value;
|
||||
await writeJsonFile(filePath, existing);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -236,6 +236,32 @@ describe('setupOpenCode — JSONC preservation', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('preserves tab indentation in existing file', async () => {
|
||||
const tabbed = `{\n\t"model": "test"\n}`;
|
||||
await fs.writeFile(opencodeJsonPath(), tabbed, 'utf-8');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(opencodeJsonPath(), 'utf-8');
|
||||
expect(raw).toContain('\t"model"');
|
||||
expect(raw).toContain('\t"gitnexus"');
|
||||
});
|
||||
|
||||
it('preserves 4-space indentation in existing file', async () => {
|
||||
const fourSpace = `{
|
||||
"model": "test"
|
||||
}`;
|
||||
await fs.writeFile(opencodeJsonPath(), fourSpace, 'utf-8');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(opencodeJsonPath(), 'utf-8');
|
||||
const mcpLine = raw.split('\n').find((l) => l.includes('"gitnexus"'));
|
||||
expect(mcpLine).toMatch(/^ /);
|
||||
});
|
||||
|
||||
it('skips when ~/.config/opencode directory does not exist', async () => {
|
||||
await fs.rm(opencodeDir(), { recursive: true, force: true });
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue