mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Revert "Revert "[web] Convert models and self-referential test files to ESM "" GitOrigin-RevId: f64000ae31d298b075a8722dfc51f294c71bc021
148 lines
4.0 KiB
JavaScript
148 lines
4.0 KiB
JavaScript
/* eslint-disable */
|
|
import { extractImports, findJSAndImports } from './esm-check-migration.mjs'
|
|
import path from 'node:path'
|
|
import fs from 'node:fs'
|
|
|
|
const imports = await findJSAndImports(
|
|
['app', 'modules'].map(dir => path.resolve(dir))
|
|
)
|
|
|
|
const entryPoint = fs.existsSync('app.js') ? 'app.js' : 'app.mjs'
|
|
imports.set(path.resolve(entryPoint), extractImports(entryPoint))
|
|
|
|
const moduleImports = new Map()
|
|
imports.forEach((deps, module) => {
|
|
for (const dep of deps) {
|
|
if (!moduleImports.has(dep)) {
|
|
moduleImports.set(dep, new Set())
|
|
}
|
|
moduleImports.set(dep, moduleImports.get(dep).add(module))
|
|
}
|
|
})
|
|
|
|
const soloImports = new Map()
|
|
moduleImports.forEach((importedBy, module) => {
|
|
if (importedBy.size === 1) {
|
|
soloImports.set(module, [...importedBy][0])
|
|
}
|
|
})
|
|
|
|
console.log(soloImports)
|
|
|
|
for (const [module, importedBy] of soloImports) {
|
|
if (!moduleImports.has(importedBy)) {
|
|
console.log(
|
|
`${module} is only imported by ${importedBy}, which has no other imports`
|
|
)
|
|
}
|
|
if (soloImports.has(importedBy)) {
|
|
console.log(
|
|
`${module} is only imported by ${importedBy}, which is only imported by ${soloImports.get(importedBy)}`
|
|
)
|
|
}
|
|
const chains = findDependencyChainsToTarget(imports, module)
|
|
const conversionsToMake = chains.reduce((conversions, chain) => {
|
|
chain.forEach(dep => {
|
|
conversions.add(dep)
|
|
})
|
|
return conversions
|
|
}, new Set())
|
|
|
|
if (conversionsToMake.length < 10) {
|
|
console.log(
|
|
`To convert ${module}, would need to convert: ${[...conversionsToMake].length}`
|
|
)
|
|
}
|
|
}
|
|
|
|
// --- Circular dependency detection ---
|
|
function findCircularDependencies(importsMap) {
|
|
const cycles = []
|
|
const visited = new Set()
|
|
const stack = []
|
|
|
|
function dfs(file, pathStack) {
|
|
if (pathStack.includes(file)) {
|
|
// Cycle detected
|
|
const cycleStart = pathStack.indexOf(file)
|
|
cycles.push(pathStack.slice(cycleStart).concat(file))
|
|
return
|
|
}
|
|
if (!importsMap.has(file)) return
|
|
pathStack.push(file)
|
|
for (const imp of importsMap.get(file)) {
|
|
const resolvedImp = path.resolve(imp)
|
|
dfs(resolvedImp, pathStack)
|
|
}
|
|
pathStack.pop()
|
|
}
|
|
|
|
for (const file of importsMap.keys()) {
|
|
dfs(file, [])
|
|
}
|
|
return cycles
|
|
}
|
|
|
|
const cycles = findCircularDependencies(imports)
|
|
if (cycles.length > 0) {
|
|
console.log('Circular dependencies found:')
|
|
for (const cycle of cycles) {
|
|
console.log(' ' + cycle.join(' -> '))
|
|
}
|
|
} else {
|
|
console.log('No circular dependencies detected.')
|
|
}
|
|
|
|
// --- Find all chains of dependencies to a target file ---
|
|
function findDependencyChainsToTarget(importsMap, targetPath) {
|
|
const chains = []
|
|
const resolvedTarget = path.resolve(targetPath)
|
|
|
|
function dfs(current, pathStack) {
|
|
if (pathStack.includes(current)) return // avoid cycles
|
|
pathStack.push(current)
|
|
if (current === resolvedTarget) {
|
|
chains.push([...pathStack])
|
|
pathStack.pop()
|
|
return
|
|
}
|
|
if (!importsMap.has(current)) {
|
|
pathStack.pop()
|
|
return
|
|
}
|
|
for (const imp of importsMap.get(current)) {
|
|
const resolvedImp = path.resolve(imp)
|
|
dfs(resolvedImp, pathStack)
|
|
}
|
|
pathStack.pop()
|
|
}
|
|
|
|
for (const file of importsMap.keys()) {
|
|
if (file === resolvedTarget) continue // skip self
|
|
dfs(file, [])
|
|
}
|
|
return chains
|
|
}
|
|
|
|
// Example usage: set your target file path here
|
|
const targetFile =
|
|
'/Users/arumble/Documents/Projects/internal/services/web/app/src/Features/Analytics/AnalyticsManager.js' // <-- change to your target
|
|
const chains = findDependencyChainsToTarget(imports, targetFile)
|
|
if (chains.length > 0) {
|
|
console.log(`Dependency chains leading to ${targetFile}:`)
|
|
for (const chain of chains) {
|
|
console.log(' ' + chain.join(' -> '))
|
|
}
|
|
} else {
|
|
console.log(`No dependency chains found leading to ${targetFile}.`)
|
|
}
|
|
|
|
const conversionsToMake = chains.reduce((conversions, chain) => {
|
|
chain.forEach(dep => {
|
|
conversions.add(dep)
|
|
})
|
|
return conversions
|
|
}, new Set())
|
|
|
|
console.log([...conversionsToMake].join(' '))
|