mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(ui): read TOML arrays that run over several lines in the outline
The outline of django's pyproject.toml showed "dependencies [; authors [". An array or inline table that runs over several lines is now read to its end, and its items are split at its own commas only, so an inline table such as an author stays one item. Signed-off-by: Bernhard Jackiewicz <bj@techport.io>
This commit is contained in:
1 parent
baf10f945e
commit
be62214ca3
2 files changed
+72
-6
No files matched your search
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { fileOutline } from './file-outline';
|
||||
|
||||
/** django's pyproject.toml, its first table and the start of [project]. */
|
||||
const PYPROJECT = `[build-system]
|
||||
requires = ["setuptools>=75.8.1"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "Django"
|
||||
requires-python = ">= 3.10"
|
||||
dependencies = [
|
||||
"asgiref>=3.8.1",
|
||||
"sqlparse>=0.3.1",
|
||||
"tzdata; sys_platform == 'win32'",
|
||||
]
|
||||
authors = [
|
||||
{name = "Django Software Foundation", email = "foundation@djangoproject.com"},
|
||||
]
|
||||
license = {text = "BSD-3-Clause"}
|
||||
`;
|
||||
|
||||
/** "was macht diese datei?" on pyproject.toml showed "dependencies [; authors [" for arrays over several lines. */
|
||||
describe('TOML arrays over several lines in the outline', () => {
|
||||
it('lists the items of a multi-line array, and keeps commas inside an inline table', () => {
|
||||
const outline = fileOutline('pyproject.toml', PYPROJECT, 'en')!;
|
||||
expect(outline).toContain('- `[project]`: name `Django`; requires-python `>= 3.10`; dependencies: `asgiref>=3.8.1`, `sqlparse>=0.3.1`, `tzdata; sys_platform == \'win32\'`; '
|
||||
+ 'authors: `{name = "Django Software Foundation", email = "foundation@djangoproject.com"}`; license `{text = "BSD-3-Clause"}`');
|
||||
expect(outline).not.toMatch(/dependencies \[|authors \[/);
|
||||
expect(outline).toContain('- `[build-system]`: requires: `setuptools>=75.8.1`; build-backend `setuptools.build_meta`');
|
||||
});
|
||||
});
|
||||
@@ -29,17 +29,48 @@ function jsonValue(value: unknown): YamlValue {
|
||||
return { kind: 'scalar', value: String(value) };
|
||||
}
|
||||
|
||||
/** TOML: the keys before the first table, each `[table]` with its keys, each `[[table]]` as a list item. */
|
||||
/** Brackets still open after `text`, outside strings and comments. */
|
||||
function openBrackets(text: string): number {
|
||||
let depth = 0, quote: string | undefined;
|
||||
for (let index = 0; index < text.length; index++) {
|
||||
const character = text[index];
|
||||
if (quote) { if (character === '\\' && quote === '"') index++; else if (character === quote) quote = undefined; continue; }
|
||||
if (character === '#') break;
|
||||
if (character === '"' || character === "'") quote = character;
|
||||
else if (character === '[' || character === '{') depth++;
|
||||
else if (character === ']' || character === '}') depth--;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
/** The items of an array, split at its own commas, not at those inside strings or inline tables. */
|
||||
function arrayItems(inner: string): string[] {
|
||||
const items: string[] = [];
|
||||
let depth = 0, quote: string | undefined, start = 0;
|
||||
for (let index = 0; index < inner.length; index++) {
|
||||
const character = inner[index];
|
||||
if (quote) { if (character === '\\' && quote === '"') index++; else if (character === quote) quote = undefined; continue; }
|
||||
if (character === '"' || character === "'") quote = character;
|
||||
else if (character === '[' || character === '{') depth++;
|
||||
else if (character === ']' || character === '}') depth--;
|
||||
else if (character === ',' && depth === 0) { items.push(inner.slice(start, index)); start = index + 1; }
|
||||
}
|
||||
return [...items, inner.slice(start)].map(item => item.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
/** TOML: the keys before the first table, each `[table]` with its keys, each `[[table]]` as a list
|
||||
* item. An array may run over several lines ("dependencies = [" with one item per line). */
|
||||
function tomlTree(text: string): YamlValue | undefined {
|
||||
const root: [string, YamlValue][] = [];
|
||||
let current = root, quoted: string | undefined;
|
||||
const unquote = (item: string) => item.replace(/^(["'])(.*)\1$/, '$2');
|
||||
const value = (raw: string): YamlValue => {
|
||||
const plain = raw.replace(/\s+#[^"']*$/, '').trim();
|
||||
if (/^\[.*\]$/.test(plain)) return { kind: 'list', items: plain.slice(1, -1).split(',').map(item => item.trim().replace(/^(["'])(.*)\1$/, '$2')).filter(Boolean).map(item => ({ kind: 'scalar', value: item })) };
|
||||
return { kind: 'scalar', value: plain.replace(/^(["'])(.*)\1$/, '$2') };
|
||||
if (/^\[[\s\S]*\]$/.test(plain)) return { kind: 'list', items: arrayItems(plain.slice(1, -1)).map(item => ({ kind: 'scalar', value: unquote(item) })) };
|
||||
return { kind: 'scalar', value: unquote(plain) };
|
||||
};
|
||||
for (const raw of text.split(/\r?\n/)) {
|
||||
const line = raw.trim();
|
||||
const lines = text.split(/\r?\n/);
|
||||
for (let at = 0; at < lines.length; at++) {
|
||||
const line = lines[at].trim();
|
||||
if (quoted) { if (line.split(quoted).length % 2 === 0) quoted = undefined; continue; }
|
||||
if (!line || line.startsWith('#')) continue;
|
||||
const table = /^(\[\[?)\s*([^\]]+?)\s*\]\]?\s*(?:#.*)?$/.exec(line);
|
||||
@@ -57,7 +88,10 @@ function tomlTree(text: string): YamlValue | undefined {
|
||||
if (!key) continue;
|
||||
const delimiter = ['"""', "'''"].find(mark => line.split(mark).length === 2);
|
||||
if (delimiter) quoted = delimiter;
|
||||
current.push([key[1], delimiter ? { kind: 'scalar', value: '' } : value(key[2])]);
|
||||
let raw = key[2];
|
||||
// The lines an open array or inline table runs over, without their comments.
|
||||
while (!delimiter && openBrackets(raw) > 0 && at + 1 < lines.length) raw += ` ${lines[++at].trim().replace(/\s+#[^"']*$/, '')}`;
|
||||
current.push([key[1], delimiter ? { kind: 'scalar', value: '' } : value(raw)]);
|
||||
}
|
||||
return root.length ? { kind: 'map', entries: root } : undefined;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user