@tkskto/vue-component-analyzer
Advanced tools
Comparing version 0.1.2 to 0.1.3
#!/usr/bin/env node | ||
const {version} = require('../package.json'); | ||
/** | ||
@@ -13,2 +11,4 @@ * Catch and report unexpected error. | ||
const {version} = require('../package.json'); | ||
console.error(`Something went wrong. component-analyzer: ${version}. follow error message.`); | ||
@@ -15,0 +15,0 @@ console.error(`${error.message}`); |
@@ -1,6 +0,1 @@ | ||
/*! | ||
@tkskto/vue-component-analyzer v0.1.2 | ||
https://github.com/tkskto/ | ||
Released under the MIT License. | ||
*/ | ||
class MyCustomEvent { | ||
@@ -101,3 +96,3 @@ constructor(type) { | ||
constructor() { | ||
super(...arguments); | ||
super(); | ||
this._data = { | ||
@@ -107,2 +102,9 @@ entries: [], | ||
}; | ||
this.getHowManyDaysAgo = (date) => { | ||
const time = date.getTime(); | ||
const diff = this._todayTime - time; | ||
return Math.floor(diff / 86400000); | ||
}; | ||
this._today = new Date(); | ||
this._todayTime = this._today.getTime(); | ||
} | ||
@@ -122,8 +124,9 @@ get data() { | ||
class Seed { | ||
constructor(file, level, index, count) { | ||
constructor(file, count, _model) { | ||
this._model = _model; | ||
this._children = []; | ||
this._name = file.name; | ||
this._props = file.props; | ||
this._level = level; | ||
this._index = index; | ||
this._fileSize = file.size; | ||
this._lastModifiedTime = file.lastModifiedTime; | ||
this._count = count; | ||
@@ -140,7 +143,25 @@ } | ||
} | ||
renderWithProps() { | ||
return `<details><summary>${this._name}</summary><pre>${JSON.stringify(this._props, null, '\t')}</pre></details>`; | ||
renderProps() { | ||
return this._props ? `<pre class="file__props">props: ${JSON.stringify(this._props, null, '\t')}</pre>` : ''; | ||
} | ||
renderMetaData() { | ||
const fileSize = (this._fileSize / 1024).toFixed(2); | ||
const lastUpdated = this._lastModifiedTime === 0 ? 0 : this._model.getHowManyDaysAgo(new Date(this._lastModifiedTime)); | ||
if (fileSize && lastUpdated) { | ||
return ` | ||
<span class="file__meta">FileSize: ${fileSize} KB</span> | ||
<span class="file__meta">LastUpdated: ${lastUpdated} days ago</span> | ||
`; | ||
} | ||
return ''; | ||
} | ||
renderDetails() { | ||
return `<details> | ||
<summary>${this._name}</summary> | ||
${this.renderProps()} | ||
${this.renderMetaData()} | ||
</details>`; | ||
} | ||
render() { | ||
const contents = this._props ? this.renderWithProps() : this._name; | ||
const contents = this.renderDetails(); | ||
let childHTML = ''; | ||
@@ -191,4 +212,4 @@ let seedClassName = ''; | ||
if (data) { | ||
const root = new Seed(entry, 0, 0, 0); | ||
this._tree.push(this.generateSeed(entry, root, 0)); | ||
const root = new Seed(entry, 0, this._model); | ||
this._tree.push(this.generateSeed(entry, root)); | ||
} | ||
@@ -201,3 +222,3 @@ } | ||
} | ||
generateSeed(data, seed, level) { | ||
generateSeed(data, seed) { | ||
const tree = []; | ||
@@ -209,5 +230,5 @@ const { children } = data; | ||
const child = children[i]; | ||
const childSeed = new Seed(child, level + 1, i, count[child.name]); | ||
const childSeed = new Seed(child, count[child.name], this._model); | ||
childSeeds.push(childSeed); | ||
this.generateSeed(child, childSeed, level + 1); | ||
this.generateSeed(child, childSeed); | ||
} | ||
@@ -214,0 +235,0 @@ seed.children = childSeeds; |
@@ -1,21 +0,262 @@ | ||
/** | ||
* see license.txt | ||
*/ | ||
/*! | ||
@tkskto/vue-component-analyzer v0.1.2 | ||
@tkskto/vue-component-analyzer v0.1.3 | ||
https://github.com/tkskto/ | ||
Released under the MIT License. | ||
dependencies: | ||
commander -- 6.1.0 | ||
ejs -- 3.1.5 | ||
express -- 4.17.1 | ||
globby -- 11.0.1 | ||
mkdirp -- 1.0.4 | ||
opener -- 1.5.2 | ||
vue-eslint-parser -- 7.1.1 | ||
ws -- 7.3.1 | ||
*/ | ||
'use strict'; | ||
var require$$0 = require('vue-eslint-parser'); | ||
var require$$1 = require('fs'); | ||
var path = require('path'); | ||
var http = require('http'); | ||
var require$$0$1 = require('ejs'); | ||
var express = require('express'); | ||
var webSocket = require('ws'); | ||
var opener = require('opener'); | ||
var mkdirp = require('mkdirp'); | ||
var commander = require('commander'); | ||
var globby = require('globby'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0); | ||
var require$$1__default = /*#__PURE__*/_interopDefaultLegacy(require$$1); | ||
var path__default = /*#__PURE__*/_interopDefaultLegacy(path); | ||
var http__default = /*#__PURE__*/_interopDefaultLegacy(http); | ||
var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$1); | ||
var express__default = /*#__PURE__*/_interopDefaultLegacy(express); | ||
var webSocket__default = /*#__PURE__*/_interopDefaultLegacy(webSocket); | ||
var opener__default = /*#__PURE__*/_interopDefaultLegacy(opener); | ||
var mkdirp__default = /*#__PURE__*/_interopDefaultLegacy(mkdirp); | ||
var commander__default = /*#__PURE__*/_interopDefaultLegacy(commander); | ||
var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby); | ||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | ||
function createCommonjsModule(fn, basedir, module) { | ||
return module = { | ||
path: basedir, | ||
exports: {}, | ||
require: function (path, base) { | ||
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); | ||
} | ||
}, fn(module, module.exports), module.exports; | ||
} | ||
function commonjsRequire () { | ||
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); | ||
} | ||
class FileCounter { | ||
constructor() { | ||
this._count = {}; | ||
} | ||
add(filename) { | ||
if (Object.prototype.hasOwnProperty.call(this._count, filename)) { | ||
this._count[filename]++; | ||
} | ||
else { | ||
this._count[filename] = 1; | ||
} | ||
} | ||
get count() { | ||
return this._count; | ||
} | ||
} | ||
var FileCounter_1 = FileCounter; | ||
var utils = createCommonjsModule(function (module, exports) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const utils_1 = require("./utils"); | ||
const server_1 = require("./server"); | ||
const fs_1 = require("fs"); | ||
const path_1 = tslib_1.__importDefault(require("path")); | ||
const mkdirp = require('mkdirp'); | ||
const commander = require('commander'); | ||
const globby = require('globby'); | ||
const { parse } = require$$0__default['default']; | ||
const { readFileSync, existsSync, statSync } = require$$1__default['default']; | ||
const { resolve, extname, dirname } = path__default['default']; | ||
const cwd = process.cwd(); | ||
const counter = new FileCounter_1(); | ||
const getImportDeclaration = (nodeArr) => { | ||
return nodeArr.filter((node) => node.type === 'ImportDeclaration'); | ||
}; | ||
const getPropsDeclaration = (tokens) => { | ||
let isPropsToken = false; | ||
let result = '{'; | ||
let closedCount = 0; | ||
const needQuotingTypes = ['Identifier', 'Boolean', 'Keyword']; | ||
for (const token of tokens) { | ||
const { type, value } = token; | ||
if (isPropsToken || (type === 'Identifier' && value === 'props')) { | ||
const needQuoting = needQuotingTypes.includes(type); | ||
isPropsToken = true; | ||
if (type === 'Punctuator') { | ||
if (value === '{') { | ||
closedCount++; | ||
} | ||
else if (value === '}') { | ||
closedCount--; | ||
if (result[result.length - 1] === ',') { | ||
result = result.slice(0, -1); | ||
} | ||
if (closedCount === 0) { | ||
result += '}'; | ||
break; | ||
} | ||
} | ||
} | ||
if (needQuoting) { | ||
result += '"'; | ||
} | ||
result += value.replace(/'/ug, '"'); | ||
if (needQuoting) { | ||
result += '"'; | ||
} | ||
} | ||
} | ||
return `${result}}`; | ||
}; | ||
const resolveFile = (_filename, _currentFileName) => { | ||
let filename = ''; | ||
if (_filename.startsWith('../')) { | ||
filename = resolve(dirname(_currentFileName), _filename); | ||
} | ||
else if (_filename.startsWith('./')) { | ||
filename = `${dirname(_currentFileName)}/${_filename.replace(/\.\/|/ug, '')}`; | ||
} | ||
else if (_filename.startsWith('~') || _filename.startsWith('@')) { | ||
filename = _filename.replace('~', '.').replace('@', '.'); | ||
} | ||
if (filename) { | ||
if (extname(filename) === '' && existsSync(`${filename}.vue`)) { | ||
return `${filename}.vue`; | ||
} | ||
} | ||
return filename; | ||
}; | ||
const getImportDeclarationTree = (fileName, isTest = false) => { | ||
const filename = resolve(cwd, fileName); | ||
const shortFilename = filename.replace(cwd, ''); | ||
const children = []; | ||
const result = { | ||
name: shortFilename, | ||
props: '', | ||
size: 0, | ||
lastModifiedTime: 0, | ||
children, | ||
}; | ||
console.log(`read ${filename}.`); | ||
counter.add(shortFilename); | ||
if (extname(filename) === '') { | ||
return result; | ||
} | ||
const stat = statSync(filename); | ||
if (!isTest) { | ||
result.lastModifiedTime = Number(stat.mtimeMs.toFixed(0)); | ||
} | ||
result.size = stat.size; | ||
if (extname(filename) !== '.vue') { | ||
return result; | ||
} | ||
try { | ||
const file = readFileSync(filename, 'utf-8'); | ||
const parserOption = { | ||
ecmaVersion: 2018, | ||
sourceType: 'module', | ||
}; | ||
const esLintProgram = parse(file, parserOption); | ||
if (esLintProgram.tokens) { | ||
const propsDeclaration = JSON.parse(getPropsDeclaration(esLintProgram.tokens)); | ||
if (propsDeclaration && propsDeclaration.props) { | ||
result.props = propsDeclaration.props; | ||
} | ||
} | ||
const body = getImportDeclaration(esLintProgram.body); | ||
for (let i = 0, len = body.length; i < len; i++) { | ||
const source = String(body[i].source.value); | ||
if (source) { | ||
const nextFilename = resolveFile(source, filename); | ||
if (nextFilename) { | ||
children.push(getImportDeclarationTree(nextFilename, isTest)); | ||
} | ||
} | ||
} | ||
} | ||
catch (err) { | ||
console.error(`Something went wrong with reading ${filename}`); | ||
console.error(err.message); | ||
} | ||
return result; | ||
}; | ||
exports.counter = counter; | ||
exports.getImportDeclarationTree = getImportDeclarationTree; | ||
}); | ||
var server = createCommonjsModule(function (module, exports) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const { renderFile } = require$$0__default$1['default']; | ||
const projectRoot = path__default['default'].resolve(__dirname, '..'); | ||
const startServer = (port, json) => { | ||
const HOST = '127.0.0.1'; | ||
const app = express__default['default'](); | ||
app.engine('ejs', renderFile); | ||
app.set('view engine', 'ejs'); | ||
app.set('views', `${projectRoot}/views`); | ||
app.use(express__default['default'].static(`${projectRoot}/`)); | ||
const server = http__default['default'].createServer(app); | ||
const wss = new webSocket__default['default'].Server({ | ||
server, | ||
}); | ||
app.use('/', (req, res) => { | ||
res.render('viewer', { | ||
mode: 'server', | ||
title: 'analyze report', | ||
enableWebSocket: true, | ||
}); | ||
}); | ||
server.listen(port, HOST, () => { | ||
const addressPort = server.address().port || port; | ||
const url = `http://${HOST}:${addressPort}/`; | ||
console.log(`Vue Component Analyzer is started at ${url}`); | ||
console.log('Use \'Ctrl+C\' to close it'); | ||
opener__default['default'](url); | ||
wss.on('connection', (ws) => { | ||
wss.clients.forEach((client) => { | ||
client.send(JSON.stringify(json)); | ||
}); | ||
ws.addEventListener('error', () => { | ||
console.error('Something went to wrong on web socket.'); | ||
}); | ||
}); | ||
}); | ||
}; | ||
exports.startServer = startServer; | ||
}); | ||
var __awaiter = (commonjsGlobal && commonjsGlobal.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
const { getImportDeclarationTree, counter } = utils; | ||
const { startServer } = server; | ||
const { writeFileSync } = require$$1__default['default']; | ||
const FORMAT = { | ||
@@ -27,4 +268,4 @@ BROWSER: 'browser', | ||
function writeFileExtra(filename, data) { | ||
mkdirp(path_1.default.dirname(filename)).then(() => { | ||
fs_1.writeFileSync(filename, data); | ||
mkdirp__default['default'](path__default['default'].dirname(filename)).then(() => { | ||
writeFileSync(filename, data); | ||
}).catch((err) => { | ||
@@ -36,13 +277,13 @@ if (err) { | ||
} | ||
(async () => { | ||
(() => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
commander.option('--dir [dir]', 'root directory of src.', 'src'); | ||
commander.option('-f, --format [type]', 'Add the specified type of report [browser, json or both]', FORMAT.BROWSER); | ||
commander.option('-o, --out [dir]', 'output directory (enable with setting --format option to "json" or "both")', 'out'); | ||
commander.option('-p, --port [number]', 'select a port number for the local server', '8888'); | ||
const argv = commander.parse(process.argv); | ||
commander__default['default'].option('--dir [dir]', 'root directory of src.', 'src'); | ||
commander__default['default'].option('-f, --format [type]', 'Add the specified type of report [browser, json or both]', FORMAT.BROWSER); | ||
commander__default['default'].option('-o, --out [dir]', 'output directory (enable with setting --format option to "json" or "both")', 'out'); | ||
commander__default['default'].option('-p, --port [number]', 'select a port number for the local server', '8888'); | ||
const argv = commander__default['default'].parse(process.argv); | ||
if (argv.format !== FORMAT.BROWSER && argv.format !== FORMAT.JSON && argv.format !== FORMAT.BOTH) { | ||
console.error(`not support ${argv.format} format.`); | ||
} | ||
const entries = await globby([argv.dir], { | ||
const entries = yield globby__default['default']([argv.dir], { | ||
expandDirectories: { | ||
@@ -55,3 +296,3 @@ extensions: ['vue'], | ||
const entryFile = entries[i]; | ||
const children = utils_1.getImportDeclarationTree(entryFile); | ||
const children = getImportDeclarationTree(entryFile); | ||
entriesData.push(children); | ||
@@ -61,13 +302,13 @@ } | ||
entries: entriesData, | ||
count: utils_1.counter.count, | ||
count: counter.count, | ||
}; | ||
if (argv.format === FORMAT.BOTH) { | ||
server_1.startServer(argv.port, result); | ||
writeFileExtra(path_1.default.resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
startServer(argv.port, result); | ||
writeFileExtra(path__default['default'].resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
} | ||
else if (argv.format === FORMAT.BROWSER) { | ||
server_1.startServer(argv.port, result); | ||
startServer(argv.port, result); | ||
} | ||
else if (argv.format === FORMAT.JSON) { | ||
writeFileExtra(path_1.default.resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
writeFileExtra(path__default['default'].resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
} | ||
@@ -79,2 +320,8 @@ console.log('finished analyzing.'); | ||
} | ||
})(); | ||
}))(); | ||
var _temp = { | ||
}; | ||
module.exports = _temp; |
{ | ||
"name": "@tkskto/vue-component-analyzer", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "Analyze dependency tree for Vue.js SFC (Single File Component)", | ||
@@ -11,4 +11,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"dev": "rollup --config -w", | ||
"build": "rollup --config", | ||
"build": "tsc -p tsconfig.json && rollup --config", | ||
"lint": "eslint -c .eslintrc.json src", | ||
@@ -40,4 +39,4 @@ "cover": "npm run cover:test && npm run cover:report", | ||
"files": [ | ||
"bin", | ||
"dist", | ||
"bin", | ||
"types", | ||
@@ -44,0 +43,0 @@ "views" |
@@ -5,2 +5,4 @@ declare namespace vueComponentAnalyzer { | ||
props: string, | ||
size: number, | ||
lastModifiedTime: number, | ||
children: FileReport[] | ||
@@ -14,5 +16,1 @@ } | ||
} | ||
interface Window { | ||
enableWebSocket: boolean; | ||
} |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
spdx disjunction for an artifact's license information
Licensespdx disjunction for an artifact's license information
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
spdx disjunction for an artifact's license information
Licensespdx disjunction for an artifact's license information
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license
Found 1 instance in 1 package
27600
1
100
737
1
10
2