fix(mongodb): accept trailing commas in shell arguments

This commit is contained in:
Guoyu Su
2026-07-25 08:47:06 +08:00
committed by GitHub
parent 98d1ab3ab3
commit d341581ff0
2 changed files with 98 additions and 1 deletions
+63
View File
@@ -534,6 +534,69 @@ test("parseMongoAggregateCommand accepts an empty pipeline", () => {
});
});
test("parseMongoAggregateCommand accepts Mongo Shell trailing commas", () => {
const command = parseMongoAggregateCommand(`db.AdressInfo.aggregate([
{
$match: {
IsDelete: 0,
DataSource: { $ne: 'XC' },
TypeName: 1,
},
},
{
$project: {
MainId: '$_id',
labels: ['primary', 'backup',],
},
},
{ $out: 'IBMBiititle' },
], {
allowDiskUse: true,
})`);
assert.ok(command);
assert.deepEqual(JSON.parse(command.pipeline), [
{
$match: {
IsDelete: 0,
DataSource: { $ne: "XC" },
TypeName: 1,
},
},
{
$project: {
MainId: "$_id",
labels: ["primary", "backup"],
},
},
{ $out: "IBMBiititle" },
]);
assert.deepEqual(JSON.parse(command.options ?? "null"), { allowDiskUse: true });
});
test("parseMongoAggregateCommand preserves trailing-comma text inside strings", () => {
const command = parseMongoAggregateCommand(`db.logs.aggregate([
{
$project: {
objectText: "literal,}",
arrayText: "literal,]",
escapedQuote: "literal\\",]",
},
},
])`);
assert.ok(command);
assert.deepEqual(JSON.parse(command.pipeline), [
{
$project: {
objectText: "literal,}",
arrayText: "literal,]",
escapedQuote: 'literal",]',
},
},
]);
});
test("parseMongoAggregateCommand ignores comments inside aggregate pipelines", () => {
const command = parseMongoAggregateCommand(`
db.cash.aggregate([
+35 -1
View File
@@ -241,6 +241,39 @@ function mongoLineCommentEnd(source: string, start: number): number {
return source.length;
}
function removeTrailingCommas(source: string): string {
let result = "";
let inString = false;
let escaped = false;
for (let index = 0; index < source.length; index += 1) {
const char = source[index] ?? "";
if (inString) {
result += char;
if (escaped) escaped = false;
else if (char === "\\") escaped = true;
else if (char === '"') inString = false;
continue;
}
if (char === '"') {
inString = true;
result += char;
continue;
}
if (char === ",") {
let next = index + 1;
while (/\s/.test(source[next] ?? "")) next += 1;
if (source[next] === "}" || source[next] === "]") continue;
}
result += char;
}
return result;
}
export function quoteUnquotedObjectKeys(source: string): string {
let result = "";
let quote: string | null = null;
@@ -407,5 +440,6 @@ function convertSingleQuotedStrings(source: string): string {
}
}
return quote === "'" ? source : result + source.slice(copiedUntil);
const converted = quote === "'" ? source : result + source.slice(copiedUntil);
return removeTrailingCommas(converted);
}