Skip to content

Commit

Permalink
chore: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
meteorlxy committed Jul 31, 2019
0 parents commit ad93ca3
Show file tree
Hide file tree
Showing 13 changed files with 1,832 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .eslintrc.js
@@ -0,0 +1,10 @@
module.exports = {
root: true,

extends: [
'standard',
'prettier/standard',
'plugin:vue/recommended',
'plugin:prettier-vue/recommended',
],
}
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
node_modules/
*.log
59 changes: 59 additions & 0 deletions .prettierrc.js
@@ -0,0 +1,59 @@
module.exports = {
// Maximum line length
printWidth: 120,

// Specify the number of spaces per indentation-level
tabWidth: 2,

// Indent lines with tabs instead of spaces
useTabs: false,

// Use semicolons or not
semi: false,

// Use single quotes instead of double quotes
singleQuote: true,

// Change when properties in objects are quoted
quoteProps: 'as-needed',

// Use single quotes instead of double quotes in JSX
jsxSingleQuote: false,

// Print trailing commas wherever possible when multi-line
trailingComma: 'es5',

// Print spaces between brackets in object literals.
bracketSpacing: true,

// Put the `>` of a multi-line JSX element at the end of the last line instead of being alone on the next line (does not apply to self closing elements)
jsxBracketSameLine: false,

// Include parentheses around a sole arrow function parameter
arrowParens: 'avoid',

// Format only a segment of a file.
rangeStart: 0,
rangeEnd: Infinity,

// Specify which parser to use.
// parser: undefined,

// Specify the file name to use to infer which parser to use.
// filepath: undefined,

// Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file.
requirePragma: false,

// Prettier can insert a special @format marker at the top of files specifying that the file has been formatted with prettier.
insertPragma: false,

// By default, Prettier will wrap markdown text as-is since some services use a linebreak-sensitive renderer, e.g. GitHub comment and BitBucket.
proseWrap: 'preserve',

// Specify the global whitespace sensitivity for HTML files
htmlWhitespaceSensitivity: 'css',

// End of line
endOfLine: 'lf',
};
10 changes: 10 additions & 0 deletions .vscode/settings.json
@@ -0,0 +1,10 @@
{
"eslint.validate": [
"javascript",
{
"language": "vue",
"autoFix": true
}
],
"vetur.validation.template": false,
}
9 changes: 9 additions & 0 deletions LICENSE
@@ -0,0 +1,9 @@
MIT License

Copyright (c) 2019 meteorlxy & contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 changes: 34 additions & 0 deletions README.md
@@ -0,0 +1,34 @@
# eslint-plugin-prettier-vue

> Forked from [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), with some refactor and modifications.
Make prettier work better with [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue).

