diff --git a/__tests__/data/css.ts b/__tests__/data/css.ts index 88efef9..4ae1554 100644 --- a/__tests__/data/css.ts +++ b/__tests__/data/css.ts @@ -1,4 +1,6 @@ export default ` +@charset "utf8"; + /*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ /* Document diff --git a/index.ts b/index.ts index 38bbe39..8a71763 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,7 @@ -export { default as Output } from './lib/interfaces/Output' +export { default as Output } from "./lib/interfaces/Output"; -import StaticStyles from './lib/StaticStyles' +import StaticStyles from "./lib/StaticStyles"; export default (html: string, css: string) => { - return new StaticStyles(html, css).get() -} + return new StaticStyles(html, css).get(); +}; diff --git a/lib/StaticStyles.ts b/lib/StaticStyles.ts index b66cc00..19b0b65 100644 --- a/lib/StaticStyles.ts +++ b/lib/StaticStyles.ts @@ -1,23 +1,43 @@ -import * as Css from 'css' +import * as Css from "css"; -import Context from './interfaces/Context' -import Output from './interfaces/Output' +import Context from "./interfaces/Context"; +import Output from "./interfaces/Output"; -import isPseudo from './isPseudo' -import convertToDom from './convertToDom' -import humanSize from './humanSize' +import convertToDom from "./convertToDom"; +import humanSize from "./humanSize"; +import isPseudo from "./isPseudo"; export default class StaticStyles { - private startTime: [number, number] - private context: Context + private startTime: [number, number]; + private context: Context; constructor( private html: string, - private css: string + private css: string, ) { - this.startTime = process.hrtime() + this.startTime = process.hrtime(); - this.context = convertToDom(html) + this.context = convertToDom(html); + } + + public get(): Output { + const ast = Css.parse(this.css); + + ast.stylesheet.rules = this.filterStyles(ast.stylesheet.rules); + + const compressedCss: string = Css.stringify(ast, { + compress: true, + }); + + return { + css: compressedCss, + stats: { + efficiency: 1 - (compressedCss.length / this.css.length), + input: humanSize(this.css.length), + output: humanSize(compressedCss.length), + timeSpent: this.getTimeSpend(), + }, + }; } private filterStyles(rules: any[]): any[] { @@ -25,65 +45,45 @@ export default class StaticStyles { if (rule.selectors) { const matches = rule.selectors.map((selector: string): boolean => { - const pseudo = isPseudo(selector) + const pseudo = isPseudo(selector); let matchingElements: NodeList; let matchingElementsArray: Node[] = []; if (pseudo) { - const selectorSet = selector.split(':') + const selectorSet = selector.split(":"); if (selectorSet[0] && selectorSet[0].length > 0) { selector = selectorSet[0]; } else { - return true + return true; } } try { - matchingElements = this.context.document.querySelectorAll(selector) - matchingElementsArray = Array.from(matchingElements) + matchingElements = this.context.document.querySelectorAll(selector); + matchingElementsArray = Array.from(matchingElements); } catch (error) {} - return matchingElementsArray.length > 0 - }) + return matchingElementsArray.length > 0; + }); if (matches.indexOf(true) === -1) { - rule.declarations = [] + rule.declarations = []; } } else if (rule.rules) { rule.rules = this.filterStyles(rule.rules); } - return rule - }) + return rule; + }); } private getTimeSpend(): [number, number] { - const currentTime: [number, number] = process.hrtime() + const currentTime: [number, number] = process.hrtime(); return [ currentTime[0] - this.startTime[0], - (currentTime[1] - this.startTime[1]) / 1000000 // get milli sec - ] - } - - public get(): Output { - const ast = Css.parse(this.css) - - ast.stylesheet.rules = this.filterStyles(ast.stylesheet.rules) - - const compressedCss: string = Css.stringify(ast, { - compress: true, - }) - - return { - stats: { - efficiency: 1 - (compressedCss.length / this.css.length), - timeSpent: this.getTimeSpend(), - input: humanSize(this.css.length), - output: humanSize(compressedCss.length), - }, - css: compressedCss, - } + (currentTime[1] - this.startTime[1]) / 1000000, // get milli sec + ]; } } diff --git a/lib/convertToDom.ts b/lib/convertToDom.ts index c6b21c6..27d0338 100644 --- a/lib/convertToDom.ts +++ b/lib/convertToDom.ts @@ -1,19 +1,19 @@ -import { JSDOM } from 'jsdom' +import { JSDOM } from "jsdom"; -import Context from './interfaces/Context' +import Context from "./interfaces/Context"; const convertToDom = (html: string): Context => { if (!html || html.length === 0) { - throw new Error('HTML not set') + throw new Error("HTML not set"); } - let jsdom: JSDOM = new JSDOM(html) + const jsdom: JSDOM = new JSDOM(html); return { + document: jsdom.window.document, jsdom, window: jsdom.window, - document: jsdom.window.document - } -} + }; +}; -export default convertToDom +export default convertToDom; diff --git a/lib/humanSize.ts b/lib/humanSize.ts index f333ad7..ca617ca 100644 --- a/lib/humanSize.ts +++ b/lib/humanSize.ts @@ -1,7 +1,7 @@ export default (size: number): string => { const i = Math.floor(Math.log(size) / Math.log(1024)); - const number: string = (size / Math.pow(1024, i)).toFixed(2) - const sizes: string[] = ['B', 'kB', 'MB', 'GB', 'TB'] + const sizeNumber: string = (size / Math.pow(1024, i)).toFixed(2); + const sizes: string[] = ["B", "kB", "MB", "GB", "TB"]; - return `${number} ${sizes[i]}` -} + return `${sizeNumber} ${sizes[i]}`; +}; diff --git a/lib/interfaces/Output.ts b/lib/interfaces/Output.ts index 10cfd3f..146659f 100644 --- a/lib/interfaces/Output.ts +++ b/lib/interfaces/Output.ts @@ -1,4 +1,4 @@ export default interface Output { - stats: object, - css: string, + stats: object; + css: string; } diff --git a/lib/isPseudo.ts b/lib/isPseudo.ts index 79809ba..d7eb029 100644 --- a/lib/isPseudo.ts +++ b/lib/isPseudo.ts @@ -7,28 +7,28 @@ export default (selector: string): boolean => { const ignoredPseudos: string[] = [ /* link */ - ':link', ':visited', + ":link", ":visited", /* user action */ - ':hover', ':active', ':focus', ':focus-within', + ":hover", ":active", ":focus", ":focus-within", /* UI element states */ - ':enabled', ':disabled', ':checked', ':indeterminate', + ":enabled", ":disabled", ":checked", ":indeterminate", /* form validation */ - ':required', ':invalid', ':valid', + ":required", ":invalid", ":valid", /* pseudo elements */ - '::first-line', '::first-letter', '::selection', '::before', '::after', + "::first-line", "::first-letter", "::selection", "::before", "::after", /* pseudo classes */ - ':target', + ":target", /* CSS2 pseudo elements */ - ':before', ':after', + ":before", ":after", /* Vendor-specific pseudo-elements: * https://developer.mozilla.org/ja/docs/Glossary/Vendor_Prefix */ - '::?-(?:moz|ms|webkit|o)-[a-z0-9-]+' + "::?-(?:moz|ms|webkit|o)-[a-z0-9-]+", ]; // Actual regex is of the format: /^(:hover|:focus|...)$/i - const pseudosRegex: RegExp = new RegExp('(' + ignoredPseudos.join('|') + ')', 'i'); - const matches: RegExpMatchArray | null = selector.match(pseudosRegex) + const pseudosRegex: RegExp = new RegExp("(" + ignoredPseudos.join("|") + ")", "i"); + const matches: RegExpMatchArray | null = selector.match(pseudosRegex); - return !!(matches && matches.length > 0) -} + return !!(matches && matches.length > 0); +}; diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..c74c612 --- /dev/null +++ b/tslint.json @@ -0,0 +1,26 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "variable-name": [ + true, + "ban-keywords", + "check-format" + ], + "interface-name": { + "options": [ + "never-prefix" + ] + } + }, + "rulesDirectory": [], + "linterOptions": { + "exclude": [ + "dist/**/*", + "node_modules/**/*" + ] + } +} diff --git a/yarn.lock b/yarn.lock index 7ec3b9c..03d1f67 100644 --- a/yarn.lock +++ b/yarn.lock @@ -725,10 +725,6 @@ tr46@^1.0.0: dependencies: punycode "^2.1.0" -tsc@^1.20150623.0: - version "1.20150623.0" - resolved "https://registry.yarnpkg.com/tsc/-/tsc-1.20150623.0.tgz#4ebc3c774e169148cbc768a7342533f082c7a6e5" - tslib@^1.8.0, tslib@^1.8.1: version "1.9.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"