diff --git a/package.json b/package.json index 2abd26a..4d479be 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "performance" ], "engines": { - "node": ">=8" + "node": ">=18" }, "scripts": { "pretest": "npm run build", @@ -48,4 +48,4 @@ "esbuild": "^0.16.17", "uvu": "^0.5.6" } -} +} \ No newline at end of file diff --git a/src/__fixtures__/bol-dot-com.txt b/src/__fixtures__/bol-dot-com.txt index 10e210e..2810fb0 100644 --- a/src/__fixtures__/bol-dot-com.txt +++ b/src/__fixtures__/bol-dot-com.txt @@ -1,16 +1,26 @@ ─────────────────────────────────────────────────────────── Lines of Code │ Filesize │ Rules │ Selectors │ Declarations -17,818 │ 468.9KB │ 4,801 │ 6,664 │ 10,083 +17,818 │ 468.9KB │ 4,801 │ 6,664 │ 10,083 ─────────────────────────────────────────────────────────── +Comments 0B (0 items) +Embedded Content 55.5KB (75 items) + Rulesets Most common Average Maximum -Selectors / rule 1 1.399 210 -Declarations / rule 1 2.093 25 +Selectors / rule 1 1.40 210 +Declarations / rule 1 2.09 25 +Empty rules 0 Selectors Most common Average Maximum -Complexity 1 2.369 13 +Complexity 1 2.37 13 Specificity 0/1/0 0/1.4/0.4 0/7/1 + Total Unique Ratio +All Selectors 6,664 4,298 64.5% +ID Selectors 0 0 0.0% +Accessibility 1 1 100.0% +Vendor prefixed 92 81 88.0% + AtRules Total Unique Unique % @media 986 23 2.3% @supports 5 3 60.0% @@ -18,15 +28,27 @@ AtRules Total Unique Unique % @import 0 0 0.0% @keyframes 19 19 100.0% @container 0 0 0.0% +@property 0 0 0.0% Declarations Total Unique Unique % -Declarations 10,083 1,797 17.8% +All Declarations 10,083 1,797 17.8% !important 1,589 +Properties Total Unique Unique % +All Properties 10,083 156 1.5% +Custom Properties 0 0 0.0% +Vendor Prefixed 104 20 19.2% +Browserhacks 0 0 0.0% + Values Total Unique Unique % Colors 1,151 89 7.7% +Gradients 6 5 83.3% Font-sizes 276 60 21.7% Font-families 46 8 17.4% +Line-heights 90 22 24.4% Text-shadows 1 1 100.0% Box-shadows 38 16 42.1% -Z-indexes 101 22 21.8% \ No newline at end of file +Z-indexes 101 22 21.8% +Vendor Prefixed 7 5 71.4% +Browserhacks 0 0 0.0% +Units 3,474 9 0.3% \ No newline at end of file diff --git a/src/__fixtures__/cnn.txt b/src/__fixtures__/cnn.txt index 6a3fcd4..0341ab9 100644 --- a/src/__fixtures__/cnn.txt +++ b/src/__fixtures__/cnn.txt @@ -1,16 +1,26 @@ ─────────────────────────────────────────────────────────── Lines of Code │ Filesize │ Rules │ Selectors │ Declarations -23,399 │ 795.8KB │ 4,893 │ 8,889 │ 13,265 +23,399 │ 795.8KB │ 4,893 │ 8,889 │ 13,265 ─────────────────────────────────────────────────────────── +Comments 2.7KB (93 items) +Embedded Content 0B (0 items) + Rulesets Most common Average Maximum -Selectors / rule 1 1.837 48 -Declarations / rule 1 2.674 29 +Selectors / rule 1 1.84 48 +Declarations / rule 1 2.67 29 +Empty rules 0 Selectors Most common Average Maximum -Complexity 5 5.674 18 +Complexity 5 5.67 18 Specificity 0/3/0 0.0/3.3/0.3 2/2/1 + Total Unique Ratio +All Selectors 8,889 6,593 74.2% +ID Selectors 298 197 66.1% +Accessibility 0 0 0.0% +Vendor prefixed 59 49 83.1% + AtRules Total Unique Unique % @media 1,081 188 17.4% @supports 0 0 0.0% @@ -18,15 +28,27 @@ AtRules Total Unique Unique % @import 0 0 0.0% @keyframes 20 20 100.0% @container 0 0 0.0% +@property 0 0 0.0% Declarations Total Unique Unique % -Declarations 13,265 2,886 21.8% +All Declarations 13,265 2,886 21.8% !important 132 +Properties Total Unique Unique % +All Properties 13,265 217 1.6% +Custom Properties 0 0 0.0% +Vendor Prefixed 1,263 80 6.3% +Browserhacks 8 8 100.0% + Values Total Unique Unique % Colors 1,370 126 9.2% +Gradients 66 57 86.4% Font-sizes 1,293 319 24.7% Font-families 398 19 4.8% +Line-heights 364 86 23.6% Text-shadows 9 6 66.7% Box-shadows 15 9 60.0% -Z-indexes 173 19 11.0% \ No newline at end of file +Z-indexes 173 19 11.0% +Vendor Prefixed 274 75 27.4% +Browserhacks 0 0 0.0% +Units 4,402 10 0.2% \ No newline at end of file diff --git a/src/__fixtures__/css-tricks.txt b/src/__fixtures__/css-tricks.txt index c00d429..6ea466c 100644 --- a/src/__fixtures__/css-tricks.txt +++ b/src/__fixtures__/css-tricks.txt @@ -1,16 +1,26 @@ ─────────────────────────────────────────────────────────── Lines of Code │ Filesize │ Rules │ Selectors │ Declarations -4,218 │ 100.7KB │ 956 │ 1,498 │ 2,633 +4,218 │ 100.7KB │ 956 │ 1,498 │ 2,633 ─────────────────────────────────────────────────────────── +Comments 212B (2 items) +Embedded Content 0B (0 items) + Rulesets Most common Average Maximum -Selectors / rule 1 1.577 32 -Declarations / rule 1 2.731 36 +Selectors / rule 1 1.58 32 +Declarations / rule 1 2.73 36 +Empty rules 0 Selectors Most common Average Maximum -Complexity 1 3.304 17 +Complexity 1 3.30 17 Specificity 0/1/0 0.0/1.4/0.8 1/2/3 + Total Unique Ratio +All Selectors 1,498 1,275 85.1% +ID Selectors 46 41 89.1% +Accessibility 2 2 100.0% +Vendor prefixed 31 31 100.0% + AtRules Total Unique Unique % @media 63 15 23.8% @supports 0 0 0.0% @@ -18,15 +28,27 @@ AtRules Total Unique Unique % @import 0 0 0.0% @keyframes 7 7 100.0% @container 0 0 0.0% +@property 0 0 0.0% Declarations Total Unique Unique % -Declarations 2,633 1,132 43.0% +All Declarations 2,633 1,132 43.0% !important 167 +Properties Total Unique Unique % +All Properties 2,633 221 8.4% +Custom Properties 54 48 88.9% +Vendor Prefixed 88 40 45.5% +Browserhacks 2 2 100.0% + Values Total Unique Unique % Colors 472 147 31.1% +Gradients 37 29 78.4% Font-sizes 108 46 42.6% Font-families 37 9 24.3% +Line-heights 34 18 52.9% Text-shadows 2 2 100.0% Box-shadows 19 13 68.4% -Z-indexes 32 13 40.6% \ No newline at end of file +Z-indexes 32 13 40.6% +Vendor Prefixed 18 10 55.6% +Browserhacks 0 0 0.0% +Units 1,080 9 0.8% \ No newline at end of file diff --git a/src/__fixtures__/small.txt b/src/__fixtures__/small.txt index 890c866..36876f1 100644 --- a/src/__fixtures__/small.txt +++ b/src/__fixtures__/small.txt @@ -1,16 +1,26 @@ ─────────────────────────────────────────────────────────── Lines of Code │ Filesize │ Rules │ Selectors │ Declarations -7 │ 173B │ 2 │ 2 │ 3 +7 │ 173B │ 2 │ 2 │ 3 ─────────────────────────────────────────────────────────── +Comments 0B (0 items) +Embedded Content 0B (0 items) + Rulesets Most common Average Maximum Selectors / rule 1 1 1 -Declarations / rule 1.500 1.500 2 +Declarations / rule 1.50 1.50 2 +Empty rules 0 Selectors Most common Average Maximum -Complexity 1.500 1.500 2 +Complexity 1.50 1.50 2 Specificity 0/0.5/1 0/0.5/1 0/1/0 + Total Unique Ratio +All Selectors 2 2 100.0% +ID Selectors 0 0 0.0% +Accessibility 0 0 0.0% +Vendor prefixed 0 0 0.0% + AtRules Total Unique Unique % @media 1 1 100.0% @supports 1 1 100.0% @@ -18,15 +28,27 @@ AtRules Total Unique Unique % @import 0 0 0.0% @keyframes 0 0 0.0% @container 0 0 0.0% +@property 0 0 0.0% Declarations Total Unique Unique % -Declarations 3 3 100.0% +All Declarations 3 3 100.0% !important 1 +Properties Total Unique Unique % +All Properties 3 3 100.0% +Custom Properties 0 0 0.0% +Vendor Prefixed 0 0 0.0% +Browserhacks 1 1 100.0% + Values Total Unique Unique % Colors 1 1 100.0% +Gradients 0 0 0.0% Font-sizes 0 0 0.0% Font-families 0 0 0.0% +Line-heights 0 0 0.0% Text-shadows 0 0 0.0% Box-shadows 0 0 0.0% Z-indexes 0 0 0.0% +Vendor Prefixed 0 0 0.0% +Browserhacks 0 0 0.0% +Units 0 0 0.0% diff --git a/src/__fixtures__/smashing-magazine.txt b/src/__fixtures__/smashing-magazine.txt index f80e351..db9fe2f 100644 --- a/src/__fixtures__/smashing-magazine.txt +++ b/src/__fixtures__/smashing-magazine.txt @@ -1,16 +1,26 @@ ─────────────────────────────────────────────────────────── Lines of Code │ Filesize │ Rules │ Selectors │ Declarations -18,239 │ 474.8KB │ 4,427 │ 5,748 │ 11,653 +18,239 │ 474.8KB │ 4,427 │ 5,748 │ 11,653 ─────────────────────────────────────────────────────────── +Comments 418B (4 items) +Embedded Content 42.4KB (47 items) + Rulesets Most common Average Maximum -Selectors / rule 1 1.335 30 -Declarations / rule 1 2.627 24 +Selectors / rule 1 1.33 30 +Declarations / rule 1 2.63 24 +Empty rules 0 Selectors Most common Average Maximum -Complexity 1 2.985 13 +Complexity 1 2.99 13 Specificity 0/1/0 0.0/1.6/0.5 1/4/0 + Total Unique Ratio +All Selectors 5,748 3,955 68.8% +ID Selectors 15 13 86.7% +Accessibility 29 29 100.0% +Vendor prefixed 150 103 68.7% + AtRules Total Unique Unique % @media 611 171 28.0% @supports 11 3 27.3% @@ -18,15 +28,27 @@ AtRules Total Unique Unique % @import 0 0 0.0% @keyframes 46 46 100.0% @container 0 0 0.0% +@property 0 0 0.0% Declarations Total Unique Unique % -Declarations 11,653 2,929 25.1% +All Declarations 11,653 2,929 25.1% !important 284 +Properties Total Unique Unique % +All Properties 11,653 228 2.0% +Custom Properties 78 20 25.6% +Vendor Prefixed 228 36 15.8% +Browserhacks 0 0 0.0% + Values Total Unique Unique % Colors 1,793 242 13.5% +Gradients 82 48 58.5% Font-sizes 462 101 21.9% Font-families 308 18 5.8% +Line-heights 127 38 29.9% Text-shadows 69 10 14.5% Box-shadows 76 44 57.9% -Z-indexes 86 19 22.1% \ No newline at end of file +Z-indexes 86 19 22.1% +Vendor Prefixed 162 20 12.3% +Browserhacks 0 0 0.0% +Units 5,037 12 0.2% \ No newline at end of file diff --git a/src/bin.js b/src/bin.js index 1c70300..45432b9 100644 --- a/src/bin.js +++ b/src/bin.js @@ -5,7 +5,7 @@ import { join } from 'path' import pc from 'picocolors' import { Program } from './program' -async function getStdin() { +async function get_stdin() { const { stdin } = process if (stdin.isTTY) { return '' @@ -20,19 +20,19 @@ async function getStdin() { return result } -async function readFile(pathParam) { - const pathName = join(process.cwd(), pathParam) +async function read_file(path_param) { + const pathName = join(process.cwd(), path_param) const content = await fsReadFile(pathName, 'utf-8') return content } async function main() { - const stdin = await getStdin() + const stdin = await get_stdin() return Program({ args: process.argv.slice(2), stdin, - readFile, - terminalColors: pc, + read_file, + terminal_colors: pc, }) } diff --git a/src/components.js b/src/components.js index 4aa9db8..4650ea2 100644 --- a/src/components.js +++ b/src/components.js @@ -1,4 +1,4 @@ -import { toFilesize, toNumber, toPercentage, padEnd, padStart } from './formatters.js' +import { to_filesize, to_number, to_percentage, pad_end, pad_start } from './formatters.js' const columns = [19, 12, 12, 12] const width = columns.reduce((total, num) => (total += num), 0) + columns.length @@ -7,9 +7,9 @@ export function Analytics(stats, style) { function Row(...tds) { return tds.map((td, index) => { if (index === 0) { - return padEnd(String(td), columns[index]) + return pad_end(String(td), columns[index]) } - return padStart(String(td), columns[index]) + return pad_start(String(td), columns[index]) }).join(' ') } @@ -28,17 +28,33 @@ export function Analytics(stats, style) { 'Declarations', ].join(style.dim(' │ ')), [ - style.bold(toNumber(stats.stylesheet.sourceLinesOfCode).padEnd('Lines of Code'.length)), - style.bold(toFilesize(stats.stylesheet.size).padEnd('Filesize'.length)), - style.bold(toNumber(stats.rules.total).padEnd('Rules'.length)), - style.bold(toNumber(stats.selectors.total).padEnd('Selectors'.length)), - style.bold(toNumber(stats.declarations.total).padEnd('Declarations'.length)), + style.bold(to_number(stats.stylesheet.sourceLinesOfCode).padEnd('Lines of Code'.length)), + style.bold(to_filesize(stats.stylesheet.size).padEnd('Filesize'.length)), + style.bold(to_number(stats.rules.total).padEnd('Rules'.length)), + style.bold(to_number(stats.selectors.total).padEnd('Selectors'.length)), + style.bold(to_number(stats.declarations.total)), ].join(style.dim(' │ ')), Hr(), ].join('\n') } + function Stylesheet(stylesheet) { + return [ + Row( + 'Comments', + to_filesize(stylesheet.comments.size), + style.dim(`(${stylesheet.comments.total} items)`), + ), + Row( + 'Embedded Content', + to_filesize(stylesheet.embeddedContent.size.total), + style.dim(`(${stylesheet.embeddedContent.total} items)`) + ) + ].join('\n') + } + function Rules(rules) { + let empty_count = to_number(rules.empty.total) return [ Row( style.underline('Rulesets'), @@ -48,16 +64,22 @@ export function Analytics(stats, style) { ), Row( `Selectors / rule`, - toNumber(rules.selectors.mode), - toNumber(rules.selectors.mean), - toNumber(rules.selectors.max), + to_number(rules.selectors.mode), + to_number(rules.selectors.mean), + to_number(rules.selectors.max), ), Row( `Declarations / rule`, - toNumber(rules.declarations.mode), - toNumber(rules.declarations.mean), - toNumber(rules.declarations.max), + to_number(rules.declarations.mode), + to_number(rules.declarations.mean), + to_number(rules.declarations.max), ), + Row( + `Empty rules`, + '', + '', + rules.empty.total > 0 ? style.red(empty_count) : empty_count + ) ].join('\n') } @@ -71,23 +93,54 @@ export function Analytics(stats, style) { ), Row( 'Complexity', - toNumber(selectors.complexity.mode), - toNumber(selectors.complexity.mean), - toNumber(selectors.complexity.max), + to_number(selectors.complexity.mode), + to_number(selectors.complexity.mean), + to_number(selectors.complexity.max), ), Row( 'Specificity', selectors.specificity.mode.join(style.dim('/')), selectors.specificity.mean - .map(n => toNumber(n, { decimals: 1 })) + .map(n => to_number(n, { decimals: 1 })) .join(style.dim('/')), selectors.specificity.max.join(style.dim('/')) ), + Row(), + Row( + '', + style.dim('Total'), + style.dim('Unique'), + style.dim('Ratio'), + ), + Row( + `All Selectors`, + to_number(selectors.total), + to_number(selectors.totalUnique), + to_percentage(selectors.uniquenessRatio), + ), + Row( + `ID Selectors`, + to_number(selectors.id.total), + to_number(selectors.id.totalUnique), + to_percentage(selectors.id.uniquenessRatio), + ), + Row( + `Accessibility`, + to_number(selectors.accessibility.total), + to_number(selectors.accessibility.totalUnique), + to_percentage(selectors.accessibility.uniquenessRatio), + ), + Row( + `Vendor prefixed`, + to_number(selectors.prefixed.total), + to_number(selectors.prefixed.totalUnique), + to_percentage(selectors.prefixed.uniquenessRatio), + ), ].join('\n') } function AtRules(atrules) { - const { media, supports, fontface, import: imports, keyframes, container } = atrules + const { media, supports, fontface, import: imports, keyframes, container, property } = atrules return [ Row( @@ -98,44 +151,50 @@ export function Analytics(stats, style) { ), Row( '@media', - toNumber(media.total), - toNumber(media.totalUnique), - toPercentage(media.uniquenessRatio), + to_number(media.total), + to_number(media.totalUnique), + to_percentage(media.uniquenessRatio), ), Row( '@supports', - toNumber(supports.total), - toNumber(supports.totalUnique), - toPercentage(supports.uniquenessRatio), + to_number(supports.total), + to_number(supports.totalUnique), + to_percentage(supports.uniquenessRatio), ), Row( '@font-face', - toNumber(fontface.total), - toNumber(fontface.totalUnique), - toPercentage(fontface.uniquenessRatio), + to_number(fontface.total), + to_number(fontface.totalUnique), + to_percentage(fontface.uniquenessRatio), ), Row( '@import', - toNumber(imports.total), - toNumber(imports.totalUnique), - toPercentage(imports.uniquenessRatio), + to_number(imports.total), + to_number(imports.totalUnique), + to_percentage(imports.uniquenessRatio), ), Row( '@keyframes', - toNumber(keyframes.total), - toNumber(keyframes.totalUnique), - toPercentage(keyframes.uniquenessRatio), + to_number(keyframes.total), + to_number(keyframes.totalUnique), + to_percentage(keyframes.uniquenessRatio), ), Row( '@container', - toNumber(container.total), - toNumber(container.totalUnique), - toPercentage(container.uniquenessRatio), + to_number(container.total), + to_number(container.totalUnique), + to_percentage(container.uniquenessRatio), + ), + Row( + '@property', + to_number(property.total), + to_number(property.totalUnique), + to_percentage(property.uniquenessRatio), ), ].join('\n') } - function Declarations(declarations) { + function Declarations(declarations, properties) { return [ Row( style.underline('Declarations'), @@ -144,15 +203,50 @@ export function Analytics(stats, style) { style.dim('Unique %'), ), Row( - 'Declarations', - toNumber(declarations.total), - toNumber(declarations.unique.total), - toPercentage(declarations.unique.ratio), + 'All Declarations', + to_number(declarations.total), + to_number(declarations.unique.total), + to_percentage(declarations.unique.ratio), ), Row( '!important', - toNumber(declarations.importants.total), - ) + to_number(declarations.importants.total), + ), + ].join('\n') + } + + function Properties(properties) { + return [ + Row( + style.underline('Properties'), + style.dim('Total'), + style.dim('Unique'), + style.dim('Unique %'), + ), + Row( + 'All Properties', + to_number(properties.total), + to_number(properties.totalUnique), + to_percentage(properties.uniquenessRatio) + ), + Row( + 'Custom Properties', + to_number(properties.custom.total), + to_number(properties.custom.totalUnique), + to_percentage(properties.custom.uniquenessRatio) + ), + Row( + 'Vendor Prefixed', + to_number(properties.prefixed.total), + to_number(properties.prefixed.totalUnique), + to_percentage(properties.prefixed.uniquenessRatio) + ), + Row( + 'Browserhacks', + to_number(properties.browserhacks.total), + to_number(properties.browserhacks.totalUnique), + to_percentage(properties.browserhacks.uniquenessRatio) + ), ].join('\n') } @@ -160,14 +254,14 @@ export function Analytics(stats, style) { function ValueRow(title, total, totalUnique, uniquenessRatio) { return Row( title, - toNumber(total), - toNumber(totalUnique), - toPercentage(uniquenessRatio), + to_number(total), + to_number(totalUnique), + to_percentage(uniquenessRatio), ) } const { - colors, fontSizes, fontFamilies, textShadows, boxShadows, zindexes + colors, gradients, fontSizes, fontFamilies, lineHeights, textShadows, boxShadows, zindexes, prefixes, browserhacks, units, } = values return [ @@ -177,18 +271,26 @@ export function Analytics(stats, style) { style.dim('Unique'), style.dim('Unique %'), ), - ValueRow('Colors', colors.total, colors.totalUnique, colors.uniquenessRatio,), - ValueRow('Font-sizes', fontSizes.total, fontSizes.totalUnique, fontSizes.uniquenessRatio,), - ValueRow('Font-families', fontFamilies.total, fontFamilies.totalUnique, fontFamilies.uniquenessRatio,), - ValueRow('Text-shadows', textShadows.total, textShadows.totalUnique, textShadows.uniquenessRatio,), - ValueRow('Box-shadows', boxShadows.total, boxShadows.totalUnique, boxShadows.uniquenessRatio,), - ValueRow('Z-indexes', zindexes.total, zindexes.totalUnique, zindexes.uniquenessRatio,), + ValueRow('Colors', colors.total, colors.totalUnique, colors.uniquenessRatio), + ValueRow('Gradients', gradients.total, gradients.totalUnique, gradients.uniquenessRatio), + ValueRow('Font-sizes', fontSizes.total, fontSizes.totalUnique, fontSizes.uniquenessRatio), + ValueRow('Font-families', fontFamilies.total, fontFamilies.totalUnique, fontFamilies.uniquenessRatio), + ValueRow('Line-heights', lineHeights.total, lineHeights.totalUnique, lineHeights.uniquenessRatio), + ValueRow('Text-shadows', textShadows.total, textShadows.totalUnique, textShadows.uniquenessRatio), + ValueRow('Box-shadows', boxShadows.total, boxShadows.totalUnique, boxShadows.uniquenessRatio), + ValueRow('Z-indexes', zindexes.total, zindexes.totalUnique, zindexes.uniquenessRatio), + + ValueRow('Vendor Prefixed', prefixes.total, prefixes.totalUnique, prefixes.uniquenessRatio), + ValueRow('Browserhacks', browserhacks.total, browserhacks.totalUnique, browserhacks.uniquenessRatio), + ValueRow('Units', units.total, units.totalUnique, units.uniquenessRatio), ].join('\n') } return [ Summary(stats), Row(), + Stylesheet(stats.stylesheet), + Row(), Rules(stats.rules), Row(), Selectors(stats.selectors), @@ -197,6 +299,8 @@ export function Analytics(stats, style) { Row(), Declarations(stats.declarations), Row(), + Properties(stats.properties), + Row(), Values(stats.values), ].join('\n') } \ No newline at end of file diff --git a/src/formatters.js b/src/formatters.js index fa6db99..a09e7ab 100644 --- a/src/formatters.js +++ b/src/formatters.js @@ -1,3 +1,5 @@ +let number_formatter = new Intl.NumberFormat() + /** * Format byte size to a human readable size, like 100KB * @param {number} number @@ -5,7 +7,7 @@ * @returns {string} * @see https://www.codexworld.com/how-to/convert-file-size-bytes-kb-mb-gb-javascript/ */ -export function toFilesize(bytes) { +export function to_filesize(bytes) { if (bytes == 0) return '0B' const sizes = ['B', 'KB', 'MB'] const step = 1000 @@ -13,17 +15,17 @@ export function toFilesize(bytes) { return parseFloat((bytes / Math.pow(step, magnitude)).toFixed(1)) + sizes[magnitude] } -export function toNumber(number, { decimals = 3 } = {}) { +export function to_number(number, { decimals = 2 } = {}) { return Number.isInteger(number) - ? new Intl.NumberFormat().format(number) + ? number_formatter.format(number) : number === 0 ? 0 : parseFloat(number).toFixed(decimals) } -export function toPercentage(number) { +export function to_percentage(number) { return String(parseFloat(number * 100).toFixed(1)) + '%' } -function strLength(str) { +function str_length(str) { // Basically strip ansi-characters from the string // source: https://github.com/usmanyunusov/nanospinner/blob/a80396e2f2613462399d39e664a690ec31a0da3f/index.js#L9 return str @@ -31,12 +33,12 @@ function strLength(str) { .length } -export function padEnd(str, padLength, padString) { - const length = strLength(str) +export function pad_end(str, padLength, padString) { + const length = str_length(str) return str + ''.padEnd(padLength - length, padString) } -export function padStart(str, padLength, padString) { - const length = strLength(str) +export function pad_start(str, padLength, padString) { + const length = str_length(str) return ''.padStart(padLength - length, padString) + str } \ No newline at end of file diff --git a/src/program.js b/src/program.js index 57debb2..fa44f86 100644 --- a/src/program.js +++ b/src/program.js @@ -2,38 +2,38 @@ import { analyze } from '@projectwallace/css-analyzer' import { help } from './help.js' import { Analytics } from './components.js' -export async function Program({ args, readFile, terminalColors, stdin }) { - const formatAsJson = '--json' - const helpArgs = ['-h', '--help'] +export async function Program({ args, read_file, terminal_colors, stdin }) { + const format_as_json = '--json' + const help_args = ['-h', '--help'] // Show help if the user explicitly asked for it - if (args.some(arg => helpArgs.includes(arg)) + if (args.some(arg => help_args.includes(arg)) // Show help if there's no input and no arguments provided || args.length === 0 && stdin === '') { - return help(terminalColors) + return help(terminal_colors) } // path is the first param that doesn't start with -- and isn't one // of the existing flags - const pathParam = args.find(arg => { - if (arg == formatAsJson) return false - if (helpArgs.includes(arg)) return false + const path_param = args.find(arg => { + if (arg == format_as_json) return false + if (help_args.includes(arg)) return false if (arg.startsWith('--')) return false return true }) - const css = pathParam ? await readFile(pathParam) : stdin + const css = path_param ? await read_file(path_param) : stdin if (!css) { - return help(terminalColors) + return help(terminal_colors) } const stats = analyze(css) delete stats.__meta__ // Format as JSON if user asked for it - if (args.some(arg => arg === formatAsJson)) { + if (args.some(arg => arg === format_as_json)) { return JSON.stringify(stats) } - return Analytics(stats, terminalColors) + return Analytics(stats, terminal_colors) } \ No newline at end of file diff --git a/src/program.test.js b/src/program.test.js index ec5cb8a..cade8cb 100644 --- a/src/program.test.js +++ b/src/program.test.js @@ -1,14 +1,21 @@ import { suite } from 'uvu' import * as assert from 'uvu/assert' -import fs from 'fs' +import fs from 'node:fs/promises' import { Program } from './program.js' import { help } from './help.js' -const cssFixture = fs.readFileSync('./src/__fixtures__/small.css', 'utf-8') -const resultFixture = fs.readFileSync('./src/__fixtures__/small.txt', 'utf-8') -const resultJson = JSON.parse(fs.readFileSync('./src/__fixtures__/small.json', 'utf-8')) - -const terminalColors = { +const [ + css_fixture, + cli_fixture, + result_json, +] = await Promise.all([ + fs.readFile('./src/__fixtures__/small.css', 'utf-8'), + fs.readFile('./src/__fixtures__/small.txt', 'utf-8'), + fs.readFile('./src/__fixtures__/small.json', 'utf-8') +]) +const result = JSON.parse(result_json) + +const terminal_colors = { bold: str => str, dim: str => str, underline: str => str, @@ -20,11 +27,11 @@ const ProgramSuite = suite('Program') ProgramSuite('wallace (no stdIn + no args)', async () => { const actual = await Program({ args: [], - readFile: () => Promise.resolve(), - terminalColors, + read_file: () => Promise.resolve(), + terminal_colors, stdin: '', }) - const expected = help(terminalColors) + const expected = help(terminal_colors) assert.equal(actual, expected) }) @@ -32,11 +39,11 @@ ProgramSuite('wallace (no stdIn + no args)', async () => { ProgramSuite('cat style.css | wallace --help', async () => { const actual = await Program({ args: ['--help'], - readFile: Promise.resolve, - terminalColors: terminalColors, - stdin: cssFixture, + read_file: Promise.resolve, + terminal_colors: terminal_colors, + stdin: css_fixture, }) - const expected = help(terminalColors) + const expected = help(terminal_colors) assert.equal(actual, expected) }) @@ -44,11 +51,11 @@ ProgramSuite('cat style.css | wallace --help', async () => { ProgramSuite('wallace style.css --help', async () => { const actual = await Program({ args: ['style.css', '--help'], - readFile: () => Promise.resolve(cssFixture), - terminalColors: terminalColors, + read_file: () => Promise.resolve(css_fixture), + terminal_colors: terminal_colors, stdin: '', }) - const expected = help(terminalColors) + const expected = help(terminal_colors) assert.equal(actual, expected) }) @@ -56,11 +63,11 @@ ProgramSuite('wallace style.css --help', async () => { ProgramSuite('cat style.css | wallace -h', async () => { const actual = await Program({ args: ['-h'], - readFile: Promise.resolve, - terminalColors: terminalColors, - stdin: cssFixture, + read_file: Promise.resolve, + terminal_colors: terminal_colors, + stdin: css_fixture, }) - const expected = help(terminalColors) + const expected = help(terminal_colors) assert.equal(actual, expected) }) @@ -68,11 +75,11 @@ ProgramSuite('cat style.css | wallace -h', async () => { ProgramSuite('wallace style.css -h', async () => { const actual = await Program({ args: ['style.css', '-h'], - readFile: () => Promise.resolve(cssFixture), - terminalColors: terminalColors, + read_file: () => Promise.resolve(css_fixture), + terminal_colors: terminal_colors, stdin: '', }) - const expected = help(terminalColors) + const expected = help(terminal_colors) assert.equal(actual, expected) }) @@ -80,31 +87,31 @@ ProgramSuite('wallace style.css -h', async () => { ProgramSuite('cat style.css | wallace', async () => { const actual = await Program({ args: [], - readFile: Promise.resolve, - terminalColors, - stdin: cssFixture, + read_file: Promise.resolve, + terminal_colors, + stdin: css_fixture, }) - assert.is(actual, resultFixture.trim()) + assert.is(actual, cli_fixture.trim()) }) ProgramSuite('cat style.css | wallace --json', async () => { const actual = await Program({ args: ['--json'], - readFile: Promise.resolve, - terminalColors, - stdin: cssFixture, + read_file: Promise.resolve, + terminal_colors, + stdin: css_fixture, }) - assert.equal(JSON.parse(actual), resultJson) + assert.equal(JSON.parse(actual), result) }) ProgramSuite('wallace non-existing.css', async () => { try { await Program({ args: ['non-existing.css'], - readFile: () => Promise.reject(new Error()), - terminalColors, + read_file: () => Promise.reject(new Error()), + terminal_colors, stdin: '', }) assert.unreachable() @@ -116,23 +123,23 @@ ProgramSuite('wallace non-existing.css', async () => { ProgramSuite('wallace style.css', async () => { const actual = await Program({ args: ['style.css'], - readFile: () => Promise.resolve(cssFixture), - terminalColors, + read_file: () => Promise.resolve(css_fixture), + terminal_colors, stdin: '', }) - assert.is(actual, resultFixture.trim()) + assert.is(actual, cli_fixture.trim()) }) ProgramSuite('wallace style.css --json', async () => { const actual = await Program({ args: ['style.css', '--json'], - readFile: () => Promise.resolve(cssFixture), - terminalColors, + read_file: () => Promise.resolve(css_fixture), + terminal_colors, stdin: '', }) - assert.equal(JSON.parse(actual), resultJson) + assert.equal(JSON.parse(actual), result) }) ProgramSuite.run() diff --git a/src/smoke.test.js b/src/smoke.test.js index 48355a6..c3a66c9 100644 --- a/src/smoke.test.js +++ b/src/smoke.test.js @@ -1,13 +1,14 @@ import { suite } from 'uvu' import * as assert from 'uvu/assert' -import fs from 'fs' +import { readFile } from 'node:fs/promises' import { analyze } from '@projectwallace/css-analyzer' import { Analytics } from './components.js' -const terminalColors = { +const terminal_colors = { bold: str => str, dim: str => str, underline: str => str, + red: str => str, } const Smoke = suite('Smoke Tests') @@ -18,11 +19,13 @@ Object.entries({ 'CNN': 'cnn', 'Smashing Magazine': 'smashing-magazine', }).map(([name, fileName]) => { - Smoke(name, () => { - const css = fs.readFileSync(`./src/__fixtures__/${fileName}.css`, 'utf-8') - const expected = fs.readFileSync(`./src/__fixtures__/${fileName}.txt`, 'utf-8') + Smoke(name, async () => { + const [css, expected] = await Promise.all([ + readFile(`./src/__fixtures__/${fileName}.css`, 'utf-8'), + readFile(`./src/__fixtures__/${fileName}.txt`, 'utf-8'), + ]) const stats = analyze(css) - const actual = Analytics(stats, terminalColors) + const actual = Analytics(stats, terminal_colors) // fs.writeFileSync(`./src/__fixtures__/${fileName}.txt`, actual) assert.equal(actual, expected) })