Repository: azeemba/eslint-plugin-json
Branch: master
Commit: b381b1583161
Files: 36
Total size: 42.4 KB
Directory structure:
gitextract_qzrczb7v/
├── .eslintignore
├── .eslintrc
├── .github/
│ └── workflows/
│ └── node.js.yml
├── .gitignore
├── .npmignore
├── .nycrc
├── LICENSE.txt
├── README.md
├── examples/
│ ├── .eslintrc
│ ├── package.json
│ └── samples/
│ ├── duplicate-keys.json
│ ├── good-json.json
│ ├── json-with-comments.json
│ ├── whole-mess.json
│ └── wrong-syntax.json
├── package.json
├── src/
│ └── index.js
├── test/
│ ├── .eslintrc.with-recommended-comments-config.mjs
│ ├── .eslintrc.with-recommended-comments-legacy-config.json
│ ├── .eslintrc.with-recommended-config.mjs
│ ├── .eslintrc.with-recommended-legacy-config.json
│ ├── custom.eslintrc-legacy.json
│ ├── custom.eslintrc.config.mjs
│ ├── integration-across-eslint-majors.sh
│ ├── integration-legacy.test.js
│ ├── integration.test.js
│ ├── packages/
│ │ ├── eslint-v7-legacy/
│ │ │ └── package.json
│ │ ├── eslint-v8/
│ │ │ └── package.json
│ │ ├── eslint-v8-legacy/
│ │ │ └── package.json
│ │ └── eslint-v9/
│ │ └── package.json
│ └── unit.test.js
└── vendor/
└── eslint-plugin-self/
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── index.js
└── package.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
test/packages
================================================
FILE: .eslintrc
================================================
{
"env": {
"node": true,
"mocha": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 2017
},
"plugins": ["prettier"],
"extends": ["eslint:recommended"],
"rules": {
"prettier/prettier": ["warn", {
"singleQuote": true,
"tabWidth": 4,
"printWidth": 100,
"bracketSpacing": false
}],
"no-console": "error"
},
"overrides": [
{
"files": "*.mjs",
"parserOptions": {
"sourceType": "module"
}
}
]
}
================================================
FILE: .github/workflows/node.js.yml
================================================
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test
- run: npm run integration ci 7-legacy 8-legacy 8 9 # eslint versions
- run: npm run integration test 7-legacy 8-legacy 8 9 # eslint versions
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
verbose: true
directory: coverage
================================================
FILE: .gitignore
================================================
node_modules
private
tmp
coverage
.nyc_output
example/package-lock.json
.vscode/
.idea/
================================================
FILE: .npmignore
================================================
test
examples
private
tmp
coverage
.npmignore
.eslintrc
.github
.vscode
.nycrc
.eslintignore
vendor
================================================
FILE: .nycrc
================================================
{
"all": true,
"include": ["src"],
"reporter": ["text", "text-summary", "lcov"]
}
================================================
FILE: LICENSE.txt
================================================
The MIT License (MIT)
Copyright (c) 2015-2021 Azeem Bande-Ali
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.
================================================
FILE: README.md
================================================
# eslint-plugin-json
[](https://www.npmjs.com/package/eslint-plugin-json)
[](https://github.com/azeemba/eslint-plugin-json/actions/workflows/node.js.yml)
[](https://codecov.io/gh/azeemba/eslint-plugin-json)
[](https://codeclimate.com/github/azeemba/eslint-plugin-json)
> Eslint plugin for JSON files
:warning: If you are using eslint v9 or newer, use eslint-plugin-json v4 or newer.
## Installation
Install `eslint-plugin-json` along [`eslint`](http://eslint.org):
```shell
$ npm install --save-dev eslint eslint-plugin-json
# or
$ yarn add --dev eslint eslint-plugin-json
```
**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-json` globally.
## Usage
### Basic configuration (Flat Config ESLint Format)
The `json` plugin ship with two recommended config you can use to easily activate it via the `extends` key.
It comes in two flavor: one strict (`recommended`) and one allowing comments `recommended-with-comments`.
```js
import json from 'eslint-plugin-json';
export default [
{
files: ["**/*.json"],
...json.configs["recommended"]
}
];
```
### Basic configuration (Legacy ESLint Format)
The `json` plugin ship with two recommended config you can use to easily activate it via the `extends` key.
It comes in two flavor: one strict (`recommended-legacy`) and one allowing comments `recommended-with-comments-legacy`.
```json
{
"extends": ["plugin:json/recommended-legacy"]
}
```
You can run ESLint on individual JSON files or you can use the `--ext` flag to add JSON files to the list.
```
eslint . --ext .json,.js
eslint example.json
```
### Custom Configuration (Flat Config ESLint Format)
If you want more granular control over which rules, and which severity you want.
If you want them all, add the `json/json` rule (or its alias `json/*`). (this is what the `recommended` config does)
#### Global rules
The global rules (`json/json` or its alias `json/*`) activate all the rules.
Note it can be configured to ignore errors cause by comments.
To do so, add option `'allowComments'` or `{allowComments: true}`
For instance:
```js
import json from "eslint-plugin-json";
export default [
{
files: ["**/*.json"],
plugins: { json },
processor: "json/json"
"rules": {
"json/*": ["error", "allowComments"],
// or the equivalent:
"json/*": ["error", {"allowComments": true}]
}
},
];
```
### Custom Configuration (Legacy ESLint Format)
If you want more granular control over which rules, and which severity you want.
Add `json` to the list of plugins (You can omit the `eslint-plugin-` prefix)
Then pick your rules.
If you want them all, add the `json/json` rule (or its alias `json/*`). (this is what the `recommended-legacy` config does)
#### Global rules
The global rules (`json/json` or its alias `json/*`) activate all the rules.
Note it can be configured to ignore errors cause by comments.
To do so, add option `'allowComments'` or `{allowComments: true}`
For instance:
```json
{
"plugins": [
"json"
],
"rules": {
"json/*": ["error", "allowComments"],
// or the equivalent:
"json/*": ["error", {"allowComments": true}]
}
}
```
#### Individual Rules
Here is the list of individual rules (with name in `kebab-case`)in case you want granular error/warning level:
- `json/undefined`
- `json/enum-value-mismatch`
- `json/unexpected-end-of-comment`
- `json/unexpected-end-of-string`
- `json/unexpected-end-of-number`
- `json/invalid-unicode`
- `json/invalid-escape-character`
- `json/invalid-character`
- `json/property-expected`
- `json/comma-expected`
- `json/colon-expected`
- `json/value-expected`
- `json/comma-or-close-backet-expected`
- `json/comma-or-close-brace-expected`
- `json/trailing-comma`
- `json/duplicate-key`
- `json/comment-not-permitted`
- `json/schema-resolve-error`
- `json/unknown` (error that does not match previous ones)
## FAQs
#### How does eslint-plugin-json work?
Starting from version 1.3, this plugin relies on what [VSCode](https://github.com/Microsoft/vscode-json-languageservice)
uses for its implementation of JSON validation.
Originaly this plugin used to use JSHint, however due to heavy dependencies, it was replaced.
#### Why doesn't this plugin use `eslint` itself or just `JSON.parse`?
`eslint`'s parser is a JavaScript parser. JSON is a stricter subset and things
that are valid JavaScript are not valid JSON. This is why something more specific
is more appropriate.
While `JSON.parse` seems ideal, it is not designed to continue after the first error.
So if you have a missing trailing comma in the start of the file, the rest of the file
will go unlinted. A smarter parser that can self-correct after seeing errors is needed
which the VSCode implementation provides by leveraging the
[jsonc-parser](https://www.npmjs.com/package/jsonc-parser) module.
#### Will this plugin provide more configuration?
It is now possible as you can see in the [Configuration section](#custom-configuration).
Additionally, support for autofixing common errors could be added in the feature.
#### Is `eslint` really the best tool to lint my JSON?
Not really. `eslint` plugin interface wasn't designed to lint a completely different language but
its interface is flexible enough to allow it. So this plugin is certainly unusual.
Ideally, your editor would natively supports linting JSON. If it doesn't though, then might as well
use this plugin. Hacky linting is better than no linting :).
================================================
FILE: examples/.eslintrc
================================================
{
"plugins": ["json"],
"rules": {
"json/*": ["warn"],
"json/duplicate-key": "error",
"json/trailing-comma": "error"
},
"overrides": [
{
"files": ["samples/json-with-comments.json"],
"rules": {
"json/*": ["warn", {"allowComments": true}]
}
}
]
}
================================================
FILE: examples/package.json
================================================
{
"name": "eslint-plugin-json-example",
"version": "1.0.0",
"description": "Some example of usage of plugin",
"main": "index.js",
"scripts": {
"lint": "eslint",
"test": "node integration-test.js"
},
"keywords": [],
"license": "ISC",
"devDependencies": {
"eslint": "^6.3.0",
"eslint-plugin-json": ".."
}
}
================================================
FILE: examples/samples/duplicate-keys.json
================================================
{
"iam": "here",
"iam": "and here"
}
================================================
FILE: examples/samples/good-json.json
================================================
{
"hello": "world"
}
================================================
FILE: examples/samples/json-with-comments.json
================================================
{
"hello": "world" // with a comment
}
================================================
FILE: examples/samples/whole-mess.json
================================================
{
"iam": "here",
"iam": "and here", // COMMENT
}
================================================
FILE: examples/samples/wrong-syntax.json
================================================
{
"oops":
}
================================================
FILE: package.json
================================================
{
"name": "eslint-plugin-json",
"version": "4.0.1",
"description": "eslint plugin for JSON files",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"json",
"eslint-plugin-json"
],
"author": "Azeem Bande-Ali <a.bandeali@gmail.com>",
"contributors": [
"Adriean Khisbe <adriean.khisbe@live.fr> (https://github.com/AdrieanKhisbe/)"
],
"main": "src/index.js",
"scripts": {
"integration": "test/integration-across-eslint-majors.sh",
"test": "nyc mocha test/unit.test.js",
"lint": "eslint src test",
"eslint": "eslint"
},
"repository": {
"type": "git",
"url": "git+https://github.com/azeemba/eslint-plugin-json.git"
},
"bugs": {
"url": "https://github.com/azeemba/eslint-plugin-json/issues"
},
"dependencies": {
"lodash": "^4.17.21",
"vscode-json-languageservice": "^4.1.6"
},
"devDependencies": {
"chai": "^4.3.4",
"codecov": "^3.8.3",
"eslint": "^8.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-self": "file:vendor/eslint-plugin-self",
"mocha": "^10.4.0",
"nyc": "^15.1.0",
"prettier": "^2.3.2"
},
"engines": {
"node": ">=18.0"
},
"url": "https://github.com/azeemba/eslint-plugin-json",
"license": "MIT"
}
================================================
FILE: src/index.js
================================================
const _ = require('lodash/fp');
const jsonService = require('vscode-json-languageservice');
const jsonServiceHandle = jsonService.getLanguageService({});
const ErrorCodes = {
Undefined: 0,
EnumValueMismatch: 1,
UnexpectedEndOfComment: 0x101,
UnexpectedEndOfString: 0x102,
UnexpectedEndOfNumber: 0x103,
InvalidUnicode: 0x104,
InvalidEscapeCharacter: 0x105,
InvalidCharacter: 0x106,
PropertyExpected: 0x201,
CommaExpected: 0x202,
ColonExpected: 0x203,
ValueExpected: 0x204,
CommaOrCloseBacketExpected: 0x205,
CommaOrCloseBraceExpected: 0x206,
TrailingComma: 0x207,
DuplicateKey: 0x208,
CommentNotPermitted: 0x209,
SchemaResolveError: 0x300,
};
const AllErrorCodes = _.values(ErrorCodes);
const AllowComments = 'allowComments';
const fileLintResults = {};
const fileComments = {};
const fileDocuments = {};
const getSignature = (problem) =>
`${problem.range.start.line} ${problem.range.start.character} ${problem.message}`;
function getDiagnostics(jsonDocument) {
return _.pipe(
_.map((problem) => [getSignature(problem), problem]),
_.reverse, // reverse ensure fromPairs keep first signature occurence of problem
_.fromPairs
)(jsonDocument.syntaxErrors);
}
const reportError = (filter) => (errorName, context) => {
_.filter(filter, fileLintResults[context.getFilename()]).forEach((error) => {
context.report({
ruleId: `json/${errorName}`,
message: error.message,
loc: {
start: {line: error.range.start.line + 1, column: error.range.start.character},
end: {line: error.range.end.line + 1, column: error.range.end.character},
},
// later: see how to add fix
});
});
};
const reportComment = (errorName, context) => {
const ruleOption = _.head(context.options);
if (ruleOption === AllowComments || _.get(AllowComments, ruleOption)) return;
_.forEach((comment) => {
context.report({
ruleId: errorName,
message: 'Comment not allowed',
loc: {
start: {line: comment.start.line + 1, column: comment.start.character},
end: {line: comment.end.line + 1, column: comment.end.character},
},
});
}, fileComments[context.getFilename()]);
};
const ruleSchema = [
{
anyOf: [
{
enum: ['allowComments'],
},
{
type: 'object',
properties: {
allowComments: {type: 'boolean'},
},
additionalProperties: false,
},
],
},
];
const makeRule = (errorName, reporters) => ({
meta: {schema: ruleSchema},
create(context) {
return {
Program() {
_.flatten([reporters]).map((reporter) => reporter(errorName, context));
},
};
},
});
const rules = _.pipe(
_.mapKeys(_.kebabCase),
_.toPairs,
_.map(([errorName, errorCode]) => [
errorName,
makeRule(
errorName,
reportError((err) => err.code === errorCode)
),
]),
_.fromPairs,
_.assign({
'*': makeRule('*', [reportError(_.constant(true)), reportComment]),
json: makeRule('json', [reportError(_.constant(true)), reportComment]),
unknown: makeRule('unknown', reportError(_.negate(AllErrorCodes.includes))),
'comment-not-permitted': makeRule('comment-not-permitted', reportComment),
})
)(ErrorCodes);
const errorSignature = (err) =>
['message', 'line', 'column', 'endLine', 'endColumn'].map((field) => err[field]).join('::');
const getErrorCode = _.pipe(_.get('ruleId'), _.split('/'), _.last);
const meta = {
name: 'eslint-plugin-json',
version: '3.1.0',
};
const jsonProcessor = {
preprocess: function (text, fileName) {
const textDocument = jsonService.TextDocument.create(fileName, 'json', 1, text);
fileDocuments[fileName] = textDocument;
const parsed = jsonServiceHandle.parseJSONDocument(textDocument);
fileLintResults[fileName] = getDiagnostics(parsed);
fileComments[fileName] = parsed.comments;
return ['']; // sorry nothing ;)
},
postprocess: function (messages, fileName) {
const textDocument = fileDocuments[fileName];
delete fileLintResults[fileName];
delete fileComments[fileName];
return _.pipe(
_.first,
_.groupBy(errorSignature),
_.mapValues((errors) => {
if (errors.length === 1) return _.first(errors);
// Otherwise there is two errors: the generic and specific one
// json/* or json/json and json/some-code
const firstErrorCode = getErrorCode(errors[0]);
const isFirstGeneric = ['*', 'json'].includes(firstErrorCode);
const genericError = errors[isFirstGeneric ? 0 : 1];
const specificError = errors[isFirstGeneric ? 1 : 0];
return genericError.severity > specificError.severity
? genericError
: specificError;
}),
_.mapValues((error) => {
const source = textDocument.getText({
start: {line: error.line - 1, character: error.column},
end: {line: error.endLine - 1, character: error.endColumn},
});
return _.assign(error, {
source,
column: error.column + 1,
endColumn: error.endColumn + 1,
});
}),
_.values
)(messages);
},
};
const processors = {
// Supports old config.
'.json': jsonProcessor,
// Supports new config.
json: jsonProcessor,
};
const configs = {
'recommended-legacy': {
plugins: ['json'],
rules: {
'json/*': 'error',
},
},
'recommended-with-comments-legacy': {
plugins: ['json'],
rules: {
'json/*': ['error', {allowComments: true}],
},
},
};
const json = {meta, rules, configs, processors};
json.configs['recommended'] = {
files: ['**/*.json'],
plugins: {
json,
},
rules: {
'json/*': 'error',
},
processor: 'json/json',
};
json.configs['recommended-with-comments'] = {
files: ['**/*.json'],
plugins: {
json,
},
rules: {
'json/*': ['error', {allowComments: true}],
},
processor: 'json/json',
};
module.exports = json;
================================================
FILE: test/.eslintrc.with-recommended-comments-config.mjs
================================================
import json from '../src/index.js';
export default [json.configs['recommended-with-comments']];
================================================
FILE: test/.eslintrc.with-recommended-comments-legacy-config.json
================================================
{
"extends": ["plugin:self/recommended-with-comments-legacy"]
}
================================================
FILE: test/.eslintrc.with-recommended-config.mjs
================================================
import json from '../src/index.js';
export default [json.configs['recommended']];
================================================
FILE: test/.eslintrc.with-recommended-legacy-config.json
================================================
{
"extends": ["plugin:self/recommended-legacy"]
}
================================================
FILE: test/custom.eslintrc-legacy.json
================================================
{
"plugins": ["self"],
"rules": {
"self/*": "warn",
"self/duplicate-key": "error",
"self/trailing-comma": "error"
},
"overrides": [
{
"files": ["samples/json-with-comments.json"],
"rules": {
"self/*": ["warn", {"allowComments": true}]
}
},
{
"files": ["samples/wrong-syntax.json"],
"rules": {
"self/*": "error"
}
}
]
}
================================================
FILE: test/custom.eslintrc.config.mjs
================================================
import json from '../src/index.js';
export default [
{
files: ['**/*.json'],
plugins: {json},
processor: 'json/json',
rules: {
'json/*': 'warn',
'json/duplicate-key': 'error',
'json/trailing-comma': 'error',
},
},
{
files: ['samples/json-with-comments.json'],
plugins: {json},
rules: {
'json/*': ['warn', {allowComments: true}],
},
},
{
files: ['samples/wrong-syntax.json'],
plugins: {json},
rules: {
'json/*': 'error',
},
},
];
================================================
FILE: test/integration-across-eslint-majors.sh
================================================
#!/usr/bin/env bash
set -e
cmd="$1"
shift
case "$cmd" in
test|install|ci);;
*)
echo "Unknown integration subcommand $cmd"
exit 2
;;
esac
if [[ -z "$@" ]]; then
echo "No eslint major versions were provided"
exit 2
fi
echo "Will perform $cmd for following eslint majors lines: $@"
for version in $@; do
(cd test/packages/eslint-v$version && npm $cmd)
done
================================================
FILE: test/integration-legacy.test.js
================================================
const {execFileSync} = require('child_process');
const {expect} = require('chai');
const _ = require('lodash/fp');
const SCOPE = 'self'; // (for test purpose only, relying the the eslint-plugin-self for tests)
const scoped = (rule) => `${SCOPE}/${rule}`;
function getLintResults(filename, eslintConfig) {
try {
const results = execFileSync(
'eslint',
[
'--config',
eslintConfig || 'custom.eslintrc-legacy.json',
'--format',
'json',
filename,
],
{
encoding: 'utf8',
stdio: 'pipe',
cwd: __dirname,
}
);
return JSON.parse(results)[0];
} catch (err) {
if (err.status !== 1 && err.status !== 0)
throw new Error(`The lint command itself failed: ${err.status}, ${err.message}`);
return JSON.parse(err.stdout)[0];
}
}
function groupInfringementsByRules(fileResults) {
const errors = {};
const warnings = {};
for (const infringement of fileResults.messages) {
const counter = infringement.severity === 1 ? warnings : errors;
counter[infringement.ruleId] = (counter[infringement.ruleId] || 0) + 1;
}
return {errors, warnings};
}
function validateInfringementExpectation(expected, actualSituation) {
if (_.isEmpty(expected)) return;
for (const someExpected of expected || []) {
const [rule, expectedCount] = someExpected.split(':');
if (expectedCount)
expect(actualSituation[scoped(rule)]).to.equal(
Number(expectedCount),
`unexpected count of rule ${rule}`
);
else expect(actualSituation).to.have.property(scoped(rule));
}
const allExpectedErrors = expected.map(_.pipe(_.split(':'), _.head, scoped));
expect(_.xor(_.keys(actualSituation), allExpectedErrors)).to.have.length(
0,
'Extra errors found'
);
}
function validateFile(filename, expectations = {}) {
const results = getLintResults(`samples/${filename}.json`, expectations.eslintrc);
const resultIndex = groupInfringementsByRules(results);
validateInfringementExpectation(expectations.errors, resultIndex.errors, 'errors');
validateInfringementExpectation(expectations.warnings, resultIndex.warnings, 'warnings');
if (expectations.errorCount !== undefined)
expect(results.errorCount).to.equal(expectations.errorCount, 'invalid count of errors');
if (expectations.warningCount !== undefined)
expect(results.warningCount).to.equal(
expectations.warningCount,
'invalid count of warnings'
);
}
describe('Integrations tests', function () {
it('validate correct json', function () {
validateFile('good-json', {errorCount: 0, warningCount: 0});
});
it('detect duplicate keys', function () {
validateFile('duplicate-keys', {
errors: ['duplicate-key:2'],
}); // FIXME: give error count!
});
it('handle comments in json', function () {
validateFile('json-with-comments', {errorCount: 0, warningCount: 0});
});
it('detect wrong syntax', function () {
validateFile('wrong-syntax', {errorCount: 1, warningCount: 0});
});
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
errors: ['duplicate-key:2', 'trailing-comma'],
warnings: ['*'],
});
});
});
describe('Integrations tests with config', function () {
describe('recommended', function () {
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
eslintrc: '.eslintrc.with-recommended-legacy-config.json',
errors: ['*:4'],
});
});
it('handle comments in json', function () {
validateFile('json-with-comments', {
eslintrc: '.eslintrc.with-recommended-legacy-config.json',
errorCount: 1, // comment-not-permitted under the '*' glob
});
});
});
describe('recommended-with-comments', function () {
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
eslintrc: '.eslintrc.with-recommended-comments-legacy-config.json',
errors: ['*:3'],
});
});
it('handle comments in json', function () {
validateFile('json-with-comments', {
eslintrc: '.eslintrc.with-recommended-comments-legacy-config.json',
errorCount: 0,
warningCount: 0,
});
});
});
});
================================================
FILE: test/integration.test.js
================================================
const {execFileSync} = require('child_process');
const {expect} = require('chai');
const _ = require('lodash/fp');
const SCOPE = 'json'; // (for test purpose only)
const scoped = (rule) => `${SCOPE}/${rule}`;
function getLintResults(filename, eslintConfig) {
try {
const results = execFileSync(
'eslint',
[
'--config',
eslintConfig || 'custom.eslintrc.config.mjs',
'--format',
'json',
filename,
],
{
encoding: 'utf8',
stdio: 'pipe',
cwd: __dirname,
}
);
return JSON.parse(results)[0];
} catch (err) {
if (err.status !== 1 && err.status !== 0)
throw new Error(`The lint command itself failed: ${err.status}, ${err.message}`);
return JSON.parse(err.stdout)[0];
}
}
function groupInfringementsByRules(fileResults) {
const errors = {};
const warnings = {};
for (const infringement of fileResults.messages) {
const counter = infringement.severity === 1 ? warnings : errors;
counter[infringement.ruleId] = (counter[infringement.ruleId] || 0) + 1;
}
return {errors, warnings};
}
function validateInfringementExpectation(expected, actualSituation) {
if (_.isEmpty(expected)) return;
for (const someExpected of expected || []) {
const [rule, expectedCount] = someExpected.split(':');
if (expectedCount)
expect(actualSituation[scoped(rule)]).to.equal(
Number(expectedCount),
`unexpected count of rule ${rule}`
);
else expect(actualSituation).to.have.property(scoped(rule));
}
const allExpectedErrors = expected.map(_.pipe(_.split(':'), _.head, scoped));
expect(_.xor(_.keys(actualSituation), allExpectedErrors)).to.have.length(
0,
'Extra errors found'
);
}
function validateFile(filename, expectations = {}) {
const results = getLintResults(`samples/${filename}.json`, expectations.eslintrc);
const resultIndex = groupInfringementsByRules(results);
validateInfringementExpectation(expectations.errors, resultIndex.errors, 'errors');
validateInfringementExpectation(expectations.warnings, resultIndex.warnings, 'warnings');
if (expectations.errorCount !== undefined)
expect(results.errorCount).to.equal(expectations.errorCount, 'invalid count of errors');
if (expectations.warningCount !== undefined)
expect(results.warningCount).to.equal(
expectations.warningCount,
'invalid count of warnings'
);
}
describe('Integrations tests', function () {
it('validate correct json', function () {
validateFile('good-json', {errorCount: 0, warningCount: 0});
});
it('detect duplicate keys', function () {
validateFile('duplicate-keys', {
errors: ['duplicate-key:2'],
}); // FIXME: give error count!
});
it('handle comments in json', function () {
validateFile('json-with-comments', {errorCount: 0, warningCount: 0});
});
it('detect wrong syntax', function () {
validateFile('wrong-syntax', {errorCount: 1, warningCount: 0});
});
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
errors: ['duplicate-key:2', 'trailing-comma'],
warnings: ['*'],
});
});
});
describe('Integrations tests with config', function () {
describe('recommended', function () {
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
eslintrc: '.eslintrc.with-recommended-config.mjs',
errors: ['*:4'],
});
});
it('handle comments in json', function () {
validateFile('json-with-comments', {
eslintrc: '.eslintrc.with-recommended-config.mjs',
errorCount: 1, // comment-not-permitted under the '*' glob
});
});
});
describe('recommended-with-comments', function () {
it('detect many infringements in messy json', function () {
validateFile('whole-mess', {
eslintrc: '.eslintrc.with-recommended-comments-config.mjs',
errors: ['*:3'],
});
});
it('handle comments in json', function () {
validateFile('json-with-comments', {
eslintrc: '.eslintrc.with-recommended-comments-config.mjs',
errorCount: 0,
warningCount: 0,
});
});
});
});
================================================
FILE: test/packages/eslint-v7-legacy/package.json
================================================
{
"name": "eslint-plugin-json-v7",
"version": "0.1.0",
"description": "Integration for eslint-plugin-json against ESLint v7",
"private": true,
"main": "index.js",
"scripts": {
"pretest": "eslint --version",
"test": "../../../node_modules/.bin/mocha test/integration-legacy.test.js"
},
"keywords": [
"eslint",
"eslint-plugin",
"eslint-plugin-json",
"integration-tests"
],
"license": "MIT",
"devDependencies": {
"eslint": "^7.32.0",
"mocha": "^10.4.0"
},
"dependencies": {}
}
================================================
FILE: test/packages/eslint-v8/package.json
================================================
{
"name": "eslint-plugin-json-v8",
"version": "0.1.0",
"description": "Integration for eslint-plugin-json against ESLint v8",
"private": true,
"main": "index.js",
"scripts": {
"pretest": "eslint --version",
"test": "ESLINT_USE_FLAT_CONFIG=true ../../../node_modules/.bin/mocha test/integration.test.js"
},
"keywords": [
"eslint",
"eslint-plugin",
"eslint-plugin-json",
"integration-tests"
],
"license": "MIT",
"devDependencies": {
"eslint": "^8.57.0",
"mocha": "^10.4.0"
},
"dependencies": {}
}
================================================
FILE: test/packages/eslint-v8-legacy/package.json
================================================
{
"name": "eslint-plugin-json-v8",
"version": "0.1.0",
"description": "Integration for eslint-plugin-json against ESLint v8",
"private": true,
"main": "index.js",
"scripts": {
"pretest": "eslint --version",
"test": "../../../node_modules/.bin/mocha test/integration-legacy.test.js"
},
"keywords": [
"eslint",
"eslint-plugin",
"eslint-plugin-json",
"integration-tests"
],
"license": "MIT",
"devDependencies": {
"eslint": "^8.0.0",
"mocha": "^9.0.3"
},
"dependencies": {}
}
================================================
FILE: test/packages/eslint-v9/package.json
================================================
{
"name": "eslint-plugin-json-v9",
"version": "0.1.0",
"description": "Integration for eslint-plugin-json against ESLint v9",
"private": true,
"main": "index.js",
"scripts": {
"pretest": "eslint --version",
"test": "node_modules/.bin/mocha test/integration.test.js"
},
"keywords": [
"eslint",
"eslint-plugin",
"eslint-plugin-json",
"integration-tests"
],
"license": "MIT",
"devDependencies": {
"eslint": "9.1.0",
"mocha": "^10.4.0"
},
"dependencies": {}
}
================================================
FILE: test/unit.test.js
================================================
const plugin = require('../src');
const {assert} = require('chai');
const _ = require('lodash/fp');
describe('plugin', function () {
describe('structure', function () {
it('should contain processors object', function () {
assert.property(plugin, 'processors', '.processors property is not defined');
});
it('should contain .json property', function () {
assert.property(plugin.processors, '.json', '.json property is not defined');
});
it('should contain .json.preprocess property', function () {
assert.property(
plugin.processors['.json'],
'preprocess',
'.json.preprocess is not defined'
);
});
it('should contain .json.postprocess property', function () {
assert.property(
plugin.processors['.json'],
'postprocess',
'.json.postprocess is not defined'
);
});
});
describe('preprocess', function () {
const preprocess = plugin.processors['.json'].preprocess;
it('should return the same text', function () {
const fileName = 'whatever-the-name.js';
const newText = preprocess('whatever', fileName);
assert.isArray(newText, 'preprocess should return array');
assert.strictEqual(newText[0], '');
});
});
describe('postprocess', function () {
const preprocess = plugin.processors['.json'].preprocess;
const postprocess = plugin.processors['.json'].postprocess;
const messageErrorFieldFromContextError = {
ruleId: _.get('ruleId'),
severity: _.getOr(1, 'severity'),
message: _.get('message'),
line: _.get('loc.start.line'),
column: _.get('loc.start.column'),
nodeType: _.getOr(null, 'nodeType'),
endLine: _.get('loc.end.line'),
endColumn: _.get('loc.end.column'),
};
const convertContextErrorToMessageError = (err) =>
_.mapValues((extractor) => extractor(err), messageErrorFieldFromContextError);
const fakeApplyRule = (rules) => (file) => {
const errors = [];
rules.forEach((rule) => {
const xxx = rule.create({
getFilename() {
return file;
},
report(err) {
errors.push(err);
},
});
xxx.Program();
});
return [errors.map(convertContextErrorToMessageError)];
};
const singleQuotes = {
fileName: 'singleQuotes.json',
text: "{'x': 0}",
};
const trailingCommas = {
fileName: 'trailing.json',
text: '{ "x": 0, }',
};
const multipleErrors = {
fileName: 'multipleErrors.json',
text: "{ x: 200, 'what': 0 }",
};
const trailingText = {
fileName: 'trailingtext.json',
text: '{ "my_string": "hello world" }' + ' \n' + 'bad_text',
};
const good = {
fileName: 'good.json',
text: JSON.stringify({a: [1, 2, 3], b: 'cat', c: {x: 1}}),
};
const rules = ['undefined', 'trailing-comma'];
const lintFile = fakeApplyRule(rules.map((rule) => plugin.rules[rule]));
const samples = [singleQuotes, trailingCommas, multipleErrors, trailingText, good];
samples.forEach((sample) => preprocess(sample.text, sample.fileName));
const errorsByFile = _.fromPairs(
samples.map((sample) => [sample.fileName, lintFile(sample.fileName)])
);
it('should return an error for the single quotes', function () {
const errors = postprocess(errorsByFile[singleQuotes.fileName], singleQuotes.fileName);
assert.isArray(errors, 'should return an array');
assert.lengthOf(errors, 1, 'should return one error');
const error = errors[0];
assert.strictEqual(error.ruleId, 'json/undefined', 'should have a string ID');
assert.strictEqual(error.severity, 1, 'should have a numeric severity');
assert.strictEqual(
error.message,
'Property keys must be doublequoted',
'should have a message'
);
assert.strictEqual(error.line, 1, 'should point to first line');
assert.strictEqual(error.column, 2, 'should point to second character');
});
it('should return an error for trailing commas', function () {
const errors = postprocess(
errorsByFile[trailingCommas.fileName],
trailingCommas.fileName
);
assert.isArray(errors, 'should return an array');
assert.lengthOf(errors, 1, 'should return one error');
const error = errors[0];
assert.strictEqual(error.ruleId, 'json/trailing-comma', 'should have a string ID');
assert.strictEqual(error.line, 1, 'should point to the first line');
assert.strictEqual(error.column, 9, 'should point to the 9th character');
});
it('should report unrecoverable syntax error', function () {
const errors = postprocess(errorsByFile[trailingText.fileName], trailingText.fileName);
assert.isArray(errors, 'should return an array');
assert.lengthOf(errors, 1, 'should return one error');
assert.isString(errors[0].message, 'should have a valid message');
// we don't validate the line/column numbers since they don't actually
// mean anything for this error. JSHint just bails on the file.
});
it('should return multiple errors for multiple errors', function () {
const errors = postprocess(
errorsByFile[multipleErrors.fileName],
multipleErrors.fileName
);
assert.isArray(errors, 'should return an array');
assert.lengthOf(errors, 2, 'should return one error');
});
it('should return no errors for good json', function () {
const errors = postprocess(errorsByFile[good.fileName], good.fileName);
assert.isArray(errors, 'should return an array');
assert.lengthOf(errors, 0, "good json shouldn't have any errors");
});
});
});
================================================
FILE: vendor/eslint-plugin-self/CHANGELOG.md
================================================
# Changelog
## v1.2.1 (2020-05-27)
* Support overrides having no rules :see_no_evil: ([#5](https://github.com/not-an-aardvark/eslint-plugin-self/issues/5)) ([e266543](https://github.com/not-an-aardvark/eslint-plugin-self/commit/e266543e50d062251755dd488abae31be7644bb1))
## v1.2.0 (2019-03-04)
* Support redefining plugins, overrides and rules with a "/" in them ([#2](https://github.com/not-an-aardvark/eslint-plugin-self/issues/2)) ([428664e](https://github.com/not-an-aardvark/eslint-plugin-self/commit/428664e1cf8f3726e0bb3b10bb3e137d271749c2))
## v1.1.0 (2018-07-06)
* Chore: add release script ([983a7d0](https://github.com/not-an-aardvark/eslint-plugin-self/commit/983a7d05c48bccc125f8d89fae1109a0c5a1d670))
* Update: Add support for @scoped packages ([#1](https://github.com/not-an-aardvark/eslint-plugin-self/issues/1)) ([c57a01b](https://github.com/not-an-aardvark/eslint-plugin-self/commit/c57a01bbf922b82d09a0cceba6b5e845fab7d23a))
## v1.0.1 (2017-07-02)
* Fix: transform references to own rules in configs to use `self` prefix ([2dce85e](https://github.com/not-an-aardvark/eslint-plugin-self/commit/2dce85e445a7604f5fd963d1366509fa7a66d420))
================================================
FILE: vendor/eslint-plugin-self/LICENSE.md
================================================
The MIT License (MIT)
=====================
Copyright © 2017 Teddy Katz
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.
================================================
FILE: vendor/eslint-plugin-self/README.md
================================================
# eslint-plugin-self
When writing an ESLint plugin, it's often useful to use the plugin's rules to lint the plugin's own codebase. You can use `eslint-plugin-self` to do that.
## Usage
```
npm install eslint-plugin-self --save-dev
```
Note: `eslint-plugin-self` must be installed locally (it will not work if installed globally), and the project that installs it must be a functioning ESLint plugin.
Add the following to your config file:
```json
{
"plugins": [
"self"
]
}
```
Then you can use your plugin's rules, with the `self/` prefix:
```json
{
"rules": {
"self/my-custom-rule": "error"
}
}
```
You can also use your plugin's configs, or anything else exported by your plugin:
```json
{
"extends": [
"plugin:self/some-config"
]
}
```
================================================
FILE: vendor/eslint-plugin-self/index.js
================================================
'use strict';
const plugin = require('../..');
const selfPlugin = Object.assign({}, plugin);
const pkgName = require('../../package.json').name;
let pluginName;
if (pkgName[0] === "@") {
const matches = pkgName.match(/^(@[^/]+)\/eslint-plugin(?:-(.*))?$/);
pluginName = matches.slice(1, 3).filter(Boolean).join('/');
} else {
pluginName = pkgName.replace(/^eslint-plugin-/, '');
}
function createRuleset(rules) {
return Object.keys(rules).reduce((newRules, oldRuleName) => {
const newRuleName = oldRuleName.startsWith(`${pluginName}/`)
? `self${oldRuleName.slice(oldRuleName.indexOf('/'))}`
: oldRuleName;
newRules[newRuleName] = rules[oldRuleName];
return newRules;
}, {});
}
if (plugin.configs) {
selfPlugin.configs = Object.assign({}, plugin.configs);
Object.keys(plugin.configs).forEach(configName => {
const config = plugin.configs[configName];
selfPlugin.configs[configName] = Object.assign({}, config);
if (config.extends) {
selfPlugin.configs[configName].extends = [].concat(config.extends)
.map(extendsName => extendsName.replace(`plugin:${pluginName}/`, 'plugin:self/'));
}
// The Array.isArray avoids attempting to change the plugins property for
// eslint v9 based configurations.
if (config.plugins && Array.isArray(config.plugins)) {
selfPlugin.configs[configName].plugins = [].concat(config.plugins)
.map(enabledPluginName => enabledPluginName.replace(pluginName, 'self'));
}
if (config.rules) {
selfPlugin.configs[configName].rules = createRuleset(config.rules);
}
if (config.overrides) {
selfPlugin.configs[configName].overrides = [].concat(config.overrides)
.map((override) => {
if (!override.rules) return override;
return Object.assign(
{},
override,
{rules: createRuleset(override.rules)}
);
})
}
});
}
module.exports = selfPlugin;
================================================
FILE: vendor/eslint-plugin-self/package.json
================================================
{
"name": "eslint-plugin-self",
"version": "1.2.1",
"description": "Allows ESLint plugins to be run on themselves",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"generate-release": "node-release-script"
},
"repository": {
"type": "git",
"url": "git+https://github.com/not-an-aardvark/eslint-plugin-self.git"
},
"keywords": [
"eslint-plugin",
"eslintplugin"
],
"author": "Teddy Katz",
"license": "MIT",
"bugs": {
"url": "https://github.com/not-an-aardvark/eslint-plugin-self/issues"
},
"homepage": "https://github.com/not-an-aardvark/eslint-plugin-self#readme",
"devDependencies": {
"@not-an-aardvark/node-release-script": "^0.1.0"
}
}
gitextract_qzrczb7v/
├── .eslintignore
├── .eslintrc
├── .github/
│ └── workflows/
│ └── node.js.yml
├── .gitignore
├── .npmignore
├── .nycrc
├── LICENSE.txt
├── README.md
├── examples/
│ ├── .eslintrc
│ ├── package.json
│ └── samples/
│ ├── duplicate-keys.json
│ ├── good-json.json
│ ├── json-with-comments.json
│ ├── whole-mess.json
│ └── wrong-syntax.json
├── package.json
├── src/
│ └── index.js
├── test/
│ ├── .eslintrc.with-recommended-comments-config.mjs
│ ├── .eslintrc.with-recommended-comments-legacy-config.json
│ ├── .eslintrc.with-recommended-config.mjs
│ ├── .eslintrc.with-recommended-legacy-config.json
│ ├── custom.eslintrc-legacy.json
│ ├── custom.eslintrc.config.mjs
│ ├── integration-across-eslint-majors.sh
│ ├── integration-legacy.test.js
│ ├── integration.test.js
│ ├── packages/
│ │ ├── eslint-v7-legacy/
│ │ │ └── package.json
│ │ ├── eslint-v8/
│ │ │ └── package.json
│ │ ├── eslint-v8-legacy/
│ │ │ └── package.json
│ │ └── eslint-v9/
│ │ └── package.json
│ └── unit.test.js
└── vendor/
└── eslint-plugin-self/
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── index.js
└── package.json
SYMBOL INDEX (15 symbols across 5 files)
FILE: src/index.js
function getDiagnostics (line 37) | function getDiagnostics(jsonDocument) {
method create (line 92) | create(context) {
FILE: test/integration-legacy.test.js
constant SCOPE (line 5) | const SCOPE = 'self';
function getLintResults (line 8) | function getLintResults(filename, eslintConfig) {
function groupInfringementsByRules (line 33) | function groupInfringementsByRules(fileResults) {
function validateInfringementExpectation (line 42) | function validateInfringementExpectation(expected, actualSituation) {
function validateFile (line 60) | function validateFile(filename, expectations = {}) {
FILE: test/integration.test.js
constant SCOPE (line 5) | const SCOPE = 'json';
function getLintResults (line 8) | function getLintResults(filename, eslintConfig) {
function groupInfringementsByRules (line 33) | function groupInfringementsByRules(fileResults) {
function validateInfringementExpectation (line 42) | function validateInfringementExpectation(expected, actualSituation) {
function validateFile (line 60) | function validateFile(filename, expectations = {}) {
FILE: test/unit.test.js
method getFilename (line 58) | getFilename() {
method report (line 61) | report(err) {
FILE: vendor/eslint-plugin-self/index.js
function createRuleset (line 15) | function createRuleset(rules) {
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (48K chars).
[
{
"path": ".eslintignore",
"chars": 14,
"preview": "test/packages\n"
},
{
"path": ".eslintrc",
"chars": 499,
"preview": "{\n \"env\": {\n \"node\": true,\n \"mocha\": true,\n \"es6\": true\n },\n \"parserOptions\": {\n \"ecmaVersion\": 2017\n },"
},
{
"path": ".github/workflows/node.js.yml",
"chars": 1136,
"preview": "# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tes"
},
{
"path": ".gitignore",
"chars": 88,
"preview": "node_modules\nprivate\ntmp\ncoverage\n.nyc_output\nexample/package-lock.json\n.vscode/\n.idea/\n"
},
{
"path": ".npmignore",
"chars": 100,
"preview": "test\nexamples\nprivate\ntmp\ncoverage\n.npmignore\n.eslintrc\n.github\n.vscode\n.nycrc\n.eslintignore\nvendor\n"
},
{
"path": ".nycrc",
"chars": 88,
"preview": "{\n \"all\": true,\n \"include\": [\"src\"],\n \"reporter\": [\"text\", \"text-summary\", \"lcov\"]\n}\n"
},
{
"path": "LICENSE.txt",
"chars": 1088,
"preview": "The MIT License (MIT)\nCopyright (c) 2015-2021 Azeem Bande-Ali\n\n\nPermission is hereby granted, free of charge, to any per"
},
{
"path": "README.md",
"chars": 5842,
"preview": "# eslint-plugin-json\n\n[](https://www.npmjs.com/package/eslint"
},
{
"path": "examples/.eslintrc",
"chars": 347,
"preview": "{\n \"plugins\": [\"json\"],\n \"rules\": {\n \"json/*\": [\"warn\"],\n \"json/duplicate-key\": \"error\",\n \"json/trailin"
},
{
"path": "examples/package.json",
"chars": 341,
"preview": "{\n \"name\": \"eslint-plugin-json-example\",\n \"version\": \"1.0.0\",\n \"description\": \"Some example of usage of plugin\",\n \"m"
},
{
"path": "examples/samples/duplicate-keys.json",
"chars": 45,
"preview": "{\n \"iam\": \"here\",\n \"iam\": \"and here\"\n}\n"
},
{
"path": "examples/samples/good-json.json",
"chars": 25,
"preview": "{\n \"hello\": \"world\"\n}\n"
},
{
"path": "examples/samples/json-with-comments.json",
"chars": 43,
"preview": "{\n \"hello\": \"world\" // with a comment\n}\n"
},
{
"path": "examples/samples/whole-mess.json",
"chars": 57,
"preview": "{\n \"iam\": \"here\",\n \"iam\": \"and here\", // COMMENT\n}\n"
},
{
"path": "examples/samples/wrong-syntax.json",
"chars": 16,
"preview": "{\n \"oops\":\n}\n"
},
{
"path": "package.json",
"chars": 1302,
"preview": "{\n \"name\": \"eslint-plugin-json\",\n \"version\": \"4.0.1\",\n \"description\": \"eslint plugin for JSON files\",\n \"keywords\": ["
},
{
"path": "src/index.js",
"chars": 6673,
"preview": "const _ = require('lodash/fp');\nconst jsonService = require('vscode-json-languageservice');\n\nconst jsonServiceHandle = j"
},
{
"path": "test/.eslintrc.with-recommended-comments-config.mjs",
"chars": 97,
"preview": "import json from '../src/index.js';\n\nexport default [json.configs['recommended-with-comments']];\n"
},
{
"path": "test/.eslintrc.with-recommended-comments-legacy-config.json",
"chars": 66,
"preview": "{\n \"extends\": [\"plugin:self/recommended-with-comments-legacy\"]\n}\n"
},
{
"path": "test/.eslintrc.with-recommended-config.mjs",
"chars": 83,
"preview": "import json from '../src/index.js';\n\nexport default [json.configs['recommended']];\n"
},
{
"path": "test/.eslintrc.with-recommended-legacy-config.json",
"chars": 54,
"preview": "{\n \"extends\": [\"plugin:self/recommended-legacy\"]\n}\n"
},
{
"path": "test/custom.eslintrc-legacy.json",
"chars": 489,
"preview": "{\n \"plugins\": [\"self\"],\n \"rules\": {\n \"self/*\": \"warn\",\n \"self/duplicate-key\": \"error\",\n \"self/trailing-"
},
{
"path": "test/custom.eslintrc.config.mjs",
"chars": 618,
"preview": "import json from '../src/index.js';\n\nexport default [\n {\n files: ['**/*.json'],\n plugins: {json},\n "
},
{
"path": "test/integration-across-eslint-majors.sh",
"chars": 380,
"preview": "#!/usr/bin/env bash\nset -e\ncmd=\"$1\"\nshift\n\ncase \"$cmd\" in\n test|install|ci);;\n *)\n echo \"Unknown integration subcom"
},
{
"path": "test/integration-legacy.test.js",
"chars": 4770,
"preview": "const {execFileSync} = require('child_process');\nconst {expect} = require('chai');\nconst _ = require('lodash/fp');\n\ncons"
},
{
"path": "test/integration.test.js",
"chars": 4691,
"preview": "const {execFileSync} = require('child_process');\nconst {expect} = require('chai');\nconst _ = require('lodash/fp');\n\ncons"
},
{
"path": "test/packages/eslint-v7-legacy/package.json",
"chars": 532,
"preview": "{\n \"name\": \"eslint-plugin-json-v7\",\n \"version\": \"0.1.0\",\n \"description\": \"Integration for eslint-plugin-json against "
},
{
"path": "test/packages/eslint-v8/package.json",
"chars": 553,
"preview": "{\n \"name\": \"eslint-plugin-json-v8\",\n \"version\": \"0.1.0\",\n \"description\": \"Integration for eslint-plugin-json against "
},
{
"path": "test/packages/eslint-v8-legacy/package.json",
"chars": 530,
"preview": "{\n \"name\": \"eslint-plugin-json-v8\",\n \"version\": \"0.1.0\",\n \"description\": \"Integration for eslint-plugin-json against "
},
{
"path": "test/packages/eslint-v9/package.json",
"chars": 514,
"preview": "{\n \"name\": \"eslint-plugin-json-v9\",\n \"version\": \"0.1.0\",\n \"description\": \"Integration for eslint-plugin-json against "
},
{
"path": "test/unit.test.js",
"chars": 6542,
"preview": "const plugin = require('../src');\nconst {assert} = require('chai');\nconst _ = require('lodash/fp');\n\ndescribe('plugin', "
},
{
"path": "vendor/eslint-plugin-self/CHANGELOG.md",
"chars": 1165,
"preview": "# Changelog\n\n## v1.2.1 (2020-05-27)\n\n* Support overrides having no rules :see_no_evil: ([#5](https://github.com/not-an-a"
},
{
"path": "vendor/eslint-plugin-self/LICENSE.md",
"chars": 1097,
"preview": "The MIT License (MIT)\n=====================\n\nCopyright © 2017 Teddy Katz\n\nPermission is hereby granted, free of charge, "
},
{
"path": "vendor/eslint-plugin-self/README.md",
"chars": 773,
"preview": "# eslint-plugin-self\n\nWhen writing an ESLint plugin, it's often useful to use the plugin's rules to lint the plugin's ow"
},
{
"path": "vendor/eslint-plugin-self/index.js",
"chars": 1970,
"preview": "'use strict';\n\nconst plugin = require('../..');\nconst selfPlugin = Object.assign({}, plugin);\n\nconst pkgName = require('"
},
{
"path": "vendor/eslint-plugin-self/package.json",
"chars": 744,
"preview": "{\n \"name\": \"eslint-plugin-self\",\n \"version\": \"1.2.1\",\n \"description\": \"Allows ESLint plugins to be run on themselves\""
}
]
About this extraction
This page contains the full source code of the azeemba/eslint-plugin-json GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (42.4 KB), approximately 11.5k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.