With the help of this plugin, you can stop prettier processing the `<template>` block of `.vue` files, so that you can following the [Vue Style Guide](https://vuejs.org/v2/style-guide/) to write your `<template>`.

## Usage

### Installation

```sh
npm install --save-dev eslint-plugin-prettier-vue eslint-plugin-vue eslint-config-prettier eslint prettier
```

### ESLint Config

```js
// .eslintrc.js
module.exports = {
extends: [
'plugin:vue/recommended',
'plugin:prettier-vue/recommended',
],
}
```

- __DO NOT__ use `eslint-plugin-prettier` together. This plugin is based on `eslint-plugin-prettier` so you do not need it.
- __DO NOT__ add `extends: ['prettier/vue']`, as you need the rules from `eslint-plugin-vue` to lint the `<template>` block of `.vue` files.

## LICENSE

[MIT](https://github.com/meteorlxy/eslint-plugin-prettier-vue/blob/master/LICENSE) &copy; [@meteorlxy](https://github.com/meteorlxy) & [Contributors](https://github.com/meteorlxy/eslint-plugin-prettier-vue/graphs/contributors)
20 changes: 20 additions & 0 deletions lib/configs.js
@@ -0,0 +1,20 @@
module.exports = {
recommended: {
/**
* extends `eslint-config-prettier`
*/
extends: ['prettier'],

/**
* use this plugin
*/
plugins: ['prettier-vue'],

/**
* use prettier rules
*/
rules: {
'prettier-vue/prettier': 'error',
},
},
}
7 changes: 7 additions & 0 deletions lib/index.js
@@ -0,0 +1,7 @@
const configs = require('./configs')
const rules = require('./rules')

module.exports = {
configs,
rules,
}
185 changes: 185 additions & 0 deletions lib/rules.js
@@ -0,0 +1,185 @@
const path = require('path')
const vueTemplateCompiler = require('vue-template-compiler')
const { parse } = require('@vue/component-compiler-utils')
const { generateDifferences } = require('prettier-linter-helpers')
const { reportInsert, reportDelete, reportReplace } = require('./utils/report')
const { INSERT, DELETE, REPLACE } = generateDifferences

// Lazily-loaded Prettier.
let prettier

module.exports = {
prettier: {
meta: {
docs: {
url: 'https://github.com/prettier/eslint-plugin-prettier#options',
},
fixable: 'code',
schema: [
// Prettier options:
{
type: 'object',
properties: {},
additionalProperties: true,
},
{
type: 'object',
properties: {
usePrettierrc: { type: 'boolean' },
fileInfoOptions: {
type: 'object',
properties: {},
additionalProperties: true,
},
},
additionalProperties: true,
},
],
},
create(context) {
const usePrettierrc = !context.options[1] || context.options[1].usePrettierrc !== false
const eslintFileInfoOptions = (context.options[1] && context.options[1].fileInfoOptions) || {}
const sourceCode = context.getSourceCode()
const filepath = context.getFilename()
let source = sourceCode.text

if (prettier && prettier.clearConfigCache) {
prettier.clearConfigCache()
}

/**
* Handle Vue SFC
*/
let vueOffset = 0
if (filepath.endsWith('.vue')) {
const descriptor = parse({
source,
compiler: vueTemplateCompiler,
filename: path.basename(filepath),
})

const vueSourceScript = descriptor.script.content
.replace(/^(\/\/\n)*/, '')
.replace(/^([\s\S]*)$/, '<script>$1</script>\n')
source = vueSourceScript
vueOffset = descriptor.script.start - '<script>'.length
}

return {
Program() {
if (!prettier) {
// Prettier is expensive to load, so only load it if needed.
prettier = require('prettier')
}

const eslintPrettierOptions = context.options[0] || {}

const prettierRcOptions = usePrettierrc
? prettier.resolveConfig.sync(filepath, {
editorconfig: true,
})
: null

const prettierFileInfo = prettier.getFileInfo.sync(
filepath,
Object.assign({}, { ignorePath: '.prettierignore' }, eslintFileInfoOptions)
)

// Skip if file is ignored using a .prettierignore file
if (prettierFileInfo.ignored) {
return
}

const initialOptions = {}

// ESLint suppports processors that let you extract and lint JS
// fragments within a non-JS language. In the cases where prettier
// supports the same language as a processor, we want to process
// the provided source code as javascript (as ESLint provides the
// rules with fragments of JS) instead of guessing the parser
// based off the filename. Otherwise, for instance, on a .md file we
// end up trying to run prettier over a fragment of JS using the
// markdown parser, which throws an error.
// If we can't infer the parser from from the filename, either
// because no filename was provided or because there is no parser
// found for the filename, use javascript.
// This is added to the options first, so that
// prettierRcOptions and eslintPrettierOptions can still override
// the parser.
//
// `parserBlocklist` should contain the list of prettier parser
// names for file types where:
// * Prettier supports parsing the file type
// * There is an ESLint processor that extracts JavaScript snippets
// from the file type.
const parserBlocklist = [null, 'graphql', 'markdown', 'html']
if (parserBlocklist.indexOf(prettierFileInfo.inferredParser) !== -1) {
// Prettier v1.16.0 renamed the `babylon` parser to `babel`
// Use the modern name if available
const supportBabelParser = prettier
.getSupportInfo()
.languages.some(language => language.parsers.includes('babel'))

initialOptions.parser = supportBabelParser ? 'babel' : 'babylon'
}

const prettierOptions = Object.assign({}, initialOptions, prettierRcOptions, eslintPrettierOptions, {
filepath,
})

// prettier.format() may throw a SyntaxError if it cannot parse the
// source code it is given. Ususally for JS files this isn't a
// problem as ESLint will report invalid syntax before trying to
// pass it to the prettier plugin. However this might be a problem
// for non-JS languages that are handled by a plugin. Notably Vue
// files throw an error if they contain unclosed elements, such as
// `<template><div></template>. In this case report an error at the
// point at which parsing failed.
let prettierSource
try {
prettierSource = prettier.format(source, prettierOptions)
} catch (err) {
if (!(err instanceof SyntaxError)) {
throw err
}

let message = 'Parsing error: ' + err.message

// Prettier's message contains a codeframe style preview of the
// invalid code and the line/column at which the error occured.
// ESLint shows those pieces of information elsewhere already so
// remove them from the message
if (err.codeFrame) {
message = message.replace(`\n${err.codeFrame}`, '')
}
if (err.loc) {
message = message.replace(/ \(\d+:\d+\)$/, '')
}

context.report({ message, loc: err.loc })

return
}

if (source !== prettierSource) {
const differences = generateDifferences(source, prettierSource)

differences.forEach(difference => {
switch (difference.operation) {
case INSERT:
reportInsert(context, difference.offset + vueOffset, difference.insertText)
break
case DELETE:
reportDelete(context, difference.offset + vueOffset, difference.deleteText)
break
case REPLACE:
reportReplace(context, difference.offset + vueOffset, difference.deleteText, difference.insertText)
break
}
})
}
},
}
},
},
}

0 comments on commit ad93ca3

Please sign in to comment.