Skip to content

Commit 5778e2d

Browse files
authored
Fix lint issues and lint in CI (#18)
1 parent fe3afbb commit 5778e2d

10 files changed

Lines changed: 359 additions & 44 deletions

File tree

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: CI
2+
'on':
3+
push:
4+
branches: [master]
5+
pull_request:
6+
7+
jobs:
8+
lint:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v6
12+
13+
- name: Setup Node.js
14+
uses: actions/setup-node@v6
15+
with:
16+
node-version-file: .tool-versions
17+
cache: yarn
18+
19+
- name: Install Packages
20+
run: yarn --immutable
21+
22+
- name: Run linter
23+
run: yarn lint

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npx lint-staged

.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodejs 24

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"lint:fix": "yarn eslint --max-warnings 0 --cache --fix && yarn prettier --write .",
88
"dev": "next dev",
99
"build": "next build",
10-
"start": "next start"
10+
"start": "next start",
11+
"prepare": "husky"
1112
},
1213
"dependencies": {
1314
"@chakra-ui/react": "^3.31.0",
@@ -44,9 +45,17 @@
4445
"eslint-plugin-react": "^7.37.5",
4546
"eslint-plugin-react-hooks": "^7.0.1",
4647
"globals": "^16.5.0",
48+
"husky": "^9.1.7",
49+
"lint-staged": "^16.2.7",
4750
"prettier": "^3.8.0",
4851
"typescript": "^5.9.3",
4952
"typescript-eslint": "^8.53.0"
5053
},
54+
"lint-staged": {
55+
"*.{js,jsx,ts,tsx}": [
56+
"yarn eslint --cache --fix --max-warnings 0 --no-warn-ignored",
57+
"yarn prettier --write"
58+
]
59+
},
5160
"packageManager": "yarn@4.11.0"
5261
}

src/app/debug/page.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import OtaPartition, { OtaPartitionDetails } from '@/esp/OtaPartition';
2626
import HexSpan from '@/components/HexSpan';
2727
import HexViewer from '@/components/HexViewer';
2828
import { downloadData } from '@/utils/download';
29-
import FileUpload, { FileUploadHandle } from '@/components/FileUpload';
3029
import { FirmwareInfo } from '@/utils/firmwareIdentifier';
3130

