Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds prettier as a formatter for .html and Vue files. Uses ESLint and Stylelint for Vue linting, choosing ESLint as a default. Resolves: #7
- Loading branch information
1 parent
f2f73ad
commit f91653a
Showing
7 changed files
with
334 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { IntrospectFn } from "../deps.ts"; | ||
import { | ||
introspect as introspectPrettier, | ||
Prettier, | ||
} from "../_shared/prettier/mod.ts"; | ||
|
||
// deno-lint-ignore no-empty-interface | ||
interface Deno {} | ||
|
||
export type Formatters = { | ||
prettier?: Prettier | null; | ||
deno?: Deno; | ||
} | null; | ||
|
||
function anyValue(records: Record<string, unknown>): boolean { | ||
return Object.values(records).some((v) => v); | ||
} | ||
|
||
export const introspect: IntrospectFn<Formatters> = async (context) => { | ||
const logger = context.getLogger("html"); | ||
logger.debug("detecting formatter"); | ||
|
||
const prettier = await introspectPrettier(context); | ||
if (prettier !== null) { | ||
logger.debug("detected Prettier"); | ||
} | ||
|
||
const formatters: Formatters = { | ||
prettier, | ||
}; | ||
|
||
if (anyValue(formatters)) return formatters; | ||
|
||
if (context.suggestDefault) { | ||
logger.warning("No Vue or Html formatter detected, using Prettier"); | ||
return { | ||
prettier: { name: "prettier", hasIgnoreFile: false }, | ||
}; | ||
} | ||
|
||
logger.debug("no supported formatter detected"); | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { IntrospectFn } from "../deps.ts"; | ||
|
||
import { | ||
ESLint, | ||
introspect as introspectESLint, | ||
} from "../_shared/eslint/mod.ts"; | ||
|
||
import { | ||
introspect as introspectStylelint, | ||
Stylelint, | ||
} from "../_shared/stylelint/mod.ts"; | ||
|
||
// deno-lint-ignore no-empty-interface | ||
interface Deno {} | ||
|
||
export type Linters = { | ||
eslint?: ESLint | null; | ||
stylelint?: Stylelint | null; | ||
deno?: Deno; | ||
} | null; | ||
|
||
function anyValue(records: Record<string, unknown>): boolean { | ||
return Object.values(records).some((v) => v); | ||
} | ||
|
||
export const introspect: IntrospectFn<Linters> = async (context) => { | ||
const logger = context.getLogger("html"); | ||
logger.debug("detecting linter"); | ||
|
||
const eslint = await introspectESLint(context); | ||
if (eslint !== null) { | ||
logger.debug("detected ESLint"); | ||
} | ||
|
||
const styleLint = await introspectStylelint(context); | ||
if (styleLint !== null) { | ||
logger.debug("detected stylelint"); | ||
} | ||
|
||
const linters = { | ||
eslint, | ||
styleLint, | ||
}; | ||
|
||
if (anyValue(linters)) return linters; | ||
|
||
if (context.suggestDefault) { | ||
logger.warning("No Vue or HTML linter detected, using ESLint"); | ||
return { | ||
eslint: { name: "eslint", hasIgnoreFile: false }, | ||
}; | ||
} | ||
|
||
logger.debug("no supported linter detected"); | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { context } from "../../../src/plugin/mod.ts"; | ||
import { assertEquals, deepMerge, WalkEntry } from "../../../deps.ts"; | ||
|
||
import { introspector } from "./mod.ts"; | ||
|
||
Deno.test("Plugins > Html has stylelint and eslint configured", async () => { | ||
const fakeContext = deepMerge( | ||
context, | ||
{ | ||
files: { | ||
// deno-lint-ignore require-await | ||
includes: async (glob: string): Promise<boolean> => { | ||
if (glob === "**/.eslintrc.{js,cjs,yaml,yml,json}") { | ||
return true; | ||
} | ||
return false; | ||
}, | ||
each: async function* (glob: string): AsyncIterableIterator<WalkEntry> { | ||
if (glob === "**/*.{html,vue}") { | ||
yield { | ||
name: "test.html", | ||
path: "fake-path", | ||
isFile: true, | ||
isSymlink: false, | ||
isDirectory: false, | ||
}; | ||
yield { | ||
name: "test.vue", | ||
path: "fake-path", | ||
isFile: true, | ||
isSymlink: false, | ||
isDirectory: false, | ||
}; | ||
} | ||
if (glob === "**/package.json") { | ||
yield { | ||
name: "package.json", | ||
path: "fake-path", | ||
isFile: true, | ||
isSymlink: false, | ||
isDirectory: false, | ||
}; | ||
} | ||
if (glob === "**/.eslintrc.{js,cjs,yaml,yml,json}") { | ||
yield { | ||
name: ".eslintrc.js", | ||
path: "fake-path", | ||
isFile: true, | ||
isSymlink: false, | ||
isDirectory: false, | ||
}; | ||
} | ||
if (glob === "**/.eslintignore") { | ||
yield { | ||
name: ".eslintignore", | ||
path: "fake-path", | ||
isFile: true, | ||
isSymlink: false, | ||
isDirectory: false, | ||
}; | ||
} | ||
return; | ||
}, | ||
// deno-lint-ignore require-await | ||
readJSON: async (path: string): Promise<Record<string, unknown>> => { | ||
const deps = { stylelint: "1.0.0", eslint: "7.2.2" }; | ||
if (path === "fake-path") { | ||
return { devDependencies: deps }; | ||
} | ||
return {}; | ||
}, | ||
}, | ||
}, | ||
); | ||
const result = await introspector.introspect( | ||
fakeContext, | ||
); | ||
|
||
assertEquals(result, { | ||
runtime: { name: "node", version: "16" }, | ||
packageManager: { name: "npm" }, | ||
linters: { | ||
eslint: { name: "eslint", hasIgnoreFile: false }, | ||
styleLint: { name: "stylelint" }, | ||
}, | ||
formatters: { prettier: { name: "prettier", hasIgnoreFile: false } }, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { Introspector } from "../deps.ts"; | ||
import { Formatters, introspect as introspectFormatter } from "./formatters.ts"; | ||
import { introspect as introspectLinter, Linters } from "./linters.ts"; | ||
import { | ||
introspect as introspectRuntime, | ||
Runtime, | ||
} from "../javascript/runtime.ts"; | ||
import { | ||
introspect as introspectPackageManager, | ||
NodePackageManager, | ||
} from "../_shared/node_package_manager/mod.ts"; | ||
|
||
// Available package managers | ||
type PackageManager = NodePackageManager | null; | ||
|
||
/** | ||
* Introspected information about a project with JavaScript | ||
*/ | ||
export default interface HtmlProject { | ||
/** | ||
* Which package manager is used in the project | ||
* | ||
* A package manager may not exist in a JavaScript project. | ||
* For example, a project that uses Deno doesn't need to use | ||
* npm, yarn or any other package manager. | ||
*/ | ||
packageManager?: PackageManager; | ||
/** | ||
* Which runtime the project uses | ||
*/ | ||
runtime: Runtime; | ||
/** | ||
* Which linter the project uses, if any | ||
*/ | ||
linters: Linters; | ||
/** | ||
* Which formatter the project uses, if any | ||
*/ | ||
formatters: Formatters; | ||
} | ||
|
||
export const introspector: Introspector<HtmlProject> = { | ||
detect: async (context) => { | ||
return await context.files.includes("**/*.{html,vue}"); | ||
}, | ||
introspect: async (context) => { | ||
const logger = context.getLogger("html"); | ||
|
||
// Runtime | ||
logger.debug("detecting runtime"); | ||
const runtime = await introspectRuntime(context); | ||
logger.debug(`detected runtime "${runtime.name}"`); | ||
if (runtime.name === "deno") { | ||
return { | ||
runtime, | ||
linters: { | ||
deno: {}, | ||
}, | ||
formatters: { | ||
deno: {}, | ||
}, | ||
}; | ||
} | ||
|
||
// Package manager | ||
logger.debug("detecting package manager"); | ||
const packageManager = await introspectPackageManager(context); | ||
logger.debug(`detected package manager "${packageManager.name}"`); | ||
// Linter and Formatter | ||
const linters = await introspectLinter(context); | ||
logger.debug(`detecting linters for html`); | ||
const formatters = await introspectFormatter(context); | ||
|
||
return { | ||
runtime, | ||
packageManager, | ||
linters, | ||
formatters, | ||
}; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,24 @@ | ||
import { introspector as CssIntrospector } from "./css/mod.ts"; | ||
import { introspector as JavaScriptIntrospector } from "./javascript/mod.ts"; | ||
import { introspector as PythonIntrospector } from "./python/mod.ts"; | ||
import { introspector as HtmlIntrospector } from "./html/mod.ts"; | ||
|
||
import type CSSProject from "./css/mod.ts"; | ||
import type JavaScriptProject from "./javascript/mod.ts"; | ||
import type PythonProject from "./python/mod.ts"; | ||
import type HtmlProject from "./html/mod.ts"; | ||
|
||
export type ProjectData = | ||
| CSSProject | ||
| JavaScriptProject | ||
| PythonProject; | ||
| PythonProject | ||
| HtmlProject; | ||
|
||
export type { CSSProject, JavaScriptProject, PythonProject }; | ||
export type { CSSProject, HtmlProject, JavaScriptProject, PythonProject }; | ||
|
||
export const introspectors = [ | ||
{ name: "css", ...CssIntrospector }, | ||
{ name: "javascript", ...JavaScriptIntrospector }, | ||
{ name: "python", ...PythonIntrospector }, | ||
{ name: "html", ...HtmlIntrospector }, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<% if (it.runtime.name === "node" && it.formatters) { -%> | ||
name: Format HTML | ||
on: | ||
pull_request: | ||
paths: | ||
- '**.html' | ||
- '**.vue' | ||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '<%= it.runtime.version %>' | ||
cache: '<%= it.packageManager.name %>' | ||
|
||
<%_ let installCmd; -%> | ||
<%_ if (it.packageManager.name === "npm") { -%> | ||
<%_ installCmd = "npm ci" %> | ||
<%_ } else { -%> | ||
<%_ installCmd = "yarn" %> | ||
<% } -%> | ||
|
||
- run: <%= installCmd %> | ||
<%_ if (it.formatters.prettier) { %> | ||
- run: npx prettier --no-error-on-unmatched-pattern --check "**/*.vue" "**/*.html" | ||
<% } -%> | ||
<% } -%> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<% if (it.runtime.name === "node" && it.linters) { -%> | ||
name: Lint Vue | ||
on: | ||
pull_request: | ||
paths: | ||
- '**.vue' | ||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '<%= it.runtime.version %>' | ||
cache: '<%= it.packageManager.name %>' | ||
|
||
<%_ let installCmd; -%> | ||
<%_ if (it.packageManager.name === "npm") { -%> | ||
<%_ installCmd = "npm ci" %> | ||
<%_ } else { -%> | ||
<%_ installCmd = "yarn" %> | ||
<% } -%> | ||
|
||
- run: <%= installCmd %> | ||
<%_ if (it.linters.eslint) { %> | ||
- run: npx eslint --ext .vue . | ||
<% } -%> | ||
<%_ if (it.linters.styleLint) { %> | ||
- run: npx stylelint --aei **/*.vue | ||
<% } -%> | ||
<% } -%> |