scripts/fixDependencies.mjs (192 lines of code) (raw):

/*eslint-env node*/ import { argv } from 'process' import * as fs from 'fs' import path from 'path' import { execSync } from 'child_process' import { request } from 'https' import { createInterface } from 'readline' console.log(argv) console.log(process.env.PWD) // 不处理的package import packageBlacklist from './ignore.mjs' packageBlacklist.push('/examples') try { const gsiInfo = await fetchGsiInfo() const packagesStr = execSync('npx lerna ls --json --all').toString() const packagesAll = JSON.parse(packagesStr) // 黑名单过滤掉 const packagesArr = packagesAll.filter((pac) => { let inBL = false packageBlacklist.forEach((rule) => { inBL = inBL || pac.location.includes(rule) }) return !inBL }) const gsiLatestVer = gsiInfo['dist-tags']['latest'] if (gsiLatestVer === undefined) { throw new Error('GSI lastest version not found') } const gsiPkgJson = gsiInfo.versions[gsiLatestVer] const lastestGsiPkgs = gsiPkgJson.dependencies console.log('lastestGsiPkgs') console.log(lastestGsiPkgs) packagesArr.forEach(async (pkg) => { const { name, location } = pkg const imports = await getPackageImports(path.resolve(location, './src')) const gsiImports = imports.gsi const otherImports = imports.other console.log(`package: ${name}`) console.log(`gsi imports: ${gsiImports}`) console.log(`other imports: ${otherImports}`) const pkgJsonPath = path.resolve(location, './package.json') const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath).toString()) const dependencies = pkgJson.dependencies || {} // delete @gs.i/all if (dependencies['@gs.i/all']) { delete dependencies['@gs.i/all'] } // check unused dependencies Object.keys(dependencies).forEach((dependency) => { if (!gsiImports.includes(dependency) && !otherImports.includes(dependency)) { delete dependencies[dependency] console.log(`removed unused dependency: ${dependency}`) } }) // add imported gsi pkgs gsiImports.forEach((gsiPkg) => { dependencies[gsiPkg] = lastestGsiPkgs[gsiPkg] }) // write file fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 4)) console.log(`package.json modification done. \n--------`) }) } catch (e) { console.log('Script error', e) } function fetchGsiInfo() { return new Promise((resolve, reject) => { const req = request('https://registry.npmjs.org/@gs.i/all', (res) => { let data = '' res.on('data', (chunk) => { data += chunk.toString() }) res.on('close', () => { const pkgJson = JSON.parse(data) resolve(pkgJson) }) }) req.on('error', (error) => { reject(error) }) req.end() }) } async function getPackageImports(pathStr) { return new Promise((resolve) => { const gsiImports = new Set() const otherImports = new Set() const pendings = [] const subdirs = fs.readdirSync(pathStr) subdirs.forEach((dir) => { if (dir === 'node_modules') return const absolute = path.resolve(pathStr, dir) walkDir(absolute, (file) => { pendings.push(getTsImports(file)) }) }) Promise.all(pendings).then((importsList) => { importsList.forEach((imports) => { imports.gsi.forEach((pkgname) => { gsiImports.add(pkgname) }) imports.other.forEach((pkgname) => { otherImports.add(pkgname) }) }) resolve({ gsi: Array.from(gsiImports), other: Array.from(otherImports), }) }) }) } function walkDir(dir, fileCallback) { const states = fs.statSync(dir) if (states.isFile()) { fileCallback(dir) return } if (states.isDirectory()) { fs.readdirSync(dir).forEach((file) => { const absolute = path.join(dir, file) const states = fs.statSync(absolute) if (states.isDirectory()) { return walkDir(absolute, fileCallback) } else if (states.isFile()) { fileCallback(absolute) } }) } } const ignorePrefix = ['.', 'worker-loader!'] function getTsImports(tsFile) { return new Promise((resolve) => { const otherImports = new Set() const gsiImports = new Set() const rd = createInterface({ input: fs.createReadStream(tsFile), }) rd.on('line', (line) => { line = line.trimStart().trimEnd() if ( line.startsWith('//') || line.startsWith('/*') || line.startsWith('*') || line.startsWith('*/') ) { return } if (line.includes(` from '`)) { const pkgFullName = line.substring( line.indexOf(` from '`) + ` from '`.length, line.length - 1 ) for (let i = 0; i < ignorePrefix.length; i++) { const prefix = ignorePrefix[i] if (pkgFullName.startsWith(prefix)) { return } } if (pkgFullName.startsWith('@gs.i')) { gsiImports.add(pkgFullName) } else { if (pkgFullName.startsWith('@')) { const firstIndex = pkgFullName.indexOf('/') const secondIndex = pkgFullName.indexOf('/', firstIndex + 1) if (secondIndex < 0) { otherImports.add(pkgFullName) } else { const pkgname = pkgFullName.substring(0, secondIndex) otherImports.add(pkgname) } } else { const firstIndex = pkgFullName.indexOf('/') if (firstIndex < 0) { otherImports.add(pkgFullName) } else { const pkgname = pkgFullName.substring(0, firstIndex) otherImports.add(pkgname) } } } } }) rd.on('close', () => { const imports = { gsi: Array.from(gsiImports), other: Array.from(otherImports), } resolve(imports) }) }) }