Navigation Menu

Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
masaakim committed Jun 29, 2017
1 parent 3fab41e commit 56043a3
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 75 deletions.
25 changes: 5 additions & 20 deletions cli.js
Expand Up @@ -28,7 +28,6 @@ const chalk = require('chalk')
const JsDiff = require('diff')
const chokidar = require('chokidar')


if (argv.v) {
console.log(pkg.version)
process.exit()
Expand Down Expand Up @@ -56,12 +55,8 @@ if (argv.r) {
const globby = require('globby')
globby([path.join(argv.r)].concat(argv._)).then(processMultipleFiles)
} else if (argv.w) {
let opts = {
ignoreInitial: true
}
if (argv.i) {
opts.ignored = argv.i
}
let opts = { ignoreInitial: true }
argv.i && (opts.ignored = argv.i)
let watcher = chokidar.watch(argv.w, opts)
let log = console.log.bind(console)
const format = filePath => {
Expand All @@ -81,14 +76,10 @@ if (argv.r) {
}
watcher
.on('add', filePath => {
if (format(filePath)) {
log(chalk.yellow(`Added ${filePath} file has been formatted`))
}
format(filePath) && log(chalk.yellow(`Added ${filePath} file has been formatted`))
})
.on('change', filePath => {
if (format(filePath)) {
log(chalk.green(`Changed ${filePath} file has been formatted`))
}
format(filePath) && log(chalk.green(`Changed ${filePath} file has been formatted`))
})
} else if (argv._[0]) {
const input = argv._[0]
Expand All @@ -113,14 +104,12 @@ if (argv.r) {
})
}


function processMultipleFiles (files) {
files = files.filter(isTargetFile).sort()
if (!files.length) {
console.error("Files glob patterns specified did not match any css files.")
return
}

Promise.all(files.map(file => {
const fullPath = path.resolve(process.cwd(), file)
const css = fs.readFileSync(fullPath, 'utf-8')
Expand All @@ -135,9 +124,7 @@ function processMultipleFiles (files) {
return handleDiff(file, css, formatted)
} else if (css !== formatted) {
fs.writeFile(fullPath, formatted, err => {
if (err) {
throw err
}
if (err) throw err
})
return file
}
Expand All @@ -159,12 +146,10 @@ function processMultipleFiles (files) {
})
}


function isTargetFile (filePath) {
return /^\.css|\.scss$/i.test(path.extname(filePath))
}


function handleDiff (file, original, formatted) {
let diff
if (original === formatted) {
Expand Down
2 changes: 1 addition & 1 deletion docs/scss/app.scss
Expand Up @@ -44,7 +44,7 @@ code.code-block {
code.code-inline {
display: inline-block;
background-color: #eee;
padding: 0 0.2rem
padding: 0 0.2rem;
}

.font-code {
Expand Down
80 changes: 26 additions & 54 deletions index.js
Expand Up @@ -2,99 +2,71 @@ const os = require('os')
const postcss = require('postcss')
const scss = require('postcss-scss')

const NEW_LINE = os.EOL
const NO_SPACES = ''
const ONE_SPACE = ' '
const TWO_SPACES = ' '
const NEW_LINE = os.EOL, NO_SPACES = '', ONE_SPACE = ' ', TWO_SPACES = ' '
const isCustomProperty = prop => prop.slice(0, 2) === '--'
const isSassVal = prop => /^\$/.test(prop)
const hasPlusInsideParens = selector => /\(.+\+.+\)/.test(selector)
const isAttrSelector = selector => /\[.+\]/.test(selector)
const isOneLinearRule = rule => rule.nodes.length === 1 && rule.nodes[0].type === 'decl' && !rule.nodes[0].raws.before.match(/\n/) && !rule.raws.after.match(/\n/) && !rule.raws.between.match(/\n/) && rule.selectors.length === 1
const countNewLine = str => str.split(NEW_LINE).length - 1
const getIndent = node => TWO_SPACES.repeat(getDepth(node))

const getDepth = node => {
let parent = node.parent
let num = 0
while (parent.type !== 'root') {
parent = parent.parent
num++
}
while (parent.type !== 'root') { parent = parent.parent; num++ }
return num
}

const getNodeBefore = (node, indentation) => {
let nodeBefore = node.type === 'decl' ? NEW_LINE + indentation : NO_SPACES
const prev = node.prev()
if (prev || node.parent.type !== 'root') {
if (node.type !== 'decl') nodeBefore = NEW_LINE + indentation
if (node.prev() || node.parent.type !== 'root') {
node.type !== 'decl' && (nodeBefore = NEW_LINE + indentation)
const nlCount = countNewLine(node.raws.before)
if (nlCount) nodeBefore = NEW_LINE.repeat(nlCount) + indentation
nlCount && (nodeBefore = NEW_LINE.repeat(nlCount) + indentation)
}
return nodeBefore
}

const isCustomProperty = prop => prop.slice(0, 2) === '--'
const isSassVal = prop => /^\$/.test(prop)
const hasPlusInsideParens = selector => /\(.+\+.+\)/.test(selector)
const isAttrSelector = selector => /\[.+\]/.test(selector)
const isOneLinearRule = rule => rule.nodes.length === 1 && rule.nodes[0].type === 'decl' && !rule.nodes[0].raws.before.match(/\n/) && !rule.raws.after.match(/\n/) && !rule.raws.between.match(/\n/) && rule.selectors.length === 1
const countNewLine = str => str.split(NEW_LINE).length - 1
const getIndent = node => TWO_SPACES.repeat(getDepth(node))

const plugin = postcss.plugin('scssfmt', () => {
const plugin = postcss.plugin('scssfmt', _ => {
return root => {
root.walkRules(rule => {
const indentation = getIndent(rule)
if (isOneLinearRule(rule)) {
rule.onelinear = true
rule.raws.after = ONE_SPACE
} else {
rule.raws.after = NEW_LINE + indentation
}

isOneLinearRule(rule) && (rule.onelinear = true)
rule.raws.before = getNodeBefore(rule, indentation)
rule.raws.between = ONE_SPACE
rule.raws.semicolon = true

if (rule.raws.selector) {
rule.selector = rule.raws.selector.raw
} else {
let tmp = []
let selector
rule.raws.after = isOneLinearRule(rule) ? ONE_SPACE : NEW_LINE + indentation
if (rule.raws.selector) rule.selector = rule.raws.selector.raw
else {
let tmp = [], selector
const separator = `,${NEW_LINE}` + indentation
rule.selectors.forEach(selector => {
if (!hasPlusInsideParens(selector) && !isAttrSelector(selector)) selector = selector.replace(/\s*([+~>])\s*/g, " $1 ").trim()
if (isAttrSelector(selector)) selector = selector.replace(/\[\s*(\S+)\s*\]/g, "[$1]")
selector = !hasPlusInsideParens(selector) && !isAttrSelector(selector) ? selector.replace(/\s*([+~>])\s*/g, " $1 ").trim() : isAttrSelector(selector) && selector.replace(/\[\s*(\S+)\s*\]/g, "[$1]")
tmp.push(selector)
})
rule.selector = tmp.join(separator)
}
})

root.walkDecls(decl => {
const indentation = getIndent(decl)
const declValue = decl.raws.value
if (declValue) decl.raws.value.raw = declValue.raw.trim()
decl.raws.before = decl === root.first ? NO_SPACES : getNodeBefore(decl, indentation)
decl.raws.value && (decl.raws.value.raw = decl.raws.value.raw.trim())
decl.raws.before = decl === root.first ? NO_SPACES : getNodeBefore(decl, getIndent(decl))
decl.raws.between = `:${ONE_SPACE}`
if (decl.parent.type === 'rule' && decl.parent.onelinear) {
decl.raws.before = ONE_SPACE
}
if (decl.raws.important) decl.raws.important = `${ONE_SPACE}!important`
decl.parent.type === 'rule' && decl.parent.onelinear && (decl.raws.before = ONE_SPACE)
decl.raws.important && (decl.raws.important = `${ONE_SPACE}!important`)
})

root.walkAtRules(atrule => {
const indentation = getIndent(atrule)
const exception = atrule.name === 'else'
atrule.raws.before = exception ? atrule.raws.before : getNodeBefore(atrule, indentation)
atrule.raws.before = atrule.name === 'else' ? atrule.raws.before : getNodeBefore(atrule, indentation)
atrule.raws.after = NEW_LINE + indentation
atrule.raws.between = atrule.nodes ? ONE_SPACE : NO_SPACES
atrule.raws.afterName = atrule.params ? ONE_SPACE : NO_SPACES
if (atrule.raws.semicolon !== undefined) atrule.raws.semicolon = true
atrule.raws.semicolon !== undefined && (atrule.raws.semicolon = true)
})
}
})

const scssfmt = (css, options) => {
options = options || {}
options.syntax = scss
return postcss([plugin()]).process(css, options).css
}

module.exports = scssfmt
module.exports = (css, options = { syntax: scss }) => postcss([plugin()]).process(css, options).css
module.exports.plugin = plugin

0 comments on commit 56043a3

Please sign in to comment.