@tkskto/vue-component-analyzer
Advanced tools
Comparing version 0.3.1 to 0.3.2
# Changelog | ||
## 0.3.2 | ||
### enhancement | ||
- add icon. | ||
### Chores | ||
- \#110 update `vue-eslint-parser` 7.7.2 to 7.9.0 | ||
- \#103 update `ws` 7.5.2 to 7.5.3 | ||
## 0.3.1 | ||
@@ -4,0 +15,0 @@ |
@@ -1,472 +0,1 @@ | ||
class MyCustomEvent { | ||
constructor(type) { | ||
this.type = type; | ||
this.currentTarget = null; | ||
} | ||
} | ||
MyCustomEvent.COMPLETE = 'complete'; | ||
MyCustomEvent.CHANGE_PROPERTY = 'changeProperty'; | ||
class CustomEventListener { | ||
constructor(type, handler, priority = 0) { | ||
this.type = type; | ||
this.handler = handler; | ||
this.priority = priority; | ||
} | ||
equalCurrentListener(type, handler) { | ||
return this.type === type && this.handler === handler; | ||
} | ||
} | ||
class CustomEventDispatcher { | ||
constructor() { | ||
this.listeners = {}; | ||
} | ||
dispatchEvent(event) { | ||
let e; | ||
let type; | ||
if (event instanceof MyCustomEvent) { | ||
type = event.type; | ||
e = event; | ||
} | ||
else { | ||
type = event; | ||
e = new MyCustomEvent(type); | ||
} | ||
if (this.listeners[type] !== null) { | ||
const len = this.listeners[type].length; | ||
e.currentTarget = this; | ||
for (let i = 0; i < len; i++) { | ||
const listener = this.listeners[type][i]; | ||
try { | ||
listener.handler(e); | ||
} | ||
catch (error) { | ||
if (window.console) { | ||
console.error(error.stack); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
console.warn('implement "addEventListener" before dispatch'); | ||
} | ||
} | ||
addEventListener(type, callback, priority = 0) { | ||
if (!this.listeners[type]) { | ||
this.listeners[type] = []; | ||
} | ||
this.listeners[type].push(new CustomEventListener(type, callback, priority)); | ||
this.listeners[type].sort((listener1, listener2) => listener2.priority - listener1.priority); | ||
} | ||
removeEventListener(type, callback) { | ||
if (this.hasEventListener(type, callback)) { | ||
for (let i = 0; i < this.listeners[type].length; i++) { | ||
const listener = this.listeners[type][i]; | ||
if (listener.equalCurrentListener(type, callback)) { | ||
this.listeners[type].splice(i, 1); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
clearEventListener() { | ||
this.listeners = {}; | ||
} | ||
containEventListener(type) { | ||
if (!this.listeners[type]) { | ||
return false; | ||
} | ||
return this.listeners[type].length > 0; | ||
} | ||
hasEventListener(type, callback) { | ||
if (!this.listeners[type]) { | ||
return false; | ||
} | ||
for (let i = 0; i < this.listeners[type].length; i++) { | ||
const listener = this.listeners[type][i]; | ||
if (listener.equalCurrentListener(type, callback)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
class Model extends CustomEventDispatcher { | ||
constructor() { | ||
super(); | ||
this._data = { | ||
entries: [], | ||
count: {}, | ||
}; | ||
this._viewType = 'GRAPH'; | ||
this._visibleSettings = false; | ||
this._visibleProps = true; | ||
this._visibleFileSize = true; | ||
this._visibleLastUpdated = true; | ||
this._visibleReferenceCount = true; | ||
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(); | ||
} | ||
get data() { | ||
return this._data; | ||
} | ||
set data(value) { | ||
this._data = value; | ||
this.dispatchEvent(Model.EVENT.DATA_UPDATE); | ||
} | ||
get viewType() { | ||
return this._viewType; | ||
} | ||
set viewType(value) { | ||
this._viewType = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
get visibleSettings() { | ||
return this._visibleSettings; | ||
} | ||
set visibleSettings(value) { | ||
this._visibleSettings = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
get visibleProps() { | ||
return this._visibleProps; | ||
} | ||
set visibleProps(value) { | ||
this._visibleProps = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
get visibleFileSize() { | ||
return this._visibleFileSize; | ||
} | ||
set visibleFileSize(value) { | ||
this._visibleFileSize = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
get visibleLastUpdated() { | ||
return this._visibleLastUpdated; | ||
} | ||
set visibleLastUpdated(value) { | ||
this._visibleLastUpdated = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
get visibleReferenceCount() { | ||
return this._visibleReferenceCount; | ||
} | ||
set visibleReferenceCount(value) { | ||
this._visibleReferenceCount = value; | ||
this.dispatchEvent(Model.EVENT.SETTING_CHANGED); | ||
} | ||
} | ||
Model.EVENT = { | ||
DATA_UPDATE: 'dataUpdate', | ||
SETTING_CHANGED: 'settingChanged', | ||
}; | ||
class Seed { | ||
constructor(file, count, _model) { | ||
this._model = _model; | ||
this._children = []; | ||
this._name = file.name; | ||
this._props = file.props; | ||
this._fileSize = file.size; | ||
this._lastModifiedTime = file.lastModifiedTime; | ||
this._count = count; | ||
} | ||
renderChildren() { | ||
let html = ''; | ||
for (let i = 0, len = this._children.length; i < len; i++) { | ||
html += this._children[i].render(); | ||
} | ||
return `<div class="group"> | ||
${html} | ||
</div>`; | ||
} | ||
renderProps() { | ||
return this._props ? `<pre class="file__props">props: ${JSON.stringify(this._props, null, '\t')}</pre>` : ''; | ||
} | ||
renderMetaData() { | ||
let metaString = ''; | ||
const fileSize = (this._fileSize / 1024).toFixed(2); | ||
const lastUpdated = this._lastModifiedTime === 0 ? 0 : this._model.getHowManyDaysAgo(new Date(this._lastModifiedTime)); | ||
if (fileSize) { | ||
metaString += `<span class="file__meta meta__fileSize">FileSize: ${fileSize} KB</span>`; | ||
} | ||
metaString += `<span class="file__meta meta__lastUpdated">LastUpdated: ${lastUpdated} days ago</span>`; | ||
return metaString; | ||
} | ||
renderDetails() { | ||
return `<details class="detail"> | ||
<summary>${this._name}</summary> | ||
${this.renderProps()} | ||
${this.renderMetaData()} | ||
</details>`; | ||
} | ||
render() { | ||
const contents = this.renderDetails(); | ||
let childHTML = ''; | ||
let seedClassName = ''; | ||
if (this._children.length > 0) { | ||
childHTML = this.renderChildren(); | ||
} | ||
else { | ||
seedClassName = ' -no-child'; | ||
} | ||
return `<div class="seed${seedClassName}"> | ||
<div class="file"> | ||
<div class="filename"> | ||
<div class="file__text">${contents}</div> | ||
${this.getCountText()} | ||
</div> | ||
</div> | ||
${childHTML} | ||
</div>`; | ||
} | ||
getCountText() { | ||
if (this._count === 0) { | ||
return ''; | ||
} | ||
else if (this._count === 1) { | ||
return '<span class="file__count">1 time referenced.</span>'; | ||
} | ||
return `<span class="file__count">${this._count} times referenced.</span>`; | ||
} | ||
get children() { | ||
return this._children; | ||
} | ||
set children(value) { | ||
this._children = value; | ||
} | ||
} | ||
class Renderer { | ||
constructor(_model) { | ||
this._model = _model; | ||
this._tree = []; | ||
this.ready = () => { | ||
if ('GRAPH' === this._model.viewType) { | ||
const { data } = this._model; | ||
const { entries } = data; | ||
for (let i = 0, len = entries.length; i < len; i++) { | ||
const entry = entries[i]; | ||
if (data) { | ||
const root = new Seed(entry, 0, this._model); | ||
this._tree.push(this.generateSeed(entry, root)); | ||
} | ||
} | ||
} | ||
this.render(); | ||
}; | ||
this._app = document.getElementById('app'); | ||
_model.addEventListener(Model.EVENT.DATA_UPDATE, this.ready); | ||
} | ||
generateSeed(data, seed) { | ||
const tree = []; | ||
const { children } = data; | ||
const childSeeds = []; | ||
const { count } = this._model.data; | ||
for (let i = 0, len = children.length; i < len; i++) { | ||
const child = children[i]; | ||
const childSeed = new Seed(child, count[child.name], this._model); | ||
childSeeds.push(childSeed); | ||
this.generateSeed(child, childSeed); | ||
} | ||
seed.children = childSeeds; | ||
tree.push(seed); | ||
return tree; | ||
} | ||
renderLine(name, level, isLast) { | ||
let line = ' '; | ||
for (let i = 0; i < level; i++) { | ||
line += '│ '; | ||
} | ||
line += isLast ? '└─ ' : '├─ '; | ||
line += name; | ||
return `${line}\n`; | ||
} | ||
renderEntry(entry, level) { | ||
let result = ''; | ||
for (let i = 0, len = entry.children.length; i < len; i++) { | ||
const child = entry.children[i]; | ||
result += this.renderLine(child.name, level, i === (len - 1)); | ||
result += this.renderEntry(child, level + 1); | ||
} | ||
return result; | ||
} | ||
render() { | ||
let html = ''; | ||
for (let i = 0, len = this._tree.length; i < len; i++) { | ||
const [root] = this._tree[i]; | ||
html += root.render(); | ||
} | ||
html = `<div class="root html">${html}</div>`; | ||
const { entries } = this._model.data; | ||
let text = ''; | ||
for (let i = 0, len = entries.length; i < len; i++) { | ||
const entry = entries[i]; | ||
text += `${entry.name}\n`; | ||
text += this.renderEntry(entries[i], 0); | ||
if (i < len - 1) { | ||
text += '\n'; | ||
} | ||
} | ||
text = `<div class="root text"><pre class="tree">${text}</pre></div>`; | ||
if (this._app) { | ||
this._app.innerHTML = html + text; | ||
} | ||
} | ||
} | ||
class VisibleSwitcher { | ||
constructor(_elm, _model) { | ||
this._elm = _elm; | ||
this._model = _model; | ||
this._type = _elm.dataset.settingName; | ||
_elm.addEventListener('change', this.onChange.bind(this)); | ||
} | ||
onChange() { | ||
switch (this._type) { | ||
case 'props': | ||
this._model.visibleProps = this._elm.checked; | ||
break; | ||
case 'fileSize': | ||
this._model.visibleFileSize = this._elm.checked; | ||
break; | ||
case 'lastUpdated': | ||
this._model.visibleLastUpdated = this._elm.checked; | ||
break; | ||
case 'referenceCount': | ||
this._model.visibleReferenceCount = this._elm.checked; | ||
break; | ||
default: | ||
throw new Error(`not supported type: ${this._type}`); | ||
} | ||
} | ||
} | ||
class ViewSwitcher { | ||
constructor(_elm, _type, _model) { | ||
this._elm = _elm; | ||
this._type = _type; | ||
this._model = _model; | ||
_elm.addEventListener('change', this.onChange.bind(this)); | ||
} | ||
onChange() { | ||
this._model.viewType = this._type; | ||
} | ||
} | ||
const setSettings = function (model) { | ||
const { body } = document; | ||
const btnSwitchSettings = document.getElementById('btn-settings'); | ||
const nodeListOfSwitch = body.querySelectorAll('.js-settings-toggle'); | ||
const switcherElmForGraph = document.getElementById('js-view-switch-graph'); | ||
const switcherElmForText = document.getElementById('js-view-switch-text'); | ||
new ViewSwitcher(switcherElmForGraph, 'GRAPH', model); | ||
new ViewSwitcher(switcherElmForText, 'TEXT', model); | ||
const onSettingsChanged = function () { | ||
body.className = `${model.viewType}`; | ||
if (model.visibleSettings) { | ||
body.classList.add('show-settings'); | ||
} | ||
if (!model.visibleProps) { | ||
body.classList.add('no-props'); | ||
} | ||
if (!model.visibleFileSize) { | ||
body.classList.add('no-fileSize'); | ||
} | ||
if (!model.visibleLastUpdated) { | ||
body.classList.add('no-lastUpdated'); | ||
} | ||
if (!model.visibleReferenceCount) { | ||
body.classList.add('no-referenceCount'); | ||
} | ||
}; | ||
nodeListOfSwitch.forEach((node) => { | ||
new VisibleSwitcher(node, model); | ||
}); | ||
model.addEventListener(Model.EVENT.SETTING_CHANGED, onSettingsChanged); | ||
if (btnSwitchSettings) { | ||
btnSwitchSettings.addEventListener('click', () => { | ||
model.visibleSettings = !model.visibleSettings; | ||
}); | ||
} | ||
onSettingsChanged(); | ||
}; | ||
class SeedOpenStateSwitcher { | ||
constructor(_button, model) { | ||
this._isOpen = false; | ||
this._details = null; | ||
this._textElement = document.getElementById('btn-toggle-visible-state-text'); | ||
_button.addEventListener('click', this.onClick.bind(this)); | ||
model.addEventListener(Model.EVENT.DATA_UPDATE, this.onDataUpdated.bind(this)); | ||
} | ||
open() { | ||
if (this._details) { | ||
this._details.forEach((detail) => { | ||
detail.open = true; | ||
}); | ||
} | ||
if (this._textElement) { | ||
this._textElement.textContent = 'collapse all'; | ||
} | ||
} | ||
close() { | ||
if (this._details) { | ||
this._details.forEach((detail) => { | ||
detail.open = false; | ||
}); | ||
} | ||
if (this._textElement) { | ||
this._textElement.textContent = 'expand all'; | ||
} | ||
} | ||
onClick() { | ||
this._isOpen = !this._isOpen; | ||
if (this._isOpen) { | ||
this.open(); | ||
} | ||
else { | ||
this.close(); | ||
} | ||
} | ||
onDataUpdated() { | ||
this._details = document.querySelectorAll('.detail'); | ||
} | ||
} | ||
const setSeedOpenStateSwitcher = (model) => { | ||
const btn = document.getElementById('btn-toggle-visible-state'); | ||
if (btn) { | ||
new SeedOpenStateSwitcher(btn, model); | ||
} | ||
}; | ||
const model = new Model(); | ||
new Renderer(model); | ||
let ws; | ||
try { | ||
if (window.enableWebSocket) { | ||
ws = new WebSocket(`ws://${location.host}`); | ||
} | ||
} | ||
catch (err) { | ||
console.warn('Couldn\'t connect to analyzer websocket server so you\'ll have to reload page manually to see updates in the treemap'); | ||
} | ||
window.addEventListener('load', () => { | ||
if (ws) { | ||
ws.addEventListener('message', (event) => { | ||
const msg = JSON.parse(event.data); | ||
setSeedOpenStateSwitcher(model); | ||
model.data = msg; | ||
setSettings(model); | ||
}); | ||
} | ||
else { | ||
console.warn('Couldn\'t connect to analyzer websocket server so you\'ll have to reload page manually to see updates in the treemap'); | ||
} | ||
}); | ||
class e{constructor(e){this.type=e,this.currentTarget=null}}e.COMPLETE="complete",e.CHANGE_PROPERTY="changeProperty";class t{constructor(e,t,s=0){this.type=e,this.handler=t,this.priority=s}equalCurrentListener(e,t){return this.type===e&&this.handler===t}}class s extends class{constructor(){this.listeners={}}dispatchEvent(t){let s,i;if(t instanceof e?(i=t.type,s=t):(i=t,s=new e(i)),null!==this.listeners[i]){const e=this.listeners[i].length;s.currentTarget=this;for(let t=0;t<e;t++){const e=this.listeners[i][t];try{e.handler(s)}catch(e){window.console&&console.error(e.stack)}}}else console.warn('implement "addEventListener" before dispatch')}addEventListener(e,s,i=0){this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].push(new t(e,s,i)),this.listeners[e].sort(((e,t)=>t.priority-e.priority))}removeEventListener(e,t){if(this.hasEventListener(e,t))for(let s=0;s<this.listeners[e].length;s++){if(this.listeners[e][s].equalCurrentListener(e,t))return void this.listeners[e].splice(s,1)}}clearEventListener(){this.listeners={}}containEventListener(e){return!!this.listeners[e]&&this.listeners[e].length>0}hasEventListener(e,t){if(!this.listeners[e])return!1;for(let s=0;s<this.listeners[e].length;s++){if(this.listeners[e][s].equalCurrentListener(e,t))return!0}return!1}}{constructor(){super(),this._data={entries:[],count:{}},this._viewType="GRAPH",this._visibleSettings=!1,this._visibleProps=!0,this._visibleFileSize=!0,this._visibleLastUpdated=!0,this._visibleReferenceCount=!0,this.getHowManyDaysAgo=e=>{const t=e.getTime(),s=this._todayTime-t;return Math.floor(s/864e5)},this._today=new Date,this._todayTime=this._today.getTime()}get data(){return this._data}set data(e){this._data=e,this.dispatchEvent(s.EVENT.DATA_UPDATE)}get viewType(){return this._viewType}set viewType(e){this._viewType=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}get visibleSettings(){return this._visibleSettings}set visibleSettings(e){this._visibleSettings=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}get visibleProps(){return this._visibleProps}set visibleProps(e){this._visibleProps=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}get visibleFileSize(){return this._visibleFileSize}set visibleFileSize(e){this._visibleFileSize=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}get visibleLastUpdated(){return this._visibleLastUpdated}set visibleLastUpdated(e){this._visibleLastUpdated=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}get visibleReferenceCount(){return this._visibleReferenceCount}set visibleReferenceCount(e){this._visibleReferenceCount=e,this.dispatchEvent(s.EVENT.SETTING_CHANGED)}}s.EVENT={DATA_UPDATE:"dataUpdate",SETTING_CHANGED:"settingChanged"};class i{constructor(e,t,s){this._model=s,this._children=[],this._name=e.name,this._props=e.props,this._fileSize=e.size,this._lastModifiedTime=e.lastModifiedTime,this._count=t}renderChildren(){let e="";for(let t=0,s=this._children.length;t<s;t++)e+=this._children[t].render();return`<div class="group">\n ${e}\n </div>`}renderProps(){return this._props?`<pre class="file__props">props: ${JSON.stringify(this._props,null,"\t")}</pre>`:""}renderMetaData(){let e="";const t=(this._fileSize/1024).toFixed(2);return t&&(e+=`<span class="file__meta meta__fileSize">FileSize: ${t} KB</span>`),e+=`<span class="file__meta meta__lastUpdated">LastUpdated: ${0===this._lastModifiedTime?0:this._model.getHowManyDaysAgo(new Date(this._lastModifiedTime))} days ago</span>`,e}renderSummary(){let e=this._name;return this._name.endsWith(".vue")?e=`<img class="icon" src="https://v3.vuejs.org/logo.png" alt="">${e}`:this._name.endsWith(".js")?e=`<img class="icon" src="https://raw.githubusercontent.com/voodootikigod/logo.js/master/js.png" alt="">${e}`:this._name.endsWith(".ts")&&(e=`<img class="icon" src="../dist/icon/icon-ts.png" alt="">${e}`),`<summary>${e}</summary>`}renderDetails(){return`<details class="detail">\n ${this.renderSummary()}\n ${this.renderProps()}\n ${this.renderMetaData()}\n </details>`}render(){const e=this.renderDetails();let t="",s="";return this._children.length>0?t=this.renderChildren():s=" -no-child",this.isJS()&&(s+=" js"),`<div class="seed${s}">\n <div class="file">\n <div class="filename">\n <div class="file__text">${e}</div>\n ${this.getCountText()}\n </div>\n </div>\n ${t}\n </div>`}getCountText(){return 0===this._count?"":1===this._count?'<span class="file__count">1 time referenced.</span>':`<span class="file__count">${this._count} times referenced.</span>`}get children(){return this._children}set children(e){this._children=e}isJS(){return this._name.endsWith(".js")}}class n{constructor(e,t){this._elm=e,this._model=t,this._type=e.dataset.settingName,e.addEventListener("change",this.onChange.bind(this))}onChange(){switch(this._type){case"props":this._model.visibleProps=this._elm.checked;break;case"fileSize":this._model.visibleFileSize=this._elm.checked;break;case"lastUpdated":this._model.visibleLastUpdated=this._elm.checked;break;case"referenceCount":this._model.visibleReferenceCount=this._elm.checked;break;default:throw new Error(`not supported type: ${this._type}`)}}}class r{constructor(e,t,s){this._elm=e,this._type=t,this._model=s,e.addEventListener("change",this.onChange.bind(this))}onChange(){this._model.viewType=this._type}}class l{constructor(e,t){this._isOpen=!1,this._details=null,this._textElement=document.getElementById("btn-toggle-visible-state-text"),e.addEventListener("click",this.onClick.bind(this)),t.addEventListener(s.EVENT.DATA_UPDATE,this.onDataUpdated.bind(this))}open(){this._details&&this._details.forEach((e=>{e.open=!0})),this._textElement&&(this._textElement.textContent="collapse all")}close(){this._details&&this._details.forEach((e=>{e.open=!1})),this._textElement&&(this._textElement.textContent="expand all")}onClick(){this._isOpen=!this._isOpen,this._isOpen?this.open():this.close()}onDataUpdated(){this._details=document.querySelectorAll(".detail")}}const a=new s;let h;new class{constructor(e){this._model=e,this._tree=[],this.ready=()=>{if("GRAPH"===this._model.viewType){const{data:e}=this._model,{entries:t}=e;for(let s=0,n=t.length;s<n;s++){const n=t[s];if(e){const e=new i(n,0,this._model);this._tree.push(this.generateSeed(n,e))}}}this.render()},this._app=document.getElementById("app"),e.addEventListener(s.EVENT.DATA_UPDATE,this.ready)}generateSeed(e,t){const s=[],{children:n}=e,r=[],{count:l}=this._model.data;for(let e=0,t=n.length;e<t;e++){const t=n[e],s=new i(t,l[t.name],this._model);r.push(s),this.generateSeed(t,s)}return t.children=r,s.push(t),s}renderLine(e,t,s){let i=" ";for(let e=0;e<t;e++)i+="│ ";return i+=s?"└─ ":"├─ ",i+=e,`${i}\n`}renderEntry(e,t){let s="";for(let i=0,n=e.children.length;i<n;i++){const r=e.children[i];s+=this.renderLine(r.name,t,i===n-1),s+=this.renderEntry(r,t+1)}return s}render(){let e="";for(let t=0,s=this._tree.length;t<s;t++){const[s]=this._tree[t];e+=s.render()}e=`<div class="root html">${e}</div>`;const{entries:t}=this._model.data;let s="";for(let e=0,i=t.length;e<i;e++){s+=`${t[e].name}\n`,s+=this.renderEntry(t[e],0),e<i-1&&(s+="\n")}s=`<div class="root text"><pre class="tree">${s}</pre></div>`,this._app&&(this._app.innerHTML=e+s)}}(a);try{window.enableWebSocket&&(h=new WebSocket(`ws://${location.host}`))}catch(e){console.warn("Couldn't connect to analyzer websocket server so you'll have to reload page manually to see updates in the treemap")}window.addEventListener("load",(()=>{h?h.addEventListener("message",(e=>{const t=JSON.parse(e.data);(e=>{const t=document.getElementById("btn-toggle-visible-state");t&&new l(t,e)})(a),a.data=t,function(e){const{body:t}=document,i=document.getElementById("btn-settings"),l=t.querySelectorAll(".js-settings-toggle"),a=document.getElementById("js-view-switch-graph"),h=document.getElementById("js-view-switch-text");new r(a,"GRAPH",e),new r(h,"TEXT",e);const o=function(){t.className=`${e.viewType}`,e.visibleSettings&&t.classList.add("show-settings"),e.visibleProps||t.classList.add("no-props"),e.visibleFileSize||t.classList.add("no-fileSize"),e.visibleLastUpdated||t.classList.add("no-lastUpdated"),e.visibleReferenceCount||t.classList.add("no-referenceCount")};l.forEach((t=>{new n(t,e)})),e.addEventListener(s.EVENT.SETTING_CHANGED,o),i&&i.addEventListener("click",(()=>{e.visibleSettings=!e.visibleSettings})),o()}(a)})):console.warn("Couldn't connect to analyzer websocket server so you'll have to reload page manually to see updates in the treemap")})); |
/*! | ||
@tkskto/vue-component-analyzer v0.3.1 | ||
@tkskto/vue-component-analyzer v0.3.2 | ||
https://github.com/tkskto/ | ||
@@ -12,460 +12,5 @@ Released under the MIT License. | ||
opener -- 1.5.2 | ||
vue-eslint-parser -- 7.7.2 | ||
ws -- 7.5.2 | ||
vue-eslint-parser -- 7.9.0 | ||
ws -- 7.5.3 | ||
*/ | ||
'use strict'; | ||
var require$$1 = require('fs'); | ||
var require$$2 = require('path'); | ||
var require$$0 = require('vue-eslint-parser'); | ||
var require$$1$1 = require('http'); | ||
var require$$2$1 = require('ejs'); | ||
var require$$3 = require('express'); | ||
var require$$4 = require('ws'); | ||
var require$$5 = require('opener'); | ||
var require$$6 = require('mkdirp'); | ||
var require$$7 = require('commander'); | ||
var require$$8 = require('globby'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var require$$1__default = /*#__PURE__*/_interopDefaultLegacy(require$$1); | ||
var require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2); | ||
var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0); | ||
var require$$1__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$1$1); | ||
var require$$2__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$2$1); | ||
var require$$3__default = /*#__PURE__*/_interopDefaultLegacy(require$$3); | ||
var require$$4__default = /*#__PURE__*/_interopDefaultLegacy(require$$4); | ||
var require$$5__default = /*#__PURE__*/_interopDefaultLegacy(require$$5); | ||
var require$$6__default = /*#__PURE__*/_interopDefaultLegacy(require$$6); | ||
var require$$7__default = /*#__PURE__*/_interopDefaultLegacy(require$$7); | ||
var require$$8__default = /*#__PURE__*/_interopDefaultLegacy(require$$8); | ||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | ||
var _temp = {}; | ||
var Constant = {}; | ||
Object.defineProperty(Constant, "__esModule", { value: true }); | ||
Constant.FORMAT = void 0; | ||
Constant.FORMAT = { | ||
BROWSER: 'browser', | ||
JSON: 'json', | ||
BOTH: 'both', | ||
}; | ||
var Model$1 = {}; | ||
Object.defineProperty(Model$1, "__esModule", { value: true }); | ||
Model$1.model = void 0; | ||
const Constant_1$1 = Constant; | ||
class Model { | ||
constructor() { | ||
this._resourceRoot = 'src'; | ||
this._format = Constant_1$1.FORMAT.BROWSER; | ||
this._outDirectory = 'out'; | ||
this._port = '8888'; | ||
this._isSilentMode = false; | ||
} | ||
get resourceRoot() { | ||
return this._resourceRoot; | ||
} | ||
set resourceRoot(value) { | ||
this._resourceRoot = value; | ||
} | ||
get format() { | ||
return this._format; | ||
} | ||
set format(value) { | ||
this._format = value; | ||
} | ||
get outDirectory() { | ||
return this._outDirectory; | ||
} | ||
set outDirectory(value) { | ||
this._outDirectory = value; | ||
} | ||
get port() { | ||
return this._port; | ||
} | ||
set port(value) { | ||
this._port = value; | ||
} | ||
get isSilentMode() { | ||
return this._isSilentMode; | ||
} | ||
set isSilentMode(value) { | ||
this._isSilentMode = value; | ||
} | ||
} | ||
Model$1.model = new Model(); | ||
var Analyzer$2 = {}; | ||
var utils = {}; | ||
Object.defineProperty(utils, "__esModule", { value: true }); | ||
utils.resolveFile = utils.getDeclarationSyntax = utils.getImportDeclaration = void 0; | ||
const Model_1$2 = Model$1; | ||
const { existsSync } = require$$1__default['default']; | ||
const { resolve, extname, dirname } = require$$2__default['default']; | ||
const getImportDeclaration = (nodeArr) => { | ||
return nodeArr.filter((node) => node.type === 'ImportDeclaration'); | ||
}; | ||
utils.getImportDeclaration = getImportDeclaration; | ||
const getDeclarationSyntax = (tokens, targetKeyName) => { | ||
let isTargetToken = false; | ||
let result = '{'; | ||
let closedCount = 0; | ||
const needQuotingTypes = ['Identifier', 'Boolean', 'Keyword']; | ||
for (const token of tokens) { | ||
const { type, value } = token; | ||
if (isTargetToken || (!isTargetToken && type === 'Identifier' && value === targetKeyName)) { | ||
const needQuoting = needQuotingTypes.includes(type); | ||
isTargetToken = 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}}`; | ||
}; | ||
utils.getDeclarationSyntax = getDeclarationSyntax; | ||
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('~', Model_1$2.model.resourceRoot).replace('@', Model_1$2.model.resourceRoot); | ||
} | ||
if (filename) { | ||
if (extname(filename) === '') { | ||
if (existsSync(`${filename}.vue`)) { | ||
return `${filename}.vue`; | ||
} | ||
else if (existsSync(`${filename}.js`)) { | ||
return `${filename}.js`; | ||
} | ||
else if (existsSync(`${filename}.ts`)) { | ||
return `${filename}.ts`; | ||
} | ||
} | ||
} | ||
return filename; | ||
}; | ||
utils.resolveFile = resolveFile; | ||
var FileCounter$1 = {}; | ||
Object.defineProperty(FileCounter$1, "__esModule", { value: true }); | ||
FileCounter$1.FileCounter = void 0; | ||
const path_1$1 = require$$2__default['default']; | ||
class FileCounter { | ||
constructor() { | ||
this._count = {}; | ||
} | ||
add(_filename) { | ||
const filename = path_1$1.resolve(_filename); | ||
if (Object.prototype.hasOwnProperty.call(this._count, filename)) { | ||
this._count[filename]++; | ||
} | ||
else { | ||
this._count[filename] = 1; | ||
} | ||
} | ||
get count() { | ||
return this._count; | ||
} | ||
} | ||
FileCounter$1.FileCounter = FileCounter; | ||
var VueComponent$1 = {}; | ||
Object.defineProperty(VueComponent$1, "__esModule", { value: true }); | ||
VueComponent$1.VueComponent = void 0; | ||
const vue_eslint_parser_1 = require$$0__default['default']; | ||
const utils_1$1 = utils; | ||
const parserOption = { | ||
ecmaVersion: 2018, | ||
sourceType: 'module', | ||
}; | ||
class VueComponent { | ||
constructor(filename, contents, stats) { | ||
var _a, _b, _c; | ||
this._filename = ''; | ||
this._lastModifiedTime = 0; | ||
this._size = 0; | ||
this._template = ''; | ||
this._style = ''; | ||
this._props = ''; | ||
this._children = []; | ||
this._importDeclaration = []; | ||
this.getProps = (tokens) => { | ||
try { | ||
const propsDeclaration = JSON.parse(utils_1$1.getDeclarationSyntax(tokens, 'props')); | ||
if (propsDeclaration && propsDeclaration.props) { | ||
return propsDeclaration.props; | ||
} | ||
return ''; | ||
} | ||
catch (err) { | ||
console.warn('failed to analyze props.'); | ||
return ''; | ||
} | ||
}; | ||
this._filename = filename; | ||
this._lastModifiedTime = (stats === null || stats === void 0 ? void 0 : stats.mtimeMs) || 0; | ||
this._size = (stats === null || stats === void 0 ? void 0 : stats.size) || 0; | ||
const templateBody = contents.match(/(?<template><template>[\s\S]*<\/template>)/u); | ||
const scriptBody = contents.match(/(?<script><script>[\s\S]*<\/script>)/u); | ||
const styleBody = contents.match(/(?<style><style>[\s\S]*<\/style>)/u); | ||
this._template = ((_a = templateBody === null || templateBody === void 0 ? void 0 : templateBody.groups) === null || _a === void 0 ? void 0 : _a.template) || ''; | ||
this._style = ((_b = styleBody === null || styleBody === void 0 ? void 0 : styleBody.groups) === null || _b === void 0 ? void 0 : _b.template) || ''; | ||
const scriptString = ((_c = scriptBody === null || scriptBody === void 0 ? void 0 : scriptBody.groups) === null || _c === void 0 ? void 0 : _c.script) || ''; | ||
const esLintProgram = vue_eslint_parser_1.parse(scriptString, parserOption); | ||
if (esLintProgram.tokens) { | ||
this._props = this.getProps(esLintProgram.tokens); | ||
} | ||
this._importDeclaration = utils_1$1.getImportDeclaration(esLintProgram.body); | ||
} | ||
addChildReport(report) { | ||
this._children.push(report); | ||
} | ||
get importDeclaration() { | ||
return this._importDeclaration; | ||
} | ||
getFileReport(isTest) { | ||
return { | ||
name: this._filename, | ||
props: this._props, | ||
size: this._size, | ||
lastModifiedTime: isTest ? 0 : Number(this._lastModifiedTime.toFixed(0)), | ||
children: this._children, | ||
}; | ||
} | ||
} | ||
VueComponent$1.VueComponent = VueComponent; | ||
Object.defineProperty(Analyzer$2, "__esModule", { value: true }); | ||
Analyzer$2.Analyzer = void 0; | ||
const utils_1 = utils; | ||
const fs_1 = require$$1__default['default']; | ||
const path_1 = require$$2__default['default']; | ||
const FileCounter_1 = FileCounter$1; | ||
const VueComponent_1 = VueComponent$1; | ||
const Model_1$1 = Model$1; | ||
const cwd = process.cwd(); | ||
class Analyzer$1 { | ||
constructor() { | ||
this.getImportDeclarationTree = (fileName, parents, isTest = false) => { | ||
const filename = path_1.resolve(cwd, fileName); | ||
const shortFilename = filename.replace(cwd, ''); | ||
const stat = fs_1.statSync(filename); | ||
const ancestorList = parents.concat(); | ||
ancestorList.push(fileName); | ||
if (!Model_1$1.model.isSilentMode) { | ||
console.log(`read ${filename}`); | ||
} | ||
this._counter.add(shortFilename); | ||
if (path_1.extname(filename) === '' || path_1.extname(filename) !== '.vue') { | ||
return { | ||
name: shortFilename, | ||
props: '', | ||
size: stat.size, | ||
lastModifiedTime: isTest ? 0 : Number(stat.mtimeMs.toFixed(0)), | ||
children: [], | ||
}; | ||
} | ||
const contents = fs_1.readFileSync(filename, 'utf-8'); | ||
const component = new VueComponent_1.VueComponent(shortFilename, contents, stat); | ||
try { | ||
for (let i = 0, len = component.importDeclaration.length; i < len; i++) { | ||
const source = String(component.importDeclaration[i].source.value); | ||
if (source) { | ||
const nextFilename = utils_1.resolveFile(source, filename); | ||
if (nextFilename) { | ||
if (parents.includes(nextFilename)) { | ||
console.warn(`Circular dependency detected between ${nextFilename} and ${filename}`); | ||
} | ||
else { | ||
component.addChildReport(this.getImportDeclarationTree(nextFilename, ancestorList, isTest)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
catch (err) { | ||
console.error(`Something went wrong with reading ${filename}`); | ||
console.error(err.message); | ||
} | ||
return component.getFileReport(isTest); | ||
}; | ||
this._counter = new FileCounter_1.FileCounter(); | ||
} | ||
get counter() { | ||
return this._counter; | ||
} | ||
} | ||
Analyzer$2.Analyzer = Analyzer$1; | ||
var server = {}; | ||
Object.defineProperty(server, "__esModule", { value: true }); | ||
const path$1 = require$$2__default['default']; | ||
const http = require$$1__default$1['default']; | ||
const { renderFile } = require$$2__default$1['default']; | ||
const express = require$$3__default['default']; | ||
const webSocket = require$$4__default['default']; | ||
const opener = require$$5__default['default']; | ||
const projectRoot = path$1.resolve(__dirname, '..'); | ||
const startServer$1 = (port, json) => { | ||
const HOST = '127.0.0.1'; | ||
const app = express(); | ||
app.engine('ejs', renderFile); | ||
app.set('view engine', 'ejs'); | ||
app.set('views', `${projectRoot}/views`); | ||
app.use(express.static(`${projectRoot}/`)); | ||
const server = http.createServer(app); | ||
const wss = new webSocket.Server({ | ||
server, | ||
}); | ||
app.use('/', (req, res) => { | ||
res.render('viewer', { | ||
mode: 'server', | ||
title: 'analyze report', | ||
enableWebSocket: true, | ||
}); | ||
}); | ||
server.on('error', (err) => { | ||
console.log(err); | ||
if (server.listening) { | ||
server.close((serverErr) => { | ||
console.log(serverErr); | ||
}); | ||
} | ||
}); | ||
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(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.'); | ||
}); | ||
}); | ||
}); | ||
}; | ||
server.startServer = startServer$1; | ||
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()); | ||
}); | ||
}; | ||
Object.defineProperty(_temp, "__esModule", { value: true }); | ||
const Constant_1 = Constant; | ||
const Model_1 = Model$1; | ||
const { Analyzer } = Analyzer$2; | ||
const { startServer } = server; | ||
const { writeFileSync } = require$$1__default['default']; | ||
const path = require$$2__default['default']; | ||
const mkdirp = require$$6__default['default']; | ||
const { program } = require$$7__default['default']; | ||
const globby = require$$8__default['default']; | ||
function writeFileExtra(filename, data) { | ||
mkdirp(path.dirname(filename)).then(() => { | ||
writeFileSync(filename, data); | ||
}).catch((err) => { | ||
if (err) { | ||
throw new Error(err.message); | ||
} | ||
}); | ||
} | ||
(() => __awaiter(void 0, void 0, void 0, function* () { | ||
try { | ||
program.option('--dir [dir]', 'root directory of src.', 'src'); | ||
program.option('-f, --format [type]', 'Add the specified type of report [browser, json or both]', Constant_1.FORMAT.BROWSER); | ||
program.option('-o, --out [dir]', 'output directory (enable with setting --format option to "json" or "both")', 'out'); | ||
program.option('-p, --port [number]', 'select a port number for the local server', '8888'); | ||
program.option('--silent', 'do not show logs with silent flag'); | ||
program.parse(process.argv); | ||
const argv = program.opts(); | ||
Model_1.model.resourceRoot = argv.dir; | ||
Model_1.model.format = argv.format; | ||
Model_1.model.outDirectory = argv.out; | ||
Model_1.model.port = argv.port; | ||
Model_1.model.isSilentMode = argv.silent || false; | ||
if (argv.format !== Constant_1.FORMAT.BROWSER && argv.format !== Constant_1.FORMAT.JSON && argv.format !== Constant_1.FORMAT.BOTH) { | ||
console.error(`not support ${argv.format} format.`); | ||
} | ||
console.log('start analyzing.'); | ||
const analyzer = new Analyzer(); | ||
const entries = yield globby([argv.dir, '!**/node_modules/**'], { | ||
expandDirectories: { | ||
extensions: ['vue'], | ||
}, | ||
}); | ||
if (entries.length === 0) { | ||
console.log('There is no entry file.'); | ||
} | ||
const entriesData = []; | ||
for (let i = 0, len = entries.length; i < len; i++) { | ||
const entryFile = entries[i]; | ||
const children = analyzer.getImportDeclarationTree(entryFile, []); | ||
entriesData.push(children); | ||
} | ||
const result = { | ||
entries: entriesData, | ||
count: analyzer.counter.count, | ||
}; | ||
if (argv.format === Constant_1.FORMAT.BOTH) { | ||
startServer(argv.port, result); | ||
writeFileExtra(path.resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
} | ||
else if (argv.format === Constant_1.FORMAT.BROWSER) { | ||
startServer(argv.port, result); | ||
} | ||
else if (argv.format === Constant_1.FORMAT.JSON) { | ||
writeFileExtra(path.resolve(process.cwd(), `${argv.out}/result.json`), JSON.stringify(result, null, 4)); | ||
} | ||
console.log('finished analyzing.'); | ||
} | ||
catch (err) { | ||
console.error(err.message); | ||
} | ||
}))(); | ||
module.exports = _temp; | ||
"use strict";var e=require("commander"),t=require("fs"),o=require("path"),r=require("vue-eslint-parser"),s=require("express"),i=require("ws"),n=require("http"),l=require("ejs"),a=require("opener"),u=require("mkdirp"),c=require("globby");function d(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var p=d(e),f=d(t),m=d(o),h=d(r),v=d(s),g=d(i),_=d(n),y=d(l),S=d(a),w=d(u),O=d(c),b="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},M={},R={};Object.defineProperty(R,"__esModule",{value:!0}),R.FORMAT=void 0,R.FORMAT={BROWSER:"browser",JSON:"json",BOTH:"both"};var D={};Object.defineProperty(D,"__esModule",{value:!0}),D.model=void 0;const T=R;D.model=new class{constructor(){this._resourceRoot="src",this._format=T.FORMAT.BROWSER,this._outDirectory="out",this._port="8888",this._isSilentMode=!1}get resourceRoot(){return this._resourceRoot}set resourceRoot(e){this._resourceRoot=e}get format(){return this._format}set format(e){this._format=e}get outDirectory(){return this._outDirectory}set outDirectory(e){this._outDirectory=e}get port(){return this._port}set port(e){this._port=e}get isSilentMode(){return this._isSilentMode}set isSilentMode(e){this._isSilentMode=e}};var F={};Object.defineProperty(F,"__esModule",{value:!0}),F.getOptions=void 0;const j=R,$=p.default;F.getOptions=e=>($.program.option("--dir [dir]","root directory of src.","src"),$.program.option("-f, --format [type]","Add the specified type of report [browser, json or both]",j.FORMAT.BROWSER),$.program.option("-o, --out [dir]",'output directory (enable with setting --format option to "json" or "both")',"out"),$.program.option("-p, --port [number]","select a port number for the local server","8888"),$.program.option("--silent","do not show logs with silent flag"),$.program.parse(e),$.program.opts());var x={},z={};Object.defineProperty(z,"__esModule",{value:!0}),z.resolveFile=z.getDeclarationSyntax=z.getImportDeclaration=void 0;const P=D,A=f.default,C=m.default;z.getImportDeclaration=e=>e.filter((e=>"ImportDeclaration"===e.type));z.getDeclarationSyntax=(e,t)=>{let o=!1,r="{",s=0;const i=["Identifier","Boolean","Keyword"];for(const n of e){const{type:e,value:l}=n;if(o||!o&&"Identifier"===e&&l===t){const t=i.includes(e);if(o=!0,"Punctuator"===e)if("{"===l)s++;else if("}"===l&&(s--,","===r[r.length-1]&&(r=r.slice(0,-1)),0===s)){r+="}";break}t&&(r+='"'),r+=l.replace(/'/gu,'"'),t&&(r+='"')}}return`${r}}`};z.resolveFile=(e,t)=>{let o="";if(e.startsWith("../")?o=C.resolve(C.dirname(t),e):e.startsWith("./")?o=`${C.dirname(t)}/${e.replace(/\.\/|/gu,"")}`:(e.startsWith("~")||e.startsWith("@"))&&(o=e.replace("~",P.model.resourceRoot).replace("@",P.model.resourceRoot)),o&&""===C.extname(o)){if(A.existsSync(`${o}.vue`))return`${o}.vue`;if(A.existsSync(`${o}.js`))return`${o}.js`;if(A.existsSync(`${o}.ts`))return`${o}.ts`}return o};var q={};Object.defineProperty(q,"__esModule",{value:!0}),q.FileCounter=void 0;const N=m.default;q.FileCounter=class{constructor(){this._count={}}add(e){const t=N.resolve(e);Object.prototype.hasOwnProperty.call(this._count,t)?this._count[t]++:this._count[t]=1}get count(){return this._count}};var W={};Object.defineProperty(W,"__esModule",{value:!0}),W.VueComponent=void 0;const B=h.default,I=z,E={ecmaVersion:2018,sourceType:"module"};W.VueComponent=class{constructor(e,t,o){var r,s,i;this._filename="",this._lastModifiedTime=0,this._size=0,this._template="",this._style="",this._props="",this._children=[],this._importDeclaration=[],this.getProps=e=>{try{const t=JSON.parse(I.getDeclarationSyntax(e,"props"));return t&&t.props?t.props:""}catch(e){return console.warn("failed to analyze props."),""}},this._filename=e,this._lastModifiedTime=(null==o?void 0:o.mtimeMs)||0,this._size=(null==o?void 0:o.size)||0;const n=t.match(/(?<template><template>[\s\S]*<\/template>)/u),l=t.match(/(?<script><script>[\s\S]*<\/script>)/u),a=t.match(/(?<style><style>[\s\S]*<\/style>)/u);this._template=(null===(r=null==n?void 0:n.groups)||void 0===r?void 0:r.template)||"",this._style=(null===(s=null==a?void 0:a.groups)||void 0===s?void 0:s.template)||"";const u=(null===(i=null==l?void 0:l.groups)||void 0===i?void 0:i.script)||"",c=B.parse(u,E);c.tokens&&(this._props=this.getProps(c.tokens)),this._importDeclaration=I.getImportDeclaration(c.body)}addChildReport(e){this._children.push(e)}get importDeclaration(){return this._importDeclaration}getFileReport(e){return{name:this._filename,props:this._props,size:this._size,lastModifiedTime:e?0:Number(this._lastModifiedTime.toFixed(0)),children:this._children}}},Object.defineProperty(x,"__esModule",{value:!0}),x.analyzer=void 0;const J=z,k=f.default,V=m.default,H=q,K=W,L=D,U=process.cwd();x.analyzer=new class{constructor(){this.getImportDeclarationTree=(e,t,o=!1)=>{const r=V.resolve(U,e),s=r.replace(U,""),i=k.statSync(r),n=t.concat();if(n.push(e),L.model.isSilentMode||console.log(`read ${r}`),this._counter.add(s),""===V.extname(r)||".vue"!==V.extname(r))return{name:s,props:"",size:i.size,lastModifiedTime:o?0:Number(i.mtimeMs.toFixed(0)),children:[]};const l=k.readFileSync(r,"utf-8"),a=new K.VueComponent(s,l,i);try{for(let e=0,s=a.importDeclaration.length;e<s;e++){const s=String(a.importDeclaration[e].source.value);if(s){const e=J.resolveFile(s,r);e&&(t.includes(e)?console.warn(`Circular dependency detected between ${e} and ${r}`):a.addChildReport(this.getImportDeclarationTree(e,n,o)))}}}catch(e){console.error(`Something went wrong with reading ${r}`),console.error(e.message)}return a.getFileReport(o)},this._counter=new H.FileCounter}get counter(){return this._counter}};var G={},Q=b&&b.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(G,"__esModule",{value:!0}),G.startServer=void 0;const X=Q(v.default),Y=Q(g.default),Z=Q(m.default),ee=Q(_.default),te=y.default,oe=Q(S.default),re=Z.default.resolve(__dirname,"..");G.startServer=(e,t)=>{const o="127.0.0.1",r=X.default();r.engine("ejs",te.renderFile),r.set("view engine","ejs"),r.set("views",`${re}/views`),r.use(X.default.static(`${re}/`));const s=ee.default.createServer(r),i=new Y.default.Server({server:s});r.use("/",((e,t)=>{t.render("viewer",{mode:"server",title:"analyze report",enableWebSocket:!0})})),s.on("error",(e=>{console.log(e),s.listening&&s.close((e=>{console.log(e)}))})),s.listen(Number(e),o,(()=>{const r=null==s?void 0:s.address();let n=e;"string"==typeof r?n=r:"object"==typeof r&&(n=String(null==r?void 0:r.port)||e);const l=`http://${o}:${n}/`;console.log(`Vue Component Analyzer is started at ${l}`),console.log("Use 'Ctrl+C' to close it"),oe.default(l),i.on("connection",(e=>{i.clients.forEach((e=>{e.send(JSON.stringify(t))})),e.addEventListener("error",(()=>{console.error("Something went to wrong on web socket.")}))}))}))};var se=b&&b.__awaiter||function(e,t,o,r){return new(o||(o=Promise))((function(s,i){function n(e){try{a(r.next(e))}catch(e){i(e)}}function l(e){try{a(r.throw(e))}catch(e){i(e)}}function a(e){var t;e.done?s(e.value):(t=e.value,t instanceof o?t:new o((function(e){e(t)}))).then(n,l)}a((r=r.apply(e,t||[])).next())}))},ie=b&&b.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(M,"__esModule",{value:!0});const ne=R,le=D,ae=F,ue=x,ce=G,de=f.default,pe=ie(m.default),fe=ie(w.default),me=ie(O.default);function he(e,t){fe.default(pe.default.dirname(e)).then((()=>{de.writeFileSync(e,t)})).catch((e=>{if(e)throw new Error(e.message)}))}se(void 0,void 0,void 0,(function*(){try{const e=ae.getOptions(process.argv);le.model.resourceRoot=e.dir,le.model.format=e.format,le.model.outDirectory=e.out,le.model.port=e.port,le.model.isSilentMode=e.silent||!1,e.format!==ne.FORMAT.BROWSER&&e.format!==ne.FORMAT.JSON&&e.format!==ne.FORMAT.BOTH&&console.error(`not support ${e.format} format.`),console.log("start analyzing.");const t=yield me.default([e.dir,"!**/node_modules/**"],{expandDirectories:{extensions:["vue"]}});0===t.length&&console.log("There is no entry file.");const o=[];for(let e=0,r=t.length;e<r;e++){const r=t[e],s=ue.analyzer.getImportDeclarationTree(r,[]);o.push(s)}const r={entries:o,count:ue.analyzer.counter.count};e.format===ne.FORMAT.BOTH?(ce.startServer(e.port,r),he(pe.default.resolve(process.cwd(),`${e.out}/result.json`),JSON.stringify(r,null,4))):e.format===ne.FORMAT.BROWSER?ce.startServer(e.port,r):e.format===ne.FORMAT.JSON&&he(pe.default.resolve(process.cwd(),`${e.out}/result.json`),JSON.stringify(r,null,4)),console.log("finished analyzing.")}catch(e){console.error(e.message)}})),module.exports=M; |
{ | ||
"name": "@tkskto/vue-component-analyzer", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"description": "Analyze dependency tree for Vue.js SFC (Single File Component)", | ||
@@ -54,12 +54,14 @@ "main": "dist/index.js", | ||
"opener": "1.5.2", | ||
"vue-eslint-parser": "7.7.2", | ||
"ws": "7.5.2" | ||
"vue-eslint-parser": "7.9.0", | ||
"ws": "7.5.3" | ||
}, | ||
"devDependencies": { | ||
"@mitsue/eslint-config": "4.0.1", | ||
"@rollup/plugin-commonjs": "19.0.0", | ||
"@rollup/plugin-commonjs": "19.0.1", | ||
"@rollup/plugin-json": "4.1.0", | ||
"@rollup/plugin-node-resolve": "13.0.0", | ||
"@rollup/plugin-typescript": "8.2.1", | ||
"@rollup/plugin-node-resolve": "13.0.2", | ||
"@rollup/plugin-typescript": "8.2.3", | ||
"@types/ejs": "3.0.7", | ||
"@types/express": "4.17.12", | ||
"@types/mkdirp": "1.0.2", | ||
"@types/mocha": "8.2.2", | ||
@@ -76,4 +78,5 @@ "@types/node": "14.17.4", | ||
"nyc": "15.1.0", | ||
"rollup": "2.52.7", | ||
"rollup": "2.53.2", | ||
"rollup-plugin-license": "2.5.0", | ||
"rollup-plugin-terser": "7.0.2", | ||
"ts-mocha": "8.0.0", | ||
@@ -80,0 +83,0 @@ "typescript": "4.3.5" |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
12
31197
24
349
3
2
+ Addedvue-eslint-parser@7.9.0(transitive)
+ Addedws@7.5.3(transitive)
- Removedvue-eslint-parser@7.7.2(transitive)
- Removedws@7.5.2(transitive)
Updatedvue-eslint-parser@7.9.0
Updatedws@7.5.3