Skip to content

Commit e7d4967

Browse files
committed
chore: parse all the files
1 parent 17b29f8 commit e7d4967

File tree

1 file changed

+131
-40
lines changed

1 file changed

+131
-40
lines changed

script/user-chart/add.ts

Lines changed: 131 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,78 @@ import {
66
type GistForm,
77
updateGist as updateGistApi
88
} from "@src/api/gist"
9+
import { CHROME_ID } from "@src/util/constant/meta"
910
import fs from "fs"
1011
import { exitWith } from "../util/process"
1112
import { type Browser, descriptionOf, filenameOf, getExistGist, type UserCount, validateTokenFromEnv } from "./common"
1213

13-
type AddArgv = {
14+
type AutoMode = {
15+
mode: 'auto'
16+
dirPath: string
17+
}
18+
19+
type ManualMode = {
20+
mode: 'manual'
1421
browser: Browser
1522
fileName: string
1623
}
1724

25+
type AddArgv = AutoMode | ManualMode
26+
27+
const BROWSER_MAP: Record<string, Browser> = {
28+
c: 'chrome',
29+
e: 'edge',
30+
f: 'firefox',
31+
}
32+
1833
function parseArgv(): AddArgv {
1934
const argv = process.argv.slice(2)
20-
const browserArgv = argv[0]
21-
const fileName = argv[1]
22-
if (!browserArgv || !fileName) {
23-
exitWith("add.ts [c/e/f] [file_name]")
35+
const [a0, a1] = argv
36+
37+
if (!a0) {
38+
exitWith("add.ts [c/e/f] [file_name] OR add.ts auto [dir_path]")
2439
}
25-
const browserArgvMap: Record<string, Browser> = {
26-
c: 'chrome',
27-
e: 'edge',
28-
f: 'firefox',
40+
41+
if (a0 === 'auto') {
42+
if (!a1) exitWith("add.ts auto [dir_path]")
43+
return { mode: 'auto', dirPath: a1 }
2944
}
30-
const browser: Browser = browserArgvMap[browserArgv]
45+
46+
if (!a1) {
47+
exitWith("add.ts [c/e/f] [file_name] OR add.ts auto [dir_path]")
48+
}
49+
50+
const browser: Browser = BROWSER_MAP[a0]
3151
if (!browser) {
3252
exitWith("add.ts [c/e/f] [file_name]")
3353
}
34-
return {
35-
browser,
36-
fileName
37-
}
54+
55+
return { mode: 'manual', browser, fileName: a1 }
3856
}
3957

40-
async function createGist(token: string, browser: Browser, data: UserCount) {
41-
const description = descriptionOf(browser)
42-
const filename = filenameOf(browser)
58+
function detectBrowser(fileName: string): Browser | null {
59+
if (fileName.includes(CHROME_ID)) return 'chrome'
60+
if (fileName.includes('usage-day-')) return 'firefox'
61+
if (fileName.includes('edgeaddon_analytics')) return 'edge'
62+
return null
63+
}
4364

44-
// 1. sort by key
65+
function sortDataByKey(data: UserCount): UserCount {
4566
const sorted: UserCount = {}
4667
Object.keys(data).sort().forEach(key => sorted[key] = data[key])
47-
// 2. create
48-
const files: Record<string, FileForm> = {}
49-
files[filename] = { filename: filename, content: JSON.stringify(sorted, null, 2) }
68+
return sorted
69+
}
70+
71+
async function createGist(token: string, browser: Browser, data: UserCount) {
72+
const description = descriptionOf(browser)
73+
const filename = filenameOf(browser)
74+
const sorted = sortDataByKey(data)
75+
const files: Record<string, FileForm> = {
76+
[filename]: {
77+
filename,
78+
content: JSON.stringify(sorted, null, 2)
79+
}
80+
}
5081
const gistForm: GistForm = {
5182
public: true,
5283
description,
@@ -67,12 +98,8 @@ async function updateGist(token: string, browser: Browser, data: UserCount, gist
6798
Object.keys(existData).sort().forEach(key => sorted[key] = existData[key])
6899
const files: Record<string, FileForm> = {}
69100
files[filename] = { filename: filename, content: JSON.stringify(sorted, null, 2) }
70-
const gistForm: GistForm = {
71-
public: true,
72-
description,
73-
files
74-
}
75-
updateGistApi(token, gist.id, gistForm)
101+
const gistForm: GistForm = { public: true, description, files }
102+
await updateGistApi(token, gist.id, gistForm)
76103
}
77104

78105
function parseChrome(content: string): UserCount {
@@ -142,22 +169,86 @@ function rjust(str: string, num: number, padding: string): string {
142169
return Array.from(new Array(num - str.length).keys()).map(_ => padding).join('') + str
143170
}
144171

172+
const PARSERS: Record<Browser, (content: string) => UserCount> = {
173+
chrome: parseChrome,
174+
edge: parseEdge,
175+
firefox: parseFirefox,
176+
}
177+
178+
async function processFile(browser: Browser, filePath: string): Promise<UserCount> {
179+
const content = fs.readFileSync(filePath, { encoding: 'utf-8' })
180+
return PARSERS[browser](content)
181+
}
182+
183+
function groupFilesByBrowser(files: string[]): Record<Browser, string[]> {
184+
const grouped: Record<Browser, string[]> = { chrome: [], edge: [], firefox: [] }
185+
for (const file of files) {
186+
const browser = detectBrowser(file)
187+
if (browser) {
188+
grouped[browser].push(file)
189+
} else {
190+
console.warn(`Unknown file format, skipping: ${file}`)
191+
}
192+
}
193+
return grouped
194+
}
195+
196+
function mergeData(target: UserCount, source: UserCount): void {
197+
Object.entries(source).forEach(([key, val]) => {
198+
target[key] = target[key] ? Math.max(target[key], val) : val
199+
})
200+
}
201+
202+
async function processDirectory(token: string, dirPath: string) {
203+
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.csv'))
204+
if (files.length === 0) exitWith(`No CSV files found in ${dirPath}`)
205+
206+
const filesByBrowser = groupFilesByBrowser(files)
207+
208+
for (const [browser, browserFiles] of Object.entries(filesByBrowser)) {
209+
if (browserFiles.length === 0) continue
210+
211+
const typedBrowser = browser as Browser
212+
console.log(`Processing ${browser.toUpperCase()}: ${browserFiles.length} file(s)`)
213+
214+
let mergedData: UserCount = {}
215+
for (const file of browserFiles) {
216+
const filePath = `${dirPath}/${file}`
217+
console.log(`Processing: ${file}`)
218+
const data = await processFile(typedBrowser, filePath)
219+
mergeData(mergedData, data)
220+
}
221+
222+
if (Object.keys(mergedData).length === 0) {
223+
console.log(`No valid data found for ${browser}`)
224+
continue
225+
}
226+
227+
console.log(`Merged ${Object.keys(mergedData).length} date entries for ${browser}`)
228+
229+
const gist = await getExistGist(token, typedBrowser)
230+
if (!gist) {
231+
console.log(`Creating new gist for ${browser}...`)
232+
await createGist(token, typedBrowser, mergedData)
233+
} else {
234+
console.log(`Updating existing gist for ${browser}...`)
235+
await updateGist(token, typedBrowser, mergedData, gist)
236+
}
237+
console.log(`${browser.toUpperCase()} completed successfully!`)
238+
}
239+
}
240+
145241
async function main() {
146242
const token = validateTokenFromEnv()
147-
const argv: AddArgv = parseArgv()
148-
const browser = argv.browser
149-
const fileName = argv.fileName
150-
const content = fs.readFileSync(fileName, { encoding: 'utf-8' })
151-
let newData: UserCount = {}
152-
if (browser === 'chrome') {
153-
newData = parseChrome(content)
154-
} else if (browser === 'edge') {
155-
newData = parseEdge(content)
156-
} else if (browser === 'firefox') {
157-
newData = parseFirefox(content)
158-
} else {
159-
exitWith("Un-supported browser: " + browser)
243+
const argv = parseArgv()
244+
245+
if (argv.mode === 'auto') {
246+
return await processDirectory(token, argv.dirPath)
160247
}
248+
249+
const { browser, fileName } = argv
250+
251+
const newData = await processFile(browser, fileName)
161252
const gist = await getExistGist(token, browser)
162253
if (!gist) {
163254
await createGist(token, browser, newData)

0 commit comments

Comments
 (0)