* Builds the WIQL query for the configured work-item filters. User-supplied * values are escaped against WIQL string-literal injection. `lastSyncAt` * narrows results to items changed since the previous sync, and `idAfter` * restricts to items with a greater id (used to probe past the 20,000-item
(filters: WorkItemFilters, lastSyncAt?: Date, idAfter?: number)
| 539 | * detection still short-circuits unchanged items via the content hash. |
| 540 | */ |
| 541 | function buildWiql(filters: WorkItemFilters, lastSyncAt?: Date, idAfter?: number): string { |
| 542 | if (filters.customWiql) return filters.customWiql |
| 543 | |
| 544 | const clauses: string[] = ['[System.TeamProject] = @project'] |
| 545 | if (filters.workItemType) { |
| 546 | clauses.push(`[System.WorkItemType] = '${escapeWiql(filters.workItemType)}'`) |
| 547 | } |
| 548 | if (filters.state) { |
| 549 | clauses.push(`[System.State] = '${escapeWiql(filters.state)}'`) |
| 550 | } |
| 551 | if (filters.areaPath) { |
| 552 | clauses.push(`[System.AreaPath] UNDER '${escapeWiql(filters.areaPath)}'`) |
| 553 | } |
| 554 | for (const tag of filters.tags) { |
| 555 | clauses.push(`[System.Tags] CONTAINS '${escapeWiql(tag)}'`) |
| 556 | } |
| 557 | if (lastSyncAt) { |
| 558 | clauses.push(`[System.ChangedDate] >= '${lastSyncAt.toISOString()}'`) |
| 559 | } |
| 560 | if (idAfter !== undefined) { |
| 561 | clauses.push(`[System.Id] > ${idAfter}`) |
| 562 | } |
| 563 | |
| 564 | return `SELECT [System.Id] FROM workitems WHERE ${clauses.join(' AND ')} ORDER BY [System.ChangedDate] DESC` |
| 565 | } |
| 566 | |
| 567 | /** |
| 568 | * Runs a WIQL query for work items in the project and returns their IDs. |
no test coverage detected