3231
function OtadataDebug({ otaPartition }: { otaPartition: OtaPartition }) {
@@ -220,6 +219,7 @@ function FirmwareIdentificationDebug({
220219
case 'crosspoint':
221220
return 'blue';
222221
case 'unknown':
222+
default:
223223
return 'orange';
224224
}
225225
};
@@ -272,9 +272,8 @@ function FirmwareIdentificationDebug({
272272
}
273273

274274
export default function Debug() {
275-
const { actions, debugActions, stepData, isRunning } = useEspOperations();
275+
const { debugActions, stepData, isRunning } = useEspOperations();
276276
const [debugOutputNode, setDebugOutputNode] = useState<ReactNode>(null);
277-
const appPartitionFileInput = React.useRef<FileUploadHandle>(null);
278277

279278
return (
280279
<Flex direction="column" gap="20px">
@@ -284,8 +283,8 @@ export default function Debug() {
284283
<Stack gap={1} color="grey" textStyle="sm">
285284
<p>
286285
These are few tools to help debugging / administering your Xtink
287-
device. They&apos;re designed to be used by those who are
288-
intentionally messing around with their device.
286+
device. Theyre designed to be used by those who are intentionally
287+
messing around with their device.
289288
</p>
290289
<p>
291290
<b>Read otadata partition</b> will read the raw data out of the{' '}
@@ -303,8 +302,8 @@ export default function Debug() {
303302
<Em>otadata</Em> to switch the boot partition.
304303
</p>
305304
<p>
306-
<b>Identify firmware in both partitions</b> will read both app0 and
307-
app1 partitions and automatically identify which firmware is
305+
<b>Identify firmware in both partitions</b> will read both app0
306+
and app1 partitions and automatically identify which firmware is
308307
installed on each (Official English, Official Chinese, CrossPoint
309308
Community, or Custom).
310309
</p>
@@ -414,4 +413,4 @@ export default function Debug() {
414413
) : null}
415414
</Flex>
416415
);
417-
}
416+
}

src/app/page.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ export default function Home() {
4848
<Alert.Description>
4949
<Stack>
5050
<p>
51-
I&apos;ve tried to make this foolproof and while the likelihood
52-
of unrecoverable things going wrong is extremely low, it&apos;s
53-
never zero. So proceed with care and make sure to grab a backup
54-
using <b>Save full flash</b> before flashing your device.
51+
Ive tried to make this foolproof and while the likelihood of
52+
unrecoverable things going wrong is extremely low, it’s never
53+
zero. So proceed with care and make sure to grab a backup using{' '}
54+
<b>Save full flash</b> before flashing your device.
5555
</p>
5656
<p>
5757
Once you start <b>Write flash from file</b> or{' '}
@@ -75,10 +75,10 @@ export default function Home() {
7575
goes wrong.
7676
</p>
7777
<p>
78-
<b>Save full flash</b> will read your device&apos;s flash and save
79-
it as <Em>flash.bin</Em>. This will take around 25 minutes to
80-
complete. You can use that file (or someone else&apos;s) with{' '}
81-
<b>Write full flash from file</b> to overwrite your device&apos;s
78+
<b>Save full flash</b> will read your devices flash and save it
79+
as <Em>flash.bin</Em>. This will take around 25 minutes to
80+
complete. You can use that file (or someone elses) with{' '}
81+
<b>Write full flash from file</b> to overwrite your devices
8282
entire flash.
8383
</p>
8484
</Stack>
@@ -116,8 +116,8 @@ export default function Home() {
116116
<Heading size="xl">OTA fast flash controls</Heading>
117117
<Stack gap={1} color="grey" textStyle="sm">
118118
<p>
119-
Before using this, I&apos;d strongly recommend taking a backup of
120-
your device using <b>Save full flash</b> above.
119+
Before using this, Id strongly recommend taking a backup of your
120+
device using <b>Save full flash</b> above.
121121
</p>
122122
<p>
123123
<b>Flash English/Chinese firmware</b> will download the firmware,
@@ -208,9 +208,9 @@ export default function Home() {
208208
<Alert.Title>Change device language</Alert.Title>
209209
<Alert.Description>
210210
Before starting the process, it is recommended to change the device
211-
language to English. To do this, select "Settings" icon, then
212-
click "OK / Confirm" button and "OK / Confirm" again until English is shown.
213-
Otherwise, the language will still be Chinese after flashing
211+
language to English. To do this, select Settings icon, then click
212+
OK / Confirm button and OK / Confirm again until English is
213+
shown. Otherwise, the language will still be Chinese after flashing
214214
and you may not notice changes.
215215
</Alert.Description>
216216
</Alert.Content>
@@ -221,9 +221,9 @@ export default function Home() {
221221
<Alert.Title>Device restart instructions</Alert.Title>
222222
<Alert.Description>
223223
Once you complete a write operation, you will need to restart your
224-
device by pressing and releasing the small "Reset" button near the bottom
225-
right, followed quickly by pressing and holding of the main power
226-
button for about 3 seconds.
224+
device by pressing and releasing the small Reset button near the
225+
bottom right, followed quickly by pressing and holding of the main
226+
power button for about 3 seconds.
227227
</Alert.Description>
228228
</Alert.Content>
229229
</Alert.Root>

src/esp/EspController.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export default class EspController {
104104
return this.espLoader.readFlash(offset, 0x640000, onPacketReceived);
105105
}
106106

107-
async readAppPartitionForIdentification(
107+
async readAppPartitionForIdentification(
108108
partitionLabel: 'app0' | 'app1',
109109
{
110110
readSize = 0x6400, // Default to 25KB (0x6400) for fast identification
@@ -123,7 +123,7 @@ export default class EspController {
123123
// Optimized read for firmware identification with flexible read size and offset:
124124
// - Default (25KB / 0x6400): Fast path, covers 99% of cases
125125
// - Additional chunks: Specify offset multiples of 25KB until identification succeeds
126-
// In testing, most firmwares are identified within the first 25KB read, so reading the entire
126+
// In testing, most firmwares are identified within the first 25KB read, so reading the entire
127127
// partition is unnecessary in the majority of cases.
128128

129129
const baseOffset = partitionLabel === 'app0' ? 0x10000 : 0x650000;
@@ -183,4 +183,4 @@ export default class EspController {
183183
reportProgress,
184184
});
185185
}
186-
}
186+
}

src/esp/useEspOperations.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ export function useEspOperations() {
2323

2424
const wrapWithRunning =
2525
<Args extends unknown[], T>(fn: (...a: Args) => Promise<T>) =>
26-
async (...a: Args) => {
27-
setIsRunning(true);
28-
return fn(...a).finally(() => setIsRunning(false));
29-
};
26+
async (...a: Args) => {
27+
setIsRunning(true);
28+
return fn(...a).finally(() => setIsRunning(false));
29+
};
3030

3131
const flashRemoteFirmware = async (
3232
getFirmware: () => Promise<Uint8Array>,
@@ -416,6 +416,7 @@ export function useEspOperations() {
416416
let info: FirmwareInfo | undefined;
417417

418418
for (let offset = 0; offset < maxReadSize; offset += chunkSize) {
419+
// eslint-disable-next-line no-await-in-loop
419420
const chunk = await espController.readAppPartitionForIdentification(
420421
partitionLabel,
421422
{
@@ -441,7 +442,13 @@ export function useEspOperations() {
441442
}
442443
}
443444

444-
return info ?? { type: 'unknown', version: 'unknown', displayName: 'Custom/Unknown Firmware' }; // Return the last identification result if not found
445+
return (
446+
info ?? {
447+
type: 'unknown',
448+
version: 'unknown',
449+
displayName: 'Custom/Unknown Firmware',
450+
}
451+
); // Return the last identification result if not found
445452
};
446453

447454
const app0Info = await runStep('Read app0 partition', () =>
@@ -486,4 +493,4 @@ export function useEspOperations() {
486493
readAndIdentifyAllFirmware: wrapWithRunning(readAndIdentifyAllFirmware),
487494
},
488495
};
489-
}
496+
}

src/utils/firmwareIdentifier.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ function findString(
1919
return -1;
2020
}
2121

22-
for (let i = startOffset; i <= data.length - searchBytes.length; i++) {
22+
for (let i = startOffset; i <= data.length - searchBytes.length; i += 1) {
2323
let match = true;
24-
for (let j = 0; j < searchBytes.length; j++) {
24+
for (let j = 0; j < searchBytes.length; j += 1) {
2525
if (data[i + j] !== searchBytes[j]) {
2626
match = false;
2727
break;
@@ -73,7 +73,7 @@ function extractVersion(data: Uint8Array, searchLimit = 25000): string {
7373

7474
// Try to find V-pattern versions (official firmware)
7575
// Pattern: [any byte]<V3.1.1 or similar
76-
for (let i = 0; i < searchArea.length - 8; i++) {
76+
for (let i = 0; i < searchArea.length - 8; i += 1) {
7777
if (searchArea[i] === 0x56) {
7878
// 'V' character
7979
const chunk = decoder.decode(
@@ -91,12 +91,16 @@ function extractVersion(data: Uint8Array, searchLimit = 25000): string {
9191
const fullString = decoder.decode(searchArea);
9292

9393
// Check for CrossPoint-ESP32-x.x.x pattern
94-
const crossPointMatch = fullString.match(/CrossPoint-ESP32-(\d+\.\d+\.\d+)/);
94+
const crossPointMatch = fullString.match(
95+
/CrossPoint-ESP32-(\d+\.\d+\.\d+)/,
96+
);
9597
if (crossPointMatch) {
9698
return crossPointMatch[1]!;
9799
}
98100

101+
// eslint-disable-next-line no-control-regex
99102
const lines = fullString.split(/[\x00\n]/);
103+
// eslint-disable-next-line no-restricted-syntax
100104
for (const line of lines) {
101105
const match = line.match(/^\d+\.\d+\.\d+$/);
102106
if (match) {
@@ -107,7 +111,7 @@ function extractVersion(data: Uint8Array, searchLimit = 25000): string {
107111
// Also search for version in common patterns
108112
const versionMatch = fullString.match(/(?:Version[:\s]*)(\d+\.\d+\.\d+)/i);
109113
if (versionMatch?.[1]) {
110-
return versionMatch[1] as string;
114+
return versionMatch[1];
111115
}
112116
} catch {
113117
// Decoding failed, continue
@@ -162,7 +166,7 @@ export function identifyFirmware(firmwareData: Uint8Array): FirmwareInfo {
162166
if (findString(areaAfterVersion, 'XTOS') !== -1) {
163167
return {
164168
type: 'official-chinese',
165-
version: version,
169+
version,
166170
displayName: 'Official Chinese',
167171
};
168172
}
@@ -171,7 +175,7 @@ export function identifyFirmware(firmwareData: Uint8Array): FirmwareInfo {
171175
// If we have a V-pattern version, valid ESP32 image, but no XTOS → English
172176
return {
173177
type: 'official-english',
174-
version: version,
178+
version,
175179
displayName: 'Official English',
176180
};
177181
}
@@ -183,15 +187,15 @@ export function identifyFirmware(firmwareData: Uint8Array): FirmwareInfo {
183187
) {
184188
return {
185189
type: 'crosspoint',
186-
version: version,
190+
version,
187191
displayName: 'CrossPoint Community Reader',
188192
};
189193
}
190194

191195
// Unknown firmware
192196
return {
193197
type: 'unknown',
194-
version: version,
198+
version,
195199
displayName: 'Custom/Unknown Firmware',
196200
};
197201
}
@@ -205,4 +209,4 @@ export function identifyFirmware(firmwareData: Uint8Array): FirmwareInfo {
205209
*/
206210
export function isIdentificationSuccessful(info: FirmwareInfo): boolean {
207211
return info.type !== 'unknown';
208-
}
212+
}

0 commit comments

Comments
 (0)