cleanstyles
Advanced tools
Comparing version 1.0.8 to 1.0.9
{ | ||
"name": "cleanstyles", | ||
"version": "1.0.8", | ||
"description": "project to detect unused stylesheet in react-native codebase(coded by jasbirrana)", | ||
"version": "1.0.9", | ||
"description": "project to detect unused stylesheet in react-native codebase", | ||
"main": "src/index.js", | ||
@@ -12,3 +12,3 @@ "type": "module", | ||
"lint:fix": "eslint --fix", | ||
"cleanit":"node src/index.js" | ||
"cleanit": "node src/index.js" | ||
}, | ||
@@ -23,4 +23,6 @@ "bin": "./src/index.js", | ||
"chalk": "^5.2.0", | ||
"figlet": "^1.5.2", | ||
"inquirer": "^9.1.4", | ||
"lodash-contrib": "^4.1200.1" | ||
"lodash": "^4.17.21", | ||
"shelljs": "^0.8.5" | ||
}, | ||
@@ -27,0 +29,0 @@ "devDependencies": { |
159
src/index.js
#!/usr/bin/env node | ||
import chalk from "chalk"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
import chalk from "chalk"; | ||
import { strContains } from "lodash-contrib"; | ||
import inquirer from "inquirer"; | ||
import { fromDir, getObjectStyleFromFile,removeNullFromAray } from "./utils.js"; | ||
import { logUnusedProperty } from "./logger.js"; | ||
import figlet from "figlet"; | ||
import { | ||
getFilesInDir, | ||
getUsedStyles, | ||
isStyleImported, | ||
searchForStyles, | ||
} from "./utils.js"; | ||
import { askQuestions } from "./logger.js"; | ||
const dirname_ = | ||
"/Users/jasbirrana/Desktop/Jasbirrana/HRx_portal/app/containers/health-pay/components/payment-summary-drawer"; | ||
const checkAllUnusedStyle = () => { | ||
// const questions = [ | ||
// { | ||
// type: "input", | ||
// name: "path", | ||
// message: "Your starting path? (eg ./app/containers/health-pay)", | ||
// }, | ||
// ]; | ||
// let START_PATH; | ||
// inquirer.prompt(questions).then((answers) => { | ||
// START_PATH = answers.path; | ||
// }); | ||
// console.log("script is running?") | ||
const values = []; | ||
fromDir("./app/containers/health-pay", "styles.ts", values); | ||
const styles = getUnusedStyle(values); | ||
if (styles.length > 0) { | ||
const countError = styles.reduce((sum, item) => sum + item.length, 0); | ||
console.log(chalk.red.bold(`\n ✖ Encontrado -->${countError} problem \n`)); | ||
process.exit(500); | ||
} else { | ||
console.log(chalk.green.bold("All good")); | ||
} | ||
}; | ||
const getUnusedStyle = (pathStyles) => | ||
pathStyles | ||
.map((pathStyle) => { | ||
const data = fs.readFileSync(pathStyle, "utf-8"); | ||
const values = getObjectStyleFromFile(data); | ||
if (!values) { | ||
return; | ||
const findUnusedStyles = (dir) => { | ||
const styles = searchForStyles(dir); | ||
Object.keys(styles).forEach((stylePath) => { | ||
let importName; | ||
getFilesInDir(dir).forEach((file) => { | ||
if (file !== stylePath) { | ||
const fileContents = fs.readFileSync(file, "utf8"); | ||
if ( | ||
isStyleImported( | ||
stylePath, | ||
path.basename(stylePath), | ||
file, | ||
fileContents | ||
) | ||
) { | ||
importName = path.basename(stylePath).split(".")[0]; | ||
} | ||
} | ||
}); | ||
const styles = values.map((item) => `styles.${item}`); | ||
if (importName) { | ||
let usedStyles; | ||
getFilesInDir(dir).forEach((file) => { | ||
if (file !== stylePath) { | ||
const fileContents = fs.readFileSync(file, "utf8"); | ||
usedStyles = getUsedStyles( | ||
importName, | ||
styles[stylePath], | ||
fileContents | ||
); | ||
} | ||
}); | ||
const currentStyleDir = path.dirname(pathStyle); | ||
const unusedStyles = styles[stylePath].filter( | ||
(styleKey) => !usedStyles.has(styleKey) | ||
); | ||
const filesInCwd = fs.readdirSync(currentStyleDir); | ||
let correspondingIndexFilePath; | ||
if ( | ||
filesInCwd.indexOf("styles.ts") !== -1 && | ||
filesInCwd.indexOf("index.tsx") !== -1 | ||
) { | ||
correspondingIndexFilePath = pathStyle.replace( | ||
"styles.ts", | ||
"index.tsx" | ||
if (unusedStyles.length > 0) { | ||
console.log( | ||
chalk.bold.italic.magentaBright(`Unused styles in ${stylePath}`) | ||
); | ||
unusedStyles.forEach((unusedStyle) => { | ||
console.log(chalk.bold.red(`-> styles.${unusedStyle}`)); | ||
}); | ||
} | ||
} | ||
}); | ||
}; | ||
if ( | ||
filesInCwd.indexOf("styles.js") !== -1 && | ||
filesInCwd.indexOf("index.js") !== -1 | ||
) { | ||
correspondingIndexFilePath = pathStyle.replace( | ||
"styles.ts", | ||
"index.tsx" | ||
); | ||
} | ||
const init = async () => { | ||
console.log( | ||
chalk.green( | ||
figlet.textSync("CLEAN IT UP", { | ||
font: "Ghost", | ||
horizontalLayout: "default", | ||
verticalLayout: "default", | ||
whitespaceBreak: false, | ||
}) | ||
) | ||
); | ||
const { path } = await askQuestions(); | ||
if (correspondingIndexFilePath) { | ||
const indexData = fs.readFileSync(correspondingIndexFilePath, "utf-8"); | ||
let unusedStyles = styles.map((item) => | ||
indexData.indexOf(item) === -1 ? item : null | ||
); | ||
unusedStyles = removeNullFromAray(unusedStyles); | ||
console.log(chalk.white.bgGreen.bold(`Your Starting Path is:${path}`)); | ||
console.log( | ||
chalk.red.bold( | ||
`\n -> ${correspondingIndexFilePath} (${unusedStyles?.length}) \n` | ||
) | ||
); | ||
unusedStyles.forEach((item) => { | ||
logUnusedProperty(item); | ||
}); | ||
return unusedStyles; | ||
} | ||
return null; | ||
}) | ||
.filter((item) => item); | ||
findUnusedStyles( | ||
"/Users/jasbirrana/Desktop/Jasbirrana/HRx_portal/app/containers/health-pay/screens" | ||
); | ||
}; | ||
checkAllUnusedStyle(); | ||
init(); |
@@ -1,16 +0,13 @@ | ||
import chalk from "chalk"; | ||
import { strContains } from "lodash-contrib"; | ||
export const logUnusedProperty = (item) => { | ||
if (item) { | ||
if (strContains(item, "create")) { | ||
const splitedUnusedStyle = item?.split(".create({"); | ||
console.log( | ||
chalk.bold.underline( | ||
` -> styles.${splitedUnusedStyle[splitedUnusedStyle?.length - 1]}` | ||
) | ||
); | ||
} else { | ||
console.log(chalk.bold.underline(` -> ${item}`)); | ||
} | ||
} | ||
import inquirer from "inquirer"; | ||
export const askQuestions = () => { | ||
const questions = [ | ||
{ | ||
type: "input", | ||
name: "path", | ||
message: "Your starting path? (eg ./app/containers/health-pay)", | ||
}, | ||
]; | ||
return inquirer.prompt(questions); | ||
}; |
149
src/utils.js
import path from "path"; | ||
import fs from "fs"; | ||
export const getFilesInDir = (dir) => { | ||
const files = []; | ||
fs.readdirSync(dir).forEach((file) => { | ||
if (file !== ".DS_Store") { | ||
const filePath = path.join(dir, file); | ||
if (fs.lstatSync(filePath).isDirectory()) { | ||
files.push(...getFilesInDir(filePath)); | ||
} else { | ||
files.push(filePath); | ||
} | ||
} | ||
}); | ||
return files; | ||
}; | ||
const TAG_START = "{"; | ||
const TAG_END = "}"; | ||
const TAG_IGNORE = "//check-style disable"; | ||
export const fromDir = (startPath, filter, values) => { | ||
if (startPath.indexOf("node_modules") >= 0 || !fs.existsSync(startPath)) { | ||
return; | ||
} | ||
const files = fs.readdirSync(startPath); | ||
for (let index = 0; index < files.length; index++) { | ||
const filename = path.join(startPath, files[index]); | ||
const stat = fs.lstatSync(filename); | ||
if (stat.isDirectory()) { | ||
fromDir(filename, filter, values); | ||
} else if (filename.indexOf(filter) >= 0) { | ||
values.push(filename); | ||
export const extractStyleObject = (data) => { | ||
const temp = data.split("StyleSheet.create({")?.[1]?.split("});")?.[0]; | ||
const keys = temp.split(": {").map((text) => { | ||
const k = text.split(" "); | ||
const t = text.split(","); | ||
if (t.length) { | ||
const l = t[t.length - 2]; | ||
if (l && !l?.includes?.("}")) return undefined; | ||
} | ||
} | ||
return k[k.length - 1]; | ||
}); | ||
return keys.filter((s) => !!s).slice(0, -1); | ||
}; | ||
export const getObjectStyleFromFile = (file) => { | ||
if (file.includes(TAG_IGNORE)) { | ||
return []; | ||
} | ||
let valueWithoutHeader; | ||
if (file.indexOf("export const styles = ") !== -1) { | ||
valueWithoutHeader = file | ||
.slice(file.indexOf("export const styles = ") + 21) | ||
.replace(/;/g, "") | ||
.replace(/ /g, ""); | ||
} | ||
if (file.indexOf("export default") !== -1) { | ||
valueWithoutHeader = file | ||
.slice(file.indexOf("export default") + 14) | ||
.replace(/;/g, "") | ||
.replace(/ /g, ""); | ||
} | ||
valueWithoutHeader = valueWithoutHeader.slice( | ||
0, | ||
valueWithoutHeader.lastIndexOf("}") | ||
); | ||
let index = null; | ||
const gotIndex = []; | ||
for (let i = valueWithoutHeader.length; i > 0; i--) { | ||
const letter = valueWithoutHeader[i - 1]; | ||
if (letter === TAG_START) { | ||
if (index) { | ||
if (gotIndex.length > 0) { | ||
gotIndex.pop(); | ||
} else { | ||
const value = valueWithoutHeader.substring(i - 2, index); | ||
valueWithoutHeader = valueWithoutHeader.replace(value, ""); | ||
index = null; | ||
} | ||
export const searchForStyles = (pathString) => { | ||
let styles = {}; | ||
const files = fs.readdirSync(pathString); | ||
files.forEach((file) => { | ||
if (file.startsWith(".")) { | ||
return; | ||
} | ||
const filePath = path.resolve(pathString, file); | ||
const isDir = fs.lstatSync(filePath).isDirectory(); | ||
if (isDir) { | ||
styles = { ...styles, ...searchForStyles(filePath) }; | ||
} else { | ||
const fileContents = fs.readFileSync(filePath, { | ||
encoding: "utf8", | ||
flag: "r", | ||
}); | ||
if (fileContents.includes("StyleSheet.create({")) { | ||
styles[filePath] = extractStyleObject(fileContents); | ||
} | ||
} else if (letter === TAG_END) { | ||
if (index) { | ||
gotIndex.push(i); | ||
} else { | ||
index = i; | ||
} | ||
} | ||
}); | ||
return styles; | ||
}; | ||
export const isStyleImported = ( | ||
stylePath, | ||
styleName, | ||
filePath, | ||
fileContents | ||
) => { | ||
const styleExtension = `.${styleName.split(".")[1]}`; | ||
const importStatements = | ||
fileContents.match(/import\s.+from\s(?:'|")(.+)(?:'|");/g) || []; | ||
for (const statement of importStatements) { | ||
let importPath = statement.split("from")[1].trim().slice(1, -2); | ||
if (!path.isAbsolute(importPath)) { | ||
importPath = path.join(path.dirname(filePath), importPath); | ||
} | ||
if (importPath + styleExtension === stylePath) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
let stringObject = valueWithoutHeader.replace(/\r?\n|\r/g, ""); | ||
export const getUsedStyles = (importName, styleKeys, fileContents) => { | ||
const usedStyles = new Set(); | ||
const temp = styleKeys.filter((key) => { | ||
return fileContents.includes(`${importName}.${key}`); | ||
}); | ||
if (stringObject && stringObject[stringObject.length - 1] === ",") { | ||
stringObject = stringObject.substring(0, stringObject.length - 1); | ||
for (const key of temp) { | ||
usedStyles.add(key); | ||
} | ||
return stringObject.split(","); | ||
}; | ||
export const removeNullFromAray = (array) => { | ||
return array.filter((ele) => ele !== null); | ||
}; | ||
return usedStyles; | ||
}; |
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
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
5
1
1
5891
5
168
1
+ Addedfiglet@^1.5.2
+ Addedlodash@^4.17.21
+ Addedshelljs@^0.8.5
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedfiglet@1.8.0(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedglob@7.2.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinterpret@1.4.0(transitive)
+ Addedis-core-module@2.16.1(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedrechoir@0.6.2(transitive)
+ Addedresolve@1.22.10(transitive)
+ Addedshelljs@0.8.5(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
+ Addedwrappy@1.0.2(transitive)
- Removedlodash-contrib@^4.1200.1
- Removedlodash@4.12.0(transitive)
- Removedlodash-contrib@4.1200.1(transitive)