Skip to content

Commit

Permalink
feat: ✨ added commit linting!
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed Jan 25, 2020
1 parent 288f1d5 commit 2d52f2c
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 26 deletions.
65 changes: 54 additions & 11 deletions src/cli.ts
@@ -1,4 +1,4 @@
import chalk, { ColorSupport } from "chalk"
import chalk from "chalk"
import { Command } from "commander"
import * as fs from "fs"
import * as path from "path"
Expand All @@ -14,20 +14,62 @@ export class Cli {
constructor(public program: Command, public devmoji: Devmoji) {
this.commits = new ConventionalCommits(devmoji)
this.opts = program.opts()
if (this.opts.edit) {
this.opts.color = false
chalk.level = 0
}

lint(text: string) {
text = text.split("\n")[0]
const errors = []
const match = /^(?<type>:?[a-z-]+)(?:\((?<scope>[a-z-]+)\))?(!?):\s+(?<description>.*)/iu.exec(
text
)
if (match) {
const type = match.groups?.type ?? ""
const scope = match.groups?.scope
const description = match.groups?.description

if (type.toLocaleLowerCase() != type) {
errors.push(`Type '${type}' should be lower case`)
}
if (!this.devmoji.config.options.types.includes(type)) {
errors.push(
`Type should be one of: ${chalk.grey(
this.devmoji.config.options.types.join(", ")
)}`
)
}
if (scope && scope.toLocaleLowerCase() != scope) {
errors.push(`Scope '${scope}' should be lower case`)
}
if (!description || description.trim().length == 0)
errors.push("Missing description")
} else {
errors.push(`Expecting a commit message like:`)
errors.push(
` ${chalk.blue("type" + chalk.bold("(scope):")) +
chalk.dim(" description")}`
)
}
if (errors.length) {
errors.push("Get help at https://www.conventionalcommits.org/")
}

errors.forEach(e => console.error(chalk.red("✖"), e))
if (errors.length) process.exit(1)
}

format(
text: string,
format = "unicode",
processCommit = false,
processLog = false
processLog = false,
color = this.opts.color
) {
if (processCommit && !processLog) text = this.commits.formatCommit(text)
if (processCommit && this.opts.lint && !processLog) {
this.lint(text)
}
if (processLog) text = this.commits.formatLog(text)
else if (processCommit)
text = this.commits.formatCommit(text, color ? true : false)
switch (format) {
case "unicode":
return this.devmoji.emojify(text)
Expand Down Expand Up @@ -64,7 +106,7 @@ export class Cli {
}

error(msg: string) {
console.error(chalk.red("[error] ") + msg)
console.error(chalk.red("error ") + msg)
process.exit(1)
}

Expand All @@ -85,7 +127,7 @@ export class Cli {
"-t|--text <text>",
"text to format. reads from stdin when omitted"
)
.option("--lint", "lint the conventional commits")
.option("--lint", "lint the conventional commit. disabled for --log")
.option(
"-f|--format <format>",
"format should be one of: unicode, shortcode, devmoji",
Expand All @@ -105,7 +147,7 @@ export class Cli {
.option(
"--color",
"use colors for formatting. Colors are enabled by default, unless output is piped to another command",
((chalk.supportsColor as ColorSupport)?.level ?? 0) > 0
chalk.level > 0
)
.option("--no-color", "don't use colors")
.version(require("../package.json").version, "--version")
Expand All @@ -131,9 +173,10 @@ export class Cli {
}
if (commitMsgFile && fs.existsSync(commitMsgFile)) {
let text = fs.readFileSync(commitMsgFile, "utf-8")
text = this.format(text, opts.format, opts.commit)
text = this.format(text, opts.format, opts.commit, false, false)
const out = this.format(text, opts.format, opts.commit, false, true)
fs.writeFileSync(commitMsgFile, text, "utf-8")
return console.log(text)
return console.log(chalk.green("✔"), out)
} else {
this.error("Couldn't find .git/COMMIT_EDITMSG")
}
Expand Down
23 changes: 8 additions & 15 deletions src/conventional-commits.ts
Expand Up @@ -2,22 +2,15 @@ import { Devmoji } from "./devmoji"
import chalk from "chalk"

export class ConventionalCommits {
regex = /(?<type>:?[a-z-]+)(?:\((?<scope>[a-z-]+)\))?(!?):\s*(?:(?<other>(?::[a-z-]+:\s*)+)\s*)?/gm
regex = /(?<type>:?[a-z-]+)(?:\((?<scope>[a-z-]+)\))?(!?):\s*(?:(?<other>(?::[a-z-]+:\s*)+)\s*)?/gmu
constructor(public devmoji: Devmoji) {}

lint(text: string) {
// ⧗ input: featf: test
// ✖ type must be one of [build, chore, ci, docs, feat, fix, improvement, perf, refactor, revert, style, test] [type-enum]
// ✖ found 1 problems, 0 warnings
// ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
formatCommit(text: string, color = false) {
return this.format(text, true, color)
}

formatCommit(text: string) {
return this.format(text, true)
}

formatLog(text: string) {
return this.format(text, false)
formatLog(text: string, color = false) {
return this.format(text, false, color)
}

formatEmoji(type: string, scope?: string, other?: string, breaking = false) {
Expand Down Expand Up @@ -55,7 +48,7 @@ export class ConventionalCommits {
return ret.join(" ")
}

format(text: string, firstOnly = false) {
format(text: string, firstOnly = false, color = false) {
text = this.devmoji.devmojify(text)
return this.devmoji.emojify(
text.replace(
Expand All @@ -78,10 +71,10 @@ export class ConventionalCommits {
)
if (!emoji.length) return match
let ret = type
if (scope) ret += chalk.bold(`(${scope})`)
if (scope) ret += color ? chalk.bold(`(${scope})`) : `(${scope})`
if (breaking) ret += "!"
ret += ":"
ret = chalk.blue(ret)
ret = color ? chalk.blue(ret) : ret
ret = ret + ` ${emoji}`
const ws = match.search(/\s*$/)
if (ws > 0) ret += match.substring(ws)
Expand Down

0 comments on commit 2d52f2c

Please sign in to comment.