Skip to content

Instantly share code, notes, and snippets.

@tai-fukaya
Last active July 6, 2022 08:11
Show Gist options
  • Save tai-fukaya/2d096715b742f6b03e319ad18737f32f to your computer and use it in GitHub Desktop.
Save tai-fukaya/2d096715b742f6b03e319ad18737f32f to your computer and use it in GitHub Desktop.
TypeScriptで作成したコンポーネントの依存関係をさっと見るためのツール

TypeScriptで作成したコンポーネントの依存関係をさっと見るためのツール

HOW TO USE

$ cd <project_folder>
$ yarn build
$ cd -
$ node parser.js referenced <project_folder>/tsconfig.tsbuildinfo --parent=organisms/component.vue
const fs = require('fs')
const usage = "node parser.js referenced|exported path --reverse(-r) --depth(-d)=0 --last(-l) --include(-i)=path --exclude(-e)=path --parent(-p)=path --json(-j)"
let options = {
target: "referencedMap",
isReverse: false,
isPrintLastOnly: false,
isPrintJson: false,
printDepth: null,
parent: "",
includeConditions: ["/src/"],
excludeConditions: ["/node_modules/"]
}
let path = ''
let arguments = process.argv.slice(2)
if (arguments.length === 0) {
console.log(usage)
return
}
if (arguments[0] === 'exported') {
options.target = 'exportedModulesMap'
}
let isUpdateIncludeConditions = false
let isUpdateExcludeConditions = false
arguments.slice(1).forEach(argument => {
if (argument[0] === '-') {
let splitted = argument.split("=")
switch (splitted[0]) {
case '--reverse':
case '-r':
options.isReverse = true
break
case '--last':
case '-l':
options.isPrintLastOnly = true
break
case '--json':
case '-j':
options.isPrintJson = true
break
case '--depth':
case '-d':
options.printDepth = parseInt(splitted[1])
break
case '--parent':
case '-p':
options.parent = splitted[1]
break
case '--include':
case '-i':
if (!isUpdateIncludeConditions) options.includeConditions = []
if (splitted.length > 1) options.includeConditions.push(splitted[1])
isUpdateIncludeConditions = true
break
case '--exclude':
case '-e':
if (!isUpdateExcludeConditions) options.excludeConditions = []
if (splitted.length > 1) options.excludeConditions.push(splitted[1])
isUpdateExcludeConditions = true
break
}
} else {
path = argument
}
})
if (path.length === 0) {
console.log(usage)
return
}
// よみこみ
function readFile(path) {
let buff = null
try {
buff = fs.readFileSync(path, "utf8");
}
catch(e) {
console.log('ERROR: readFile', e.message);
}
return buff
}
// 絞込み
function isInclude(filePath) {
const includes = options.includeConditions.length === 0 || options.includeConditions.some(w => filePath.indexOf(w) > -1)
const excludes = options.excludeConditions.some(w => filePath.indexOf(w) > -1)
return includes && !excludes
}
function narrowing(map) {
for (let k in map) {
if (isInclude(k)) {
map[k] = map[k].filter(path => isInclude(path))
} else {
delete map[k]
}
}
}
// 反転
function reverse(map) {
let rmap = {}
for (let k in map) {
let parent = k
map[k].forEach(child => {
if (child in rmap) {
rmap[child].push(parent)
} else {
rmap[child] = [parent]
}
});
}
return rmap
}
// ツリー
function generateTree(map) {
let ret = {}
// {parent: { child: {}}}
for (let k in map) {
if (k.indexOf(options.parent) > -1) {
ret[k] = search(map, k, 0)
}
}
return ret
}
let memo = {}
let count = 0
function search(map, key, level) {
let ret = {}
count++
// if (level >= options.printDepth) return ret
let childMap = map[key]
for (let i in childMap) {
let child = childMap[i]
// 同じやつがいる
if (child === key) continue
if (child in memo) {
ret[child] = memo[child]
} else {
memo[child] = {}
memo[child] = search(map, child, level + 1)
ret[child] = memo[child]
}
}
return ret
}
// プリント
function printMap(map, level) {
let blank = ''
const noPrintNext = level === options.printDepth
if (level > 0) {
blank = '|'.repeat(level-1) + '-'
}
for (let key in map) {
let childMap = map[key]
let currentBlank = blank
if(noPrintNext) {
if (Object.keys(childMap).length) {
currentBlank = currentBlank.replace('-', '+')
} else {
currentBlank = currentBlank.replace('-', ' ')
}
} else if (!Object.keys(childMap).length) {
currentBlank = currentBlank.replace('-', ' ')
}
console.log(`${currentBlank}${key}`)
if (!noPrintNext) {
printMap(childMap, level + 1)
}
}
}
// 最後だけ、プリント
let children = {}
function searchChild(map) {
for (let key in map) {
let childMap = map[key]
if (Object.keys(map[key]).length) {
searchChild(childMap)
} else {
children[key] = key
}
}
}
const buildinfo = JSON.parse(readFile(path))
let targetMap = buildinfo.program[options.target]
narrowing(targetMap)
if (options.isReverse) {
targetMap = reverse(targetMap)
}
let treeMap = generateTree(targetMap)
// console.log(count)
if (options.isPrintLastOnly) {
searchChild(treeMap)
sortedLastComponents = Object.keys(children).sort()
if (options.isPrintJson) {
console.log(JSON.stringify(sortedLastComponents))
} else {
for (let c of sortedLastComponents) {
console.log(c)
}
}
} else if (options.isPrintJson) {
console.log(JSON.stringify(treeMap))
} else {
printMap(treeMap, 0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment