( file: TFile, key: string, rawValue: string, policy: ConflictPolicy, wrapInArray: boolean, )
| 184 | } |
| 185 | |
| 186 | private async applyToFile( |
| 187 | file: TFile, |
| 188 | key: string, |
| 189 | rawValue: string, |
| 190 | policy: ConflictPolicy, |
| 191 | wrapInArray: boolean, |
| 192 | ): Promise<BulkOutcome> { |
| 193 | // Defense in depth at the write boundary: `apply` already rejects reserved |
| 194 | // keys before the loop, but `applyToFile` is reachable on its own (TS |
| 195 | // `private` is not runtime-private and `plugin.bulkEditor` is public), so |
| 196 | // fail closed here too rather than letting a reserved key reach the |
| 197 | // `frontmatter[key] = ...` assignment below. |
| 198 | this.assertWritableKey(key); |
| 199 | |
| 200 | let outcome: BulkOutcome = "skipped"; |
| 201 | |
| 202 | // Serialize through the controller's per-file write queue so this write is |
| 203 | // never lost to a concurrent controller `vault.read`+`vault.modify` edit to |
| 204 | // the same note (see the module docstring). The decision is still made |
| 205 | // against live frontmatter inside the single processFrontMatter callback. |
| 206 | await this.plugin.controller.enqueueFrontmatterWrite(file, (frontmatter: Record<string, unknown>) => { |
| 207 | const exists = Object.prototype.hasOwnProperty.call(frontmatter, key); |
| 208 | const decision = decideBulkWrite({ |
| 209 | exists, |
| 210 | currentValue: frontmatter[key], |
| 211 | rawValue, |
| 212 | policy, |
| 213 | wrapInArray, |
| 214 | }); |
| 215 | outcome = decision.outcome; |
| 216 | if (decision.action === "write") { |
| 217 | frontmatter[key] = decision.value; |
| 218 | } |
| 219 | }); |
| 220 | |
| 221 | return outcome; |
| 222 | } |
| 223 | |
| 224 | private markdownFilesIn(folder: TFolder): TFile[] { |
| 225 | const files: TFile[] = []; |
no test coverage detected