├── .npmignore
├── tests
├── components
│ ├── K.jsx
│ ├── L.ts
│ ├── M.tsx
│ ├── N.tsx
│ ├── D.js
│ ├── E.js
│ ├── G.js
│ ├── H.js
│ ├── F.js
│ ├── A.js
│ ├── I.js
│ ├── B.js
│ ├── C.js
│ └── J.js
├── ignored_types
│ ├── file.min.js
│ ├── file.chunk.js
│ └── file.bundle.js
├── ignored_paths
│ ├── bin
│ │ └── index.js
│ ├── build
│ │ └── index.js
│ ├── dist
│ │ └── index.js
│ ├── log
│ │ └── index.js
│ ├── logs
│ │ └── index.js
│ ├── out
│ │ └── index.js
│ ├── output
│ │ └── index.js
│ ├── target
│ │ └── index.js
│ ├── test
│ │ └── index.js
│ ├── tests
│ │ └── index.js
│ └── node_modules
│ │ └── index.js
├── imports
│ └── index.js
├── imports_commented
│ └── index.js
└── index.bats
├── .gitignore
├── scripts
├── deploy_package.sh
├── deploy_site.sh
└── install_bats.sh
├── .github
├── release-drafter.yml
└── workflows
│ ├── release-drafter.yml
│ └── test.yml
├── docs
├── .vuepress
│ └── config.js
└── README.md
├── package.json
├── LICENSE
└── findead.sh
/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | tests
3 | scripts
4 | docs
5 | .github
--------------------------------------------------------------------------------
/tests/components/K.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export const TestComponentK = () => { }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | !tests/ignored_paths/dist
4 | !tests/ignored_paths/node_modules
--------------------------------------------------------------------------------
/tests/components/L.ts:
--------------------------------------------------------------------------------
1 | //@ts-ignore
2 | import React from "react";
3 |
4 | export const TestComponentL = () => { }
--------------------------------------------------------------------------------
/tests/components/M.tsx:
--------------------------------------------------------------------------------
1 | //@ts-ignore
2 | import React from "react";
3 |
4 | export const TestComponentM = () => { }
--------------------------------------------------------------------------------
/tests/components/N.tsx:
--------------------------------------------------------------------------------
1 | //@ts-ignore
2 | import React from "react";
3 |
4 | export const TestComponentN = () => {};
5 |
--------------------------------------------------------------------------------
/tests/components/D.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function TestComponentD() { }
4 |
5 | export default TestComponentD;
--------------------------------------------------------------------------------
/tests/components/E.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function TestComponentE(props) { }
4 |
5 | export default TestComponentE;
--------------------------------------------------------------------------------
/tests/components/G.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TestComponentG = () => { }
4 |
5 | export default TestComponentG;
--------------------------------------------------------------------------------
/scripts/deploy_package.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | set -e
4 |
5 | cp docs/README.md README.md
6 |
7 | npm publish
8 |
9 | rm README.md
--------------------------------------------------------------------------------
/tests/components/H.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TestComponentH = (props) => { }
4 |
5 | export default TestComponentH;
--------------------------------------------------------------------------------
/tests/components/F.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | function TestComponentF({prop1, prop2}) { }
4 |
5 | export default TestComponentF;
--------------------------------------------------------------------------------
/tests/components/A.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentA extends React.Component { }
4 |
5 | export default TestComponentA;
--------------------------------------------------------------------------------
/tests/components/I.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TestComponentI = ({ prop1, prop2 }) => { }
4 |
5 | export default TestComponentI;
--------------------------------------------------------------------------------
/tests/components/B.js:
--------------------------------------------------------------------------------
1 | import { Component } from "react";
2 |
3 | class TestComponentB extends Component { }
4 |
5 | export default TestComponentB;
6 |
--------------------------------------------------------------------------------
/tests/components/C.js:
--------------------------------------------------------------------------------
1 | import { PureComponent } from "react";
2 |
3 | class TestComponentC extends PureComponent { }
4 |
5 | export default TestComponentC;
--------------------------------------------------------------------------------
/tests/ignored_types/file.min.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentMinExt extends React.Component { }
4 |
5 | export default TestComponentMinExt;
--------------------------------------------------------------------------------
/tests/ignored_types/file.chunk.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentChunkExt extends React.Component { }
4 |
5 | export default TestComponentChunkExt;
--------------------------------------------------------------------------------
/tests/ignored_types/file.bundle.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentBundleExt extends React.Component { }
4 |
5 | export default TestComponentBundleExt;
--------------------------------------------------------------------------------
/tests/ignored_paths/bin/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/build/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/dist/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/log/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/logs/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/out/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/output/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/target/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/test/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/tests/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/ignored_paths/node_modules/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | class TestComponentInIgnoredPath extends React.Component { }
4 |
5 | export default TestComponentInIgnoredPath;
--------------------------------------------------------------------------------
/tests/components/J.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const TestComponentJ1 = ({ prop1, prop2 }) => { }
4 |
5 | const TestComponentJ2 = ({ prop1, prop2 }) => {
6 | return
7 | }
8 |
9 | export default TestComponentJ2;
--------------------------------------------------------------------------------
/scripts/deploy_site.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | set -e
4 |
5 | npm run site:build
6 |
7 | cd docs/.vuepress/dist
8 |
9 | git init
10 | git add -A
11 | git commit -m 'deploy'
12 |
13 | git push -f git@github.com:narcello/findead.git master:gh-pages
14 |
15 | cd -
16 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | categories:
2 | - title: "🚀 Features"
3 | labels:
4 | - "feature"
5 | - "enhancement"
6 | - title: "🐛 Bug Fixes"
7 | labels:
8 | - "fix"
9 | - "bugfix"
10 | - "bug"
11 | change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
12 | exclude-labels:
13 | - "skip-changelog"
14 | template: |
15 | ## Changes
16 |
17 | $CHANGES
18 |
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Update Changelog
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | update_release_draft:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: release-drafter/release-drafter@v5
15 | with:
16 | config-name: release-drafter.yml
17 | env:
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/scripts/install_bats.sh:
--------------------------------------------------------------------------------
1 | install_bats() {
2 | cd bats
3 | sudo ./install.sh /usr/local
4 | }
5 |
6 | clone_bats_repo() {
7 | cd ~
8 | EXISTS_BATS_FOLDER=$(ls | grep 'bats')
9 | [[ -z "$EXISTS_BATS_FOLDER" ]] && git clone https://github.com/sstephenson/bats.git
10 | install_bats
11 | }
12 |
13 | check_bats_on_environment() {
14 | EXISTS_BATS_ON_ENVIRONMENT=$(whereis bats | grep 'bats: .*')
15 | [[ -z "$EXISTS_BATS_ON_ENVIRONMENT" ]] && clone_bats_repo
16 | }
17 |
18 | check_bats_on_environment
19 |
--------------------------------------------------------------------------------
/docs/.vuepress/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: 'Findead',
3 | description: 'Dead react components finder',
4 | base: '/findead/',
5 | themeConfig: {
6 | nav: [
7 | { text: 'Home', link: '/' },
8 | { text: 'Motivation', link: '/#motivation-dead-components' },
9 | { text: 'Tech', link: '/#tech' },
10 | { text: 'Install', link: '/#install' },
11 | { text: 'Usage', link: '/#usage' },
12 | { text: 'Examples', link: '/#examples' },
13 | { text: 'Github', link: 'https://github.com/narcello/findead', target:'_blank', rel:'' }
14 | ]
15 | }
16 | }
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Run Tests
2 |
3 | on: pull_request
4 |
5 | jobs:
6 | test-on-ubuntu:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v1
11 | - name: Install Bats
12 | run: ./scripts/install_bats.sh
13 | - name: Install dependencies
14 | run: npm i
15 | - name: Run tests
16 | run: npm t
17 |
18 | test-on-mac:
19 | runs-on: macos-latest
20 |
21 | steps:
22 | - uses: actions/checkout@v1
23 | - name: Install Bats
24 | run: ./scripts/install_bats.sh
25 | - name: Install dependencies
26 | run: npm i
27 | - name: Run tests
28 | run: npm t
29 |
--------------------------------------------------------------------------------
/tests/imports/index.js:
--------------------------------------------------------------------------------
1 | import TestComponentA from "../components/A";
2 | import TestComponentB from "../components/B";
3 | import TestComponentC from "../components/C";
4 | import TestComponentD from "../components/D";
5 | import TestComponentE from "../components/E";
6 | import TestComponentF from "../components/F";
7 | import TestComponentG from "../components/G";
8 | import TestComponentH from "../components/H";
9 | import TestComponentI from "../components/I";
10 | import TestComponentJ2 from "../components/J";
11 | import TestComponentK from "../components/K";
12 | import TestComponentL from "../components/L";
13 | import TestComponentM from "../components/M";
14 |
15 | const routes = [
16 | {
17 | path: '/path/to/component',
18 | exact: true,
19 | component: lazy(() => import('../components/N'))
20 | },
21 | ]
--------------------------------------------------------------------------------
/tests/imports_commented/index.js:
--------------------------------------------------------------------------------
1 | // import TestComponentA from "../components/A";
2 | // import TestComponentB from "../components/B";
3 | // import TestComponentC from "../components/C";
4 | // import TestComponentD from "../components/D";
5 | // import TestComponentE from "../components/E";
6 | // import TestComponentF from "../components/F";
7 | // import TestComponentG from "../components/G";
8 | // import TestComponentH from "../components/H";
9 | // import TestComponentI from "../components/I";
10 | // import TestComponentJ2 from "../components/J";
11 | // import TestComponentK from "../components/K";
12 | // import TestComponentL from "../components/L";
13 | // import TestComponentM from "../components/M";
14 |
15 | const routes = [
16 | {
17 | path: '/path/to/component',
18 | exact: true,
19 | // component: lazy(() => import('../components/N'))
20 | },
21 | ]
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "findead",
3 | "version": "1.2.3",
4 | "description": "Dead react components finder",
5 | "preferGlobal": true,
6 | "bin": {
7 | "findead": "findead.sh"
8 | },
9 | "author": {
10 | "name": "Marcello Silva",
11 | "email": "marcellovcs@gmail.com",
12 | "url": "https://github.com/narcello"
13 | },
14 | "scripts": {
15 | "test": "bats ./tests/index.bats",
16 | "site:dev": "vuepress dev docs",
17 | "site:build": "vuepress build docs",
18 | "site:deploy": "./scripts/deploy_site.sh",
19 | "npm:deploy": "./scripts/deploy_package.sh"
20 | },
21 | "repository": "https://github.com/narcello/findead",
22 | "homepage": "https://narcello.github.io/findead",
23 | "keywords": [
24 | "dead",
25 | "react",
26 | "components",
27 | "bash",
28 | "sh",
29 | "unused"
30 | ],
31 | "license": "ISC",
32 | "devDependencies": {
33 | "bats-assert": "git+https://github.com/ztombol/bats-assert.git",
34 | "bats-support": "git+https://github.com/ztombol/bats-support.git",
35 | "vuepress": "1.5.4"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Marcello Victor
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # :mag: findead
2 | Dead react components finder
3 |
4 |
5 | []()
6 | []()
7 | [](https://github.com/narcello/findead/actions/workflows/test.yml)
8 |
9 | ## :rocket: *Dead Components* is the Motivation
10 | Many times in large or even small projects, we forgot some components in code that we'll never use and we never take time to search one by one and remove.
11 |
12 | ## :camera: Demonstration
13 | 
14 | When findead finish, you'll can see:
15 | * Components name
16 | * Path of each one component
17 | * Size of each one file
18 | * How many dead components
19 | * How many browsed files
20 | * How much time spent to execution
21 | ## :computer: Tech
22 | Just bash :)
23 |
24 | ## :inbox_tray: Install
25 | * Npm
26 | ```sh
27 | npm i -g findead
28 | ```
29 | * Yarn
30 | ```sh
31 | yarn add findead
32 | ```
33 |
34 | ## :hammer: Usage
35 | ```bash
36 | findead
37 | ```
38 | Pass folder to get all of your components in js, jsx, ts and tsx files.
39 |
40 | ___obs: By default, all `node_modules` folder is ignored.___
41 |
42 | ## :zap: Examples
43 | #### Just one argument
44 | * If you pass just one argument, it will be used for `get components` and `search usages`
45 | ```bash
46 | findead ~/path/to/search
47 | ```
48 | #### Raw result
49 | * Pass `-r` flag for raw output. Better for atribute output into a file.
50 | ```bash
51 | findead -r ~/path/to/search
52 | ```
53 | #### Multiple and specific folders
54 | ```bash
55 | findead -m ~/path/to/search/{folder1,folder2,...,folderN}
56 | ```
57 |
--------------------------------------------------------------------------------
/tests/index.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 |
3 | load '../node_modules/bats-support/load'
4 | load '../node_modules/bats-assert/load'
5 |
6 | @test 'Test used component' {
7 | run echo "$(./findead.sh -m tests/{imports,components} | grep -o 'No unused components found')"
8 | assert_output "No unused components found"
9 | }
10 |
11 | @test 'Test unused component(without imports)' {
12 | run echo "$(./findead.sh tests/components | grep -o '14 possible dead components :/')"
13 | assert_output "14 possible dead components :/"
14 | }
15 |
16 | @test 'Test unused component(commented imports)' {
17 | run echo "$(./findead.sh -m tests/{imports_commented,components} | grep -o '14 possible dead components :/')"
18 | assert_output "14 possible dead components :/"
19 | }
20 |
21 | @test 'Test error: paths must precede expression' {
22 | run bash -c "cd tests/components/ && ../../findead.sh | grep -o 'paths must precede expression'"
23 | assert_failure
24 | }
25 |
26 | @test 'Test --version predicate' {
27 | PACKAGE_VERSION=$(cat ./package.json | grep '"version": .*,' | awk '{ print $2 }' | cut -d '"' -f 2)
28 | run ./findead.sh --version
29 | assert_output "findead@$PACKAGE_VERSION"
30 | }
31 |
32 | @test 'Test -v predicate' {
33 | PACKAGE_VERSION=$(cat ./package.json | grep '"version": .*,' | awk '{ print $2 }' | cut -d '"' -f 2)
34 | run ./findead.sh -v
35 | assert_output "findead@$PACKAGE_VERSION"
36 | }
37 |
38 | @test 'Test --help predicate' {
39 | run ./findead.sh --help
40 | assert_line --partial 'findead -h | --help'
41 | }
42 |
43 | @test 'Test -h predicate' {
44 | run ./findead.sh -h
45 | assert_line --partial 'findead -h | --help'
46 | }
47 |
48 | @test 'Test -r predicate' {
49 | run echo "$(./findead.sh -r tests | grep -o 'No unused components found')"
50 | assert_output 'No unused components found'
51 | }
52 |
53 | @test 'Test multiples predicates' {
54 | run echo "$(./findead.sh -mr tests/{imports_commented,components} | grep -o '14 possible dead components :/')"
55 | assert_output '14 possible dead components :/'
56 | }
57 |
58 | @test 'Test specific comands' {
59 | run wc -c < ./tests/components/A.js
60 | assert_line --partial '108'
61 | }
62 |
63 | @test 'Test ignored type files' {
64 | run bash -c "cd tests/ignored_types/ && ../../findead.sh | grep -o '1 browsed files in'"
65 | assert_output '1 browsed files in'
66 | }
67 |
68 | @test 'Test ignored paths' {
69 | run bash -c "cd tests/ignored_paths/ && ../../findead.sh | grep -o '1 browsed files in'"
70 | assert_output '1 browsed files in'
71 | }
--------------------------------------------------------------------------------
/findead.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # set -e
4 |
5 | CLASS_COMPONENT=''
6 | FIRST_LETTER_COMPONENT=''
7 | declare -a COMPONENTS
8 | AUX_ARRAY_COMPONENTS=''
9 | COUNTER_UNUSED_COMPONENTS=0
10 | AUX_COUNTER=0
11 | FIND_RETURN=''
12 | FIRST_ARGUMENT=$1
13 | PATH_TO_FIND=''
14 | FINDEAD_TIME=''
15 | TIMEFORMAT="%R"
16 | FILE_PATH=''
17 | CURRENT_FUNCTIONS=''
18 | if [ $# -gt 1 ]; then
19 | MULTIPLE_PATHS=$(echo $FIRST_ARGUMENT | grep '\-.*m')
20 | RAW=$(echo $FIRST_ARGUMENT | grep '\-.*r')
21 | fi
22 |
23 | fileSizeKB() {
24 | FILE_SIZE_B=$(wc -c <$1)
25 | [[ ${FILE_SIZE_B} -lt 1024 ]] && echo "${FILE_SIZE_B} Bytes"
26 | [[ ${FILE_SIZE_B} -gt 1023 ]] && echo "$(echo ${FILE_SIZE_B}/1024 | bc) KB"
27 | }
28 |
29 | center() {
30 | termwidth="$(tput -T xterm cols)"
31 | padding="$(printf '%0.1s' ={1..500})"
32 | printf '%*.*s %s %*.*s\n' 0 "$(((termwidth - 2 - ${#1}) / 2))" "$padding" "$1" 0 "$(((termwidth - 1 - ${#1}) / 2))" "$padding"
33 | }
34 |
35 | centerResult() {
36 | termwidth="$(tput -T xterm cols)"
37 | padding="$(printf '%0.1s' ={1..500})"
38 | printf "\e[0m%*.*s \e[36m%s\e[0m %*.*s\n" 0 "$(((termwidth - 2 - ${#1}) / 2))" "$padding" "$1" 0 "$(((termwidth - 1 - ${#1}) / 2))" "$padding"
39 | }
40 |
41 | searchFiles() {
42 | FIND_RETURN=$(
43 | eval $"find $PATH_TO_FIND -type f \( ! -name '*.chunk.*' ! -name '*.min.*' ! -name '*.bundle.*' -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) \
44 | -not -path '*/node_modules/*' \
45 | -not -path '*/dist/*' \
46 | -not -path '*/build/*' \
47 | -not -path '*/bin/*' \
48 | -not -path '*/out/*' \
49 | -not -path '*/output/*' \
50 | -not -path '*/target/*' \
51 | -not -path '*/log/*' \
52 | -not -path '*/logs/*' \
53 | -not -path '*/test/*' \
54 | -not -path '*/tests/*' \
55 | -print"
56 | )
57 | }
58 |
59 | getClassComponents() {
60 | CLASS_COMPONENT=$(cat ${FILE_PATH} | grep -o "class.*Component" | awk '{ print $2 }')
61 | USED_IN_SAME_FILE=$(grep -o "<$CLASS_COMPONENT" ${FILE_PATH})
62 | if [ ! -z "$CLASS_COMPONENT" ]; then
63 | [[ -z "$USED_IN_SAME_FILE" ]] && COMPONENTS+=("$CLASS_COMPONENT;$FILE_PATH")
64 | fi
65 | AUX_ARRAY_COMPONENTS=${COMPONENTS[@]}
66 | }
67 |
68 | checkFunctions() {
69 | for FUNCTION in $CURRENT_FUNCTIONS; do
70 | if [[ ! $FUNCTION =~ ^(\[|\]|\{|\})$ ]]; then
71 | FIRST_LETTER_FUNCTION_COMPONENT="$(echo "$FUNCTION" | head -c 1)"
72 | USED_IN_SAME_FILE=$(grep -o "<$FUNCTION" ${FILE_PATH})
73 | [[ "$FIRST_LETTER_FUNCTION_COMPONENT" =~ [A-Z] ]] &&
74 | [[ -z "$USED_IN_SAME_FILE" ]] && COMPONENTS+=("$FUNCTION;$FILE_PATH")
75 | fi
76 | AUX_ARRAY_COMPONENTS=${COMPONENTS[@]}
77 | done
78 | }
79 |
80 | getES5FunctionComponents() {
81 | CURRENT_FUNCTIONS=$(cat ${FILE_PATH} | grep -o "function.*(" | awk '{ print $2 }' | cut -d "(" -f 1)
82 | checkFunctions
83 | }
84 |
85 | getES6FunctionComponents() {
86 | CURRENT_FUNCTIONS=$(cat ${FILE_PATH} | grep -o "const.*= (.*) =>" | awk '{ print $2 }')
87 | checkFunctions
88 | }
89 |
90 | getFunctionComponents() {
91 | IS_REACT_FILE=$(cat ${FILE_PATH} | grep 'import.*React')
92 | if [ ! -z "$IS_REACT_FILE" ]; then
93 | getES5FunctionComponents
94 | getES6FunctionComponents
95 | fi
96 | }
97 |
98 | getComponents() {
99 | for ITEM in $FIND_RETURN; do
100 | FILE_PATH=$ITEM
101 | getClassComponents
102 | getFunctionComponents
103 | done
104 | }
105 |
106 | searchImports() {
107 | for COMPONENT in ${COMPONENTS[@]}; do
108 | COMPONENT_NAME=$(echo $COMPONENT | cut -d ";" -f 1)
109 | COMPONENT_FILE_PATH=$(echo $COMPONENT | cut -d ";" -f 2)
110 | ABSOLUTE_COMPONENT_FILE_PATH="/$(basename "$COMPONENT_FILE_PATH" | cut -d . -f 1)"
111 |
112 | GREP_RECURSIVE_RESULT=$(echo $FIND_RETURN | xargs grep "import.*$COMPONENT_NAME.*from")
113 | GREP_RECURSIVE_RESULT_FOR_LAZY_IMPORT=$(echo $FIND_RETURN | xargs grep "lazy(() => import(.*$ABSOLUTE_COMPONENT_FILE_PATH.*)")
114 |
115 | COMPONENTS_OCURRENCES=$([[ -z "$GREP_RECURSIVE_RESULT" && -z "$GREP_RECURSIVE_RESULT_FOR_LAZY_IMPORT" ]] && echo 0 || (printf "$GREP_RECURSIVE_RESULT\n$GREP_RECURSIVE_RESULT_FOR_LAZY_IMPORT" | wc -l))
116 | COMMENTED_IMPORT_OCCURRENCES=$(printf "$GREP_RECURSIVE_RESULT\n$GREP_RECURSIVE_RESULT_FOR_LAZY_IMPORT" | grep // | wc -l)
117 |
118 | if [ "$COMPONENTS_OCURRENCES" = 0 ] || [ "$COMPONENTS_OCURRENCES" = "$COMMENTED_IMPORT_OCCURRENCES" ]; then
119 | ((COUNTER_UNUSED_COMPONENTS++))
120 | FILE_SIZE=$(fileSizeKB $COMPONENT_FILE_PATH)
121 | [[ -z $RAW ]] && printf "\e[39m%40s | \e[35m%s | \e[33m%s %s\n" $COMPONENT_NAME $COMPONENT_FILE_PATH $FILE_SIZE || echo "$COMPONENT_NAME | $COMPONENT_FILE_PATH | $FILE_SIZE"
122 | fi
123 | AUX_COUNTER=$COUNTER_UNUSED_COMPONENTS
124 | done
125 | }
126 |
127 | showResult() {
128 | handleResult "Results"
129 | if [ $COUNTER_UNUSED_COMPONENTS -eq 0 ]; then
130 | handleResult "No unused components found"
131 | else
132 | handleResult "$COUNTER_UNUSED_COMPONENTS possible dead components :/" '\e[0m'
133 | fi
134 | BROWSED_FILES=$(echo "${FIND_RETURN/ /\n}" | wc -l)
135 | handleResult "$BROWSED_FILES browsed files in $FINDEAD_TIME seconds"
136 | }
137 |
138 | handleResult() {
139 | [[ -z $RAW ]] && centerResult "$1" || echo "$1"
140 | }
141 |
142 | main() {
143 | searchFiles && getComponents && searchImports
144 | }
145 |
146 | initStyle() {
147 | TERM=xterm-256color
148 | tput -T xterm clear
149 | tput -T xterm cup 1 0
150 | tput -T xterm rev
151 | tput -T xterm bold
152 | center 'Findead is looking for components...'
153 | tput -T xterm sgr0
154 | tput -T xterm cup 3 0
155 | }
156 |
157 | start() {
158 | [[ -z $RAW ]] && initStyle
159 | PATH_TO_FIND=$1
160 | { time main; } 2>findead_execution_time.txt
161 | FINDEAD_TIME=$(cat findead_execution_time.txt)
162 | showResult
163 | rm -rf findead_execution_time.txt
164 | [[ -z $RAW ]] && unset TIMEFORMAT
165 | }
166 |
167 | if [[ $FIRST_ARGUMENT == "--version" || $FIRST_ARGUMENT == "-v" ]]; then
168 | echo "findead@1.2.3"
169 | elif [[ $FIRST_ARGUMENT == "--help" || $FIRST_ARGUMENT == "-h" ]]; then
170 | cat <