Skip to content

Commit bbd2a2d

Browse files
committed
Added bump-utils.mjs as dependency
1 parent 28a6add commit bbd2a2d

1 file changed

Lines changed: 25 additions & 116 deletions

File tree

utils/bump/resources.js

Lines changed: 25 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -10,145 +10,54 @@
1010
// Import LIBS
1111
const fs = require('fs'), // to read/write files
1212
path = require('path'), // to manipulate paths
13-
ssri = require('ssri') // to generate SHA-256 hashes
13+
bumpUtilsFilePath = path.join(__dirname, '.cache/bump-utils.mjs')
14+
fs.mkdirSync(path.dirname(bumpUtilsFilePath), { recursive: true })
15+
fs.writeFileSync(bumpUtilsFilePath, Buffer.from(await (await fetch(
16+
'https://cdn.jsdelivr.net/gh/adamlui/ai-web-extensions@latest/utils/bump/bump-utils.mjs')).arrayBuffer()))
17+
const bump = await import(require('url').pathToFileURL(bumpUtilsFilePath))
1418

1519
// Init CACHE vars
1620
const cacheMode = process.argv.includes('--cache'),
1721
cacheFilePath = path.join(__dirname, '.cache/userJSpaths.json')
1822

19-
// Init UI COLORS
20-
const nc = '\x1b[0m', // no color
21-
dg = '\x1b[38;5;243m', // dim gray
22-
bw = '\x1b[1;97m', // bright white
23-
by = '\x1b[1;33m', // bright yellow
24-
bg = '\x1b[1;92m', // bright green
25-
br = '\x1b[1;91m' // bright red
26-
2723
// Init REGEX
2824
const regEx = {
2925
hash: { commit: /(@|\?v=)([^/#]+)/, sri: /[^#]+$/ },
3026
resName: /[^/]+\/(?:dist)?\/?[^/]+\.js(?=[?#]|$)/,
3127
jsURL: /^\/\/ @require\s+(https:\/\/cdn\.jsdelivr\.net\/gh\/.+)$/
3228
}
3329

34-
// Define FUNCTIONS
35-
36-
const log = {};
37-
['hash', 'info', 'working', 'success', 'error'].forEach(lvl => log[lvl] = function(msg) {
38-
const logColor = lvl == 'hash' ? dg : lvl == 'info' ? bw : lvl == 'working' ? by : lvl == 'success' ? bg : br,
39-
formattedMsg = logColor + ( log.endedWithLineBreak ? msg.trimStart() : msg ) + nc
40-
console.log(formattedMsg) ; log.endedWithLineBreak = msg.toString().endsWith('\n')
41-
})
42-
43-
function bumpUserJSver(userJSfilePath) {
44-
const date = new Date(),
45-
today = `${date.getFullYear()}.${date.getMonth() +1}.${date.getDate()}`, // YYYY.M.D format
46-
reVersion = /(@version\s+)([\d.]+)/,
47-
userJScontent = fs.readFileSync(userJSfilePath, 'utf-8'),
48-
currentVer = userJScontent.match(reVersion)[2]
49-
let newVer
50-
if (currentVer.startsWith(today)) { // bump sub-ver
51-
const verParts = currentVer.split('.'),
52-
subVer = verParts.length > 3 ? parseInt(verParts[3], 10) +1 : 1
53-
newVer = `${today}.${subVer}`
54-
} else // bump to today
55-
newVer = today
56-
fs.writeFileSync(userJSfilePath, userJScontent.replace(reVersion, `$1${newVer}`), 'utf-8')
57-
console.log(`Updated: ${bw}v${currentVer}${nc}${bg}v${newVer}${nc}`)
58-
}
59-
60-
function fetchData(url) {
61-
if (typeof fetch == 'undefined') // polyfill for Node.js < v21
62-
return new Promise((resolve, reject) => {
63-
try { // to use http or https module
64-
const protocol = url.match(/^([^:]+):\/\//)[1]
65-
if (!/^https?$/.test(protocol)) reject(new Error('Invalid fetchData() URL.'))
66-
require(protocol).get(url, resp => {
67-
let rawData = ''
68-
resp.on('data', chunk => rawData += chunk)
69-
resp.on('end', () => resolve({ json: () => JSON.parse(rawData) }))
70-
}).on('error', err => reject(new Error(err.message)))
71-
} catch (err) { reject(new Error('Environment not supported.'))
72-
}})
73-
else // use fetch() from Node.js v21+
74-
return fetch(url)
75-
}
76-
77-
async function findUserJS(dir = findUserJS.monorepoRoot) {
78-
const userJSfiles = []
79-
if (!dir && !findUserJS.monorepoRoot) { // no arg passed, init monorepo root
80-
dir = __dirname
81-
while (!fs.existsSync(path.join(dir, 'package.json')))
82-
dir = path.dirname(dir) // traverse up to closest manifest dir
83-
findUserJS.monorepoRoot = dir
84-
}
85-
dir = path.resolve(dir)
86-
fs.readdirSync(dir).forEach(async entry => {
87-
if (/^(?:\.|node_modules$)/.test(entry)) return
88-
const entryPath = path.join(dir, entry)
89-
if (fs.statSync(entryPath).isDirectory()) // recursively search subdirs
90-
userJSfiles.push(...await findUserJS(entryPath))
91-
else if (entry.endsWith('.user.js')) {
92-
console.log(entryPath) ; userJSfiles.push(entryPath) }
93-
})
94-
return userJSfiles
95-
}
96-
97-
async function generateSRIhash(resURL, algorithm = 'sha256') {
98-
const sriHash = ssri.fromData(
99-
Buffer.from(await (await fetchData(resURL)).arrayBuffer()), { algorithms: [algorithm] }).toString()
100-
log.hash(`${sriHash}\n`)
101-
return sriHash
102-
}
103-
104-
async function getLatestCommitHash(repo, path) {
105-
const endpoint = `https://api.github.com/repos/${repo}/commits`,
106-
latestCommitHash = (await (await fetchData(`${endpoint}?path=${ path || '' }`)).json())[0]?.sha
107-
if (latestCommitHash) log.hash(`${latestCommitHash}\n`)
108-
return latestCommitHash
109-
}
110-
111-
async function isValidResource(resURL) {
112-
try {
113-
const resIsValid = !(await (await fetchData(resURL)).text()).startsWith('Package size exceeded')
114-
if (!resIsValid) log.error(`\nInvalid resource: ${resURL}\n`)
115-
return resIsValid
116-
} catch (err) { return log.error(`\nCannot validate resource: ${resURL}\n`) }
117-
}
118-
119-
// Run MAIN routine
120-
12130
// Collect userscripts
122-
log.working(`\n${ cacheMode ? 'Collecting' : 'Searching for' } userscripts...\n`)
31+
bump.log.working(`\n${ cacheMode ? 'Collecting' : 'Searching for' } userscripts...\n`)
12332
let userJSfiles = []
12433
if (cacheMode) {
12534
try { // create missing cache file
12635
fs.mkdirSync(path.dirname(cacheFilePath), { recursive: true })
12736
const fd = fs.openSync(cacheFilePath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_RDWR)
128-
log.error(`Cache file missing. Generating ${cacheFilePath}...\n`)
129-
userJSfiles = await findUserJS() ; console.log('')
37+
bump.log.error(`Cache file missing. Generating ${cacheFilePath}...\n`)
38+
userJSfiles = await bump.findUserJS() ; console.log('')
13039
fs.writeFileSync(fd, JSON.stringify(userJSfiles, null, 2), 'utf-8')
131-
log.success(`\nCache file created @ ${cacheFilePath}`)
40+
bump.log.success(`\nCache file created @ ${cacheFilePath}`)
13241
} catch (err) { // use existing cache file
13342
userJSfiles = JSON.parse(fs.readFileSync(cacheFilePath, 'utf-8'))
13443
console.log(userJSfiles) ; console.log('')
13544
}
13645
} else { // use findUserJS()
137-
userJSfiles = await findUserJS() ; console.log('') }
46+
userJSfiles = await bump.findUserJS() ; console.log('') }
13847

13948
// Collect resources
140-
log.working('\nCollecting resources...\n')
49+
bump.log.working('\nCollecting resources...\n')
14150
const urlMap = {} ; let resCnt = 0
14251
userJSfiles.forEach(userJSfilePath => {
14352
const userJScontent = fs.readFileSync(userJSfilePath, 'utf-8'),
14453
resURLs = [...userJScontent.matchAll(new RegExp(regEx.jsURL.source, 'gm'))].map(match => match[1])
14554
if (resURLs.length > 0) { urlMap[userJSfilePath] = resURLs ; resCnt += resURLs.length }
14655
})
147-
log.success(`${resCnt} potentially bumpable resource(s) found.`)
56+
bump.log.success(`${resCnt} potentially bumpable resource(s) found.`)
14857

14958
// Fetch latest commit hash for adamlui/ai-web-extensions
150-
log.working('\nFetching latest commit hash for adamlui/ai-web-extensions...\n')
151-
const latestCommitHashes = { aiweb: await getLatestCommitHash('adamlui/ai-web-extensions') }
59+
bump.log.working('\nFetching latest commit hash for adamlui/ai-web-extensions...\n')
60+
const latestCommitHashes = { aiweb: await bump.getLatestCommitHash('adamlui/ai-web-extensions') }
15261

15362
// Process each userscript
15463
let urlsUpdatedCnt = 0 ; let filesUpdatedCnt = 0
@@ -158,55 +67,55 @@
15867
let repoName = userJSfilePath.split('\\').pop().replace('.user.js', '')
15968
if (repoName.endsWith('-mode')) repoName = repoName.slice(0, -5) // for chatgpt-widescreen
16069

161-
log.working(`\nProcessing ${repoName}...\n`)
70+
bump.log.working(`\nProcessing ${repoName}...\n`)
16271

16372
// Fetch latest commit hash for repo/chromium/extension
16473
if (urlMap[userJSfilePath].some(url => url.includes(repoName))) {
16574
console.log('Fetching latest commit hash for Chromium extension...')
166-
latestCommitHashes.chromium = await getLatestCommitHash(`adamlui/${repoName}`, 'chromium/extension')
75+
latestCommitHashes.chromium = await bump.getLatestCommitHash(`adamlui/${repoName}`, 'chromium/extension')
16776
}
16877

16978
// Process each resource
17079
let fileUpdated = false
17180
for (const resURL of urlMap[userJSfilePath]) {
172-
if (!await isValidResource(resURL)) continue // to next resource
81+
if (!await bump.isValidResource(resURL)) continue // to next resource
17382
const resName = regEx.resName.exec(resURL)?.[0] || 'resource' // dir/filename for logs
17483

17584
// Compare/update commit hash
17685
let resLatestCommitHash = latestCommitHashes[resURL.includes(repoName) ? 'chromium' : 'aiweb']
17786
if (resLatestCommitHash.startsWith( // compare hashes
17887
regEx.hash.commit.exec(resURL)?.[2] || '')) { // commit hash didn't change...
179-
console.log(`${resName} already up-to-date!`) ; log.endedWithLineBreak = false
88+
console.log(`${resName} already up-to-date!`) ; bump.log.endedWithLineBreak = false
18089
continue // ...so skip resource
18190
}
18291
resLatestCommitHash = resLatestCommitHash.substring(0, 7) // abbr it
18392
let updatedURL = resURL.replace(regEx.hash.commit, `$1${resLatestCommitHash}`) // update hash
184-
if (!await isValidResource(updatedURL)) continue // to next resource
93+
if (!await bump.isValidResource(updatedURL)) continue // to next resource
18594

18695
// Generate/compare/update SRI hash
18796
console.log(`${ !log.endedWithLineBreak ? '\n' : '' }Generating SRI (SHA-256) hash for ${resName}...`)
188-
const newSRIhash = await generateSRIhash(updatedURL)
97+
const newSRIhash = await bump.generateSRIhash(updatedURL)
18998
if (regEx.hash.sri.exec(resURL)?.[0] == newSRIhash) { // SRI hash didn't change
190-
console.log(`${resName} already up-to-date!`) ; log.endedWithLineBreak = false
99+
console.log(`${resName} already up-to-date!`) ; bump.log.endedWithLineBreak = false
191100
continue // ...so skip resource
192101
}
193102
updatedURL = updatedURL.replace(regEx.hash.sri, newSRIhash) // update hash
194-
if (!await isValidResource(updatedURL)) continue // to next resource
103+
if (!await bump.isValidResource(updatedURL)) continue // to next resource
195104

196105
// Write updated URL to userscript
197106
console.log(`Writing updated URL for ${resName}...`)
198107
const userJScontent = fs.readFileSync(userJSfilePath, 'utf-8')
199108
fs.writeFileSync(userJSfilePath, userJScontent.replace(resURL, updatedURL), 'utf-8')
200-
log.success(`${resName} bumped!\n`) ; urlsUpdatedCnt++ ; fileUpdated = true
109+
bump.log.success(`${resName} bumped!\n`) ; urlsUpdatedCnt++ ; fileUpdated = true
201110
}
202111
if (fileUpdated) {
203112
console.log(`${ !log.endedWithLineBreak ? '\n' : '' }Bumping userscript version...`)
204-
bumpUserJSver(userJSfilePath) ; filesUpdatedCnt++
113+
bump.bumpUserJSver(userJSfilePath) ; filesUpdatedCnt++
205114
}
206115
}
207116

208117
// Log final summary
209-
log[urlsUpdatedCnt > 0 ? 'success' : 'info'](
118+
bump.log[urlsUpdatedCnt > 0 ? 'success' : 'info'](
210119
`\n${ urlsUpdatedCnt > 0 ? 'Success! ' : '' }${
211120
urlsUpdatedCnt} resource(s) bumped across ${filesUpdatedCnt} file(s).`
212121
)

0 commit comments

Comments
 (0)