|
1 | 1 | import * as githubActions from "@actions/github"; |
2 | 2 | import { downloadFirmware, generateHash } from "@zwave-js/firmware-integrity"; |
| 3 | +import { |
| 4 | + parse as parseCommentJson, |
| 5 | + stringify as stringifyCommentJson, |
| 6 | +} from "comment-json"; |
3 | 7 | import JSON5 from "json5"; |
4 | 8 | import { spawnSync } from "node:child_process"; |
5 | 9 | import * as fs from "node:fs"; |
@@ -284,7 +288,11 @@ function buildIssueFieldHeadingSequences(): string[][] { |
284 | 288 | "single-target-chip-1-with-target", |
285 | 289 | ]; |
286 | 290 | for (let deviceCount = 1; deviceCount <= MAX_DEVICES; deviceCount++) { |
287 | | - for (let upgradeCount = 1; upgradeCount <= MAX_UPGRADES; upgradeCount++) { |
| 291 | + for ( |
| 292 | + let upgradeCount = 1; |
| 293 | + upgradeCount <= MAX_UPGRADES; |
| 294 | + upgradeCount++ |
| 295 | + ) { |
288 | 296 | for (const fileLayout of fileLayouts) { |
289 | 297 | sequences.add( |
290 | 298 | JSON.stringify( |
@@ -446,6 +454,33 @@ function loadFirmwareConfigs(): FirmwareConfigFile[] { |
446 | 454 | }); |
447 | 455 | } |
448 | 456 |
|
| 457 | +export function appendUpgradesToFirmwareConfigText( |
| 458 | + configText: string, |
| 459 | + newUpgrades: readonly Record<string, any>[], |
| 460 | +): string { |
| 461 | + const config = parseCommentJson<Record<string, any>>(configText); |
| 462 | + if (!Array.isArray(config.upgrades)) { |
| 463 | + throw new Error("Firmware config does not contain an upgrades array."); |
| 464 | + } |
| 465 | + |
| 466 | + for (const upgrade of newUpgrades) { |
| 467 | + config.upgrades.push(upgrade); |
| 468 | + } |
| 469 | + |
| 470 | + return `${stringifyCommentJson(config, null, "\t")}\n`; |
| 471 | +} |
| 472 | + |
| 473 | +export async function formatWithPrettier( |
| 474 | + text: string, |
| 475 | + parser: string, |
| 476 | + prettierConfig: Record<string, any> = {}, |
| 477 | +): Promise<string> { |
| 478 | + return prettier.format(text, { |
| 479 | + ...prettierConfig, |
| 480 | + parser, |
| 481 | + }); |
| 482 | +} |
| 483 | + |
449 | 484 | function chooseExistingDirectory( |
450 | 485 | candidates: string[], |
451 | 486 | preferredDirectory: string, |
@@ -616,7 +651,8 @@ export function parseIssueBody(body: string): Record<string, string | null> { |
616 | 651 | ? candidateSequences |
617 | 652 | .filter( |
618 | 653 | (candidate) => |
619 | | - candidate.headings[candidate.nextHeadingIndex] === heading, |
| 654 | + candidate.headings[candidate.nextHeadingIndex] === |
| 655 | + heading, |
620 | 656 | ) |
621 | 657 | .map((candidate) => ({ |
622 | 658 | headings: candidate.headings, |
@@ -888,7 +924,11 @@ function normalizeUpgradeVariant(upgrade: Record<string, any>): { |
888 | 924 | function getUpgradeVariantKey( |
889 | 925 | variant: NonNullable<ReturnType<typeof normalizeUpgradeVariant>>, |
890 | 926 | ): string { |
891 | | - return JSON.stringify([variant.version, variant.region, variant.ifCondition]); |
| 927 | + return JSON.stringify([ |
| 928 | + variant.version, |
| 929 | + variant.region, |
| 930 | + variant.ifCondition, |
| 931 | + ]); |
892 | 932 | } |
893 | 933 |
|
894 | 934 | function describeUpgradeVariant( |
@@ -1030,21 +1070,15 @@ export function parseUpgradeFilesFromSections({ |
1030 | 1070 | ? getSingleTargetTargetNumberFieldLabel(upgradeIndex) |
1031 | 1071 | : descriptor.targetLabels[0], |
1032 | 1072 | }); |
1033 | | - if ( |
1034 | | - urlLabel === singleTargetUrlLabel && |
1035 | | - targetRaw != null |
1036 | | - ) { |
| 1073 | + if (urlLabel === singleTargetUrlLabel && targetRaw != null) { |
1037 | 1074 | errors.push( |
1038 | 1075 | `'${targetLabel}' is not supported in the single-target submission form. That form always uses target number 0. Use the 'Firmware Submission' form instead.`, |
1039 | 1076 | ); |
1040 | 1077 | } |
1041 | 1078 | const target = |
1042 | 1079 | targetRaw != null && urlLabel !== singleTargetUrlLabel |
1043 | | - ? (validateTargetNumber( |
1044 | | - targetRaw, |
1045 | | - targetLabel, |
1046 | | - errors, |
1047 | | - ) ?? descriptor.defaultTarget) |
| 1080 | + ? (validateTargetNumber(targetRaw, targetLabel, errors) ?? |
| 1081 | + descriptor.defaultTarget) |
1048 | 1082 | : descriptor.defaultTarget; |
1049 | 1083 |
|
1050 | 1084 | files.push({ target, url }); |
@@ -1761,10 +1795,11 @@ export default async function main({ |
1761 | 1795 | for (const upgrade of upgradeFormData) { |
1762 | 1796 | const raw = upgrade.changelog.trim().replace(/\r\n/g, "\n"); |
1763 | 1797 | try { |
1764 | | - const formatted = await prettier.format(raw, { |
1765 | | - ...prettierConfig, |
1766 | | - parser: "markdown", |
1767 | | - }); |
| 1798 | + const formatted = await formatWithPrettier( |
| 1799 | + raw, |
| 1800 | + "markdown", |
| 1801 | + prettierConfig, |
| 1802 | + ); |
1768 | 1803 | formattedChangelogs.push(formatted.trim()); |
1769 | 1804 | } catch { |
1770 | 1805 | formattedChangelogs.push(raw); |
@@ -1801,42 +1836,44 @@ export default async function main({ |
1801 | 1836 | ]); |
1802 | 1837 | } |
1803 | 1838 |
|
1804 | | - const config = existingConfig |
1805 | | - ? { |
1806 | | - ...existingConfig, |
1807 | | - upgrades: [ |
1808 | | - ...(existingConfig.upgrades ?? []), |
1809 | | - ...newUpgrades, |
1810 | | - ], |
1811 | | - } |
1812 | | - : { |
1813 | | - devices: devices.map((device) => { |
1814 | | - const entry: Record<string, any> = { |
1815 | | - brand: device.brand, |
1816 | | - model: device.model, |
1817 | | - manufacturerId: device.manufacturerId, |
1818 | | - productType: device.productType, |
1819 | | - productId: device.productId, |
1820 | | - }; |
1821 | | - if (device.firmwareVersion) { |
1822 | | - entry.firmwareVersion = device.firmwareVersion; |
1823 | | - } |
1824 | | - return entry; |
1825 | | - }), |
1826 | | - upgrades: newUpgrades, |
1827 | | - }; |
| 1839 | + const configText = matchedExistingFile |
| 1840 | + ? appendUpgradesToFirmwareConfigText( |
| 1841 | + fs.readFileSync(matchedExistingFile.absolutePath, "utf-8"), |
| 1842 | + newUpgrades, |
| 1843 | + ) |
| 1844 | + : `${stringifyCommentJson( |
| 1845 | + { |
| 1846 | + devices: devices.map((device) => { |
| 1847 | + const entry: Record<string, any> = { |
| 1848 | + brand: device.brand, |
| 1849 | + model: device.model, |
| 1850 | + manufacturerId: device.manufacturerId, |
| 1851 | + productType: device.productType, |
| 1852 | + productId: device.productId, |
| 1853 | + }; |
| 1854 | + if (device.firmwareVersion) { |
| 1855 | + entry.firmwareVersion = device.firmwareVersion; |
| 1856 | + } |
| 1857 | + return entry; |
| 1858 | + }), |
| 1859 | + upgrades: newUpgrades, |
| 1860 | + }, |
| 1861 | + null, |
| 1862 | + "\t", |
| 1863 | + )}\n`; |
| 1864 | + const formattedConfigText = await formatWithPrettier( |
| 1865 | + configText, |
| 1866 | + "jsonc", |
| 1867 | + prettierConfig, |
| 1868 | + ); |
1828 | 1869 |
|
1829 | 1870 | console.log( |
1830 | 1871 | "Re-checking approved issue state before writing changes...", |
1831 | 1872 | ); |
1832 | 1873 | await ensureIssueStillApproved(true); |
1833 | 1874 | console.log(`Writing config to ${relativeFilePath}...`); |
1834 | 1875 | fs.mkdirSync(path.dirname(absoluteFilePath), { recursive: true }); |
1835 | | - fs.writeFileSync( |
1836 | | - absoluteFilePath, |
1837 | | - `${JSON.stringify(config, null, "\t")}\n`, |
1838 | | - "utf-8", |
1839 | | - ); |
| 1876 | + fs.writeFileSync(absoluteFilePath, formattedConfigText, "utf-8"); |
1840 | 1877 |
|
1841 | 1878 | git("add", relativeFilePath); |
1842 | 1879 | const lastVersion = |
|
0 commit comments