Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions packages/spec-dashboard/src/apis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,4 +286,70 @@ describe("splitManifestByTables", () => {
const dataPlaneTable = result.find((r) => r.tableName === "Data Plane Table");
expect(dataPlaneTable!.emitterNames).toEqual(["@azure-tools/typespec-csharp"]);
});

it("should preserve order of tableDefinitions in the result", () => {
const manifest = createManifest("test-package", "Display Name", [
"prefix1_scenario1",
"prefix2_scenario1",
"prefix3_scenario1",
]);
const tables: TableDefinition[] = [
{
name: "Third Table",
packageName: "test-package",
prefixes: ["prefix3_"],
},
{
name: "First Table",
packageName: "test-package",
prefixes: ["prefix1_"],
},
{
name: "Second Table",
packageName: "test-package",
prefixes: ["prefix2_"],
},
];

const result = splitManifestByTables(manifest, tables);

expect(result).toHaveLength(3);
// Results should be in the same order as tableDefinitions
expect(result[0].tableName).toBe("Third Table");
expect(result[1].tableName).toBe("First Table");
expect(result[2].tableName).toBe("Second Table");
});

it("should preserve order when mixing tables with prefixes and catch-all tables", () => {
const manifest = createManifest("test-package", "Display Name", [
"prefix1_scenario1",
"prefix2_scenario1",
"other_scenario",
]);
const tables: TableDefinition[] = [
{
name: "Second Table (Prefix2)",
packageName: "test-package",
prefixes: ["prefix2_"],
},
{
name: "First Table (Catch-All)",
packageName: "test-package",
// No prefixes - catch-all table
},
{
name: "Third Table (Prefix1)",
packageName: "test-package",
prefixes: ["prefix1_"],
},
];

const result = splitManifestByTables(manifest, tables);

expect(result).toHaveLength(3);
// Results should be in the same order as tableDefinitions, not grouped by type
expect(result[0].tableName).toBe("Second Table (Prefix2)");
expect(result[1].tableName).toBe("First Table (Catch-All)");
expect(result[2].tableName).toBe("Third Table (Prefix1)");
});
});
61 changes: 29 additions & 32 deletions packages/spec-dashboard/src/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,49 +88,46 @@ export function splitManifestByTables(
[];
const usedScenarios = new Set<string>();

// Separate tables with prefixes from catch-all tables (no prefixes)
const tablesWithPrefixes = applicableTables.filter((t) => t.prefixes && t.prefixes.length > 0);
const catchAllTables = applicableTables.filter((t) => !t.prefixes || t.prefixes.length === 0);

// Process tables with prefixes first
for (const table of tablesWithPrefixes) {
// Filter scenarios by prefixes
const filteredScenarios = manifest.scenarios.filter((s: ScenarioData) => {
if (usedScenarios.has(s.name)) {
return false; // Already assigned to another table
// First, identify which scenarios would match ANY prefix table (to reserve them from catch-all tables)
const scenariosMatchingAnyPrefix = new Set<string>();
for (const table of applicableTables) {
if (table.prefixes && table.prefixes.length > 0) {
for (const scenario of manifest.scenarios) {
if (matchesPrefixes(scenario.name, table.prefixes)) {
scenariosMatchingAnyPrefix.add(scenario.name);
}
}
return matchesPrefixes(s.name, table.prefixes!);
});
}
}

if (filteredScenarios.length > 0) {
// Mark these scenarios as used
filteredScenarios.forEach((s) => usedScenarios.add(s.name));
// Now process tables in the order they appear in tableDefinitions
for (const table of applicableTables) {
const isCatchAll = !table.prefixes || table.prefixes.length === 0;

result.push({
manifest: {
...manifest,
scenarios: filteredScenarios,
},
tableName: table.name,
emitterNames: table.emitterNames,
let matchingScenarios: ScenarioData[];
if (isCatchAll) {
// Catch-all table: only get scenarios not yet assigned AND not matching any prefix
matchingScenarios = manifest.scenarios.filter(
(s: ScenarioData) => !usedScenarios.has(s.name) && !scenariosMatchingAnyPrefix.has(s.name),
);
} else {
// Table with prefixes: filter scenarios by prefixes
matchingScenarios = manifest.scenarios.filter((s: ScenarioData) => {
if (usedScenarios.has(s.name)) {
return false; // Already assigned to another table
}
return matchesPrefixes(s.name, table.prefixes!);
});
}
}

// Process catch-all tables - they only get scenarios not yet assigned
for (const table of catchAllTables) {
const remainingScenarios = manifest.scenarios.filter(
(s: ScenarioData) => !usedScenarios.has(s.name),
);

if (remainingScenarios.length > 0) {
if (matchingScenarios.length > 0) {
// Mark these scenarios as used
remainingScenarios.forEach((s) => usedScenarios.add(s.name));
matchingScenarios.forEach((s) => usedScenarios.add(s.name));

result.push({
manifest: {
...manifest,
scenarios: remainingScenarios,
scenarios: matchingScenarios,
},
tableName: table.name,
emitterNames: table.emitterNames,
Expand Down
Loading