Socket
Socket
Sign inDemoInstall

eslint-plugin-functional

Package Overview
Dependencies
4
Maintainers
2
Versions
105
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 3.0.0

43

CHANGELOG.md

@@ -8,4 +8,19 @@ # Changelog

## [Unreleased](https://github.com/jonaskello/eslint-plugin-functional/compare/v2.0.0...HEAD)
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
## [v3.0.0](https://github.com/jonaskello/eslint-plugin-functional/compare/v2.0.0...v3.0.0) - 2020-01-11
### Merged
- set up auto-changelog so we don't have to do it manually [`#90`](https://github.com/jonaskello/eslint-plugin-functional/pull/90)
- Dependency Update. [`#89`](https://github.com/jonaskello/eslint-plugin-functional/pull/89)
- Examples of correct/incorrect code for each rule [`#60`](https://github.com/jonaskello/eslint-plugin-functional/pull/60)
- docs: rename 'allow-pattern.md' to 'ignore-pattern.md' [`#88`](https://github.com/jonaskello/eslint-plugin-functional/pull/88)
- Prettier readme [`#85`](https://github.com/jonaskello/eslint-plugin-functional/pull/85)
- Additional tests [`#86`](https://github.com/jonaskello/eslint-plugin-functional/pull/86)
### Commits
- **Breaking change:** build(dep): update all dependencies [`cae4c49`](https://github.com/jonaskello/eslint-plugin-functional/commit/cae4c49bdf3cd0845e399819046941fa4d2ee13f)
## [v2.0.0](https://github.com/jonaskello/eslint-plugin-functional/compare/v1.0.3...v2.0.0) - 2019-12-29

@@ -64,6 +79,2 @@

### Changed
- Rename the "No mutability" heading and "immutable" ruleset to "no-mutations". [`#62`](https://github.com/jonaskello/eslint-plugin-functional/pull/62)
## [v1.0.0-rc.2](https://github.com/jonaskello/eslint-plugin-functional/compare/v1.0.0-rc.1...v1.0.0-rc.2) - 2019-08-07

@@ -83,2 +94,6 @@

### Fixed
- Merge pull request #57 from jonaskello/issue-56 [`#56`](https://github.com/jonaskello/eslint-plugin-functional/issues/56)
## [v0.5.3](https://github.com/jonaskello/eslint-plugin-functional/compare/v0.5.2...v0.5.3) - 2019-08-02

@@ -118,3 +133,3 @@

- Test configs [`#43`](https://github.com/jonaskello/eslint-plugin-functional/pull/43)
- feat(no-mixed-type): no-mixed-interface -> no-mixed-type [`#42`](https://github.com/jonaskello/eslint-plugin-functional/pull/42)
- feat(no-mixed-type): no-mixed-interface -> no-mixed-type [`#42`](https://github.com/jonaskello/eslint-plugin-functional/pull/42)
- feat(configs): Create additional configs for each category of rules. [`#40`](https://github.com/jonaskello/eslint-plugin-functional/pull/40)

@@ -128,2 +143,6 @@ - feat(functional-parameters): Add option to allow iifes [`#39`](https://github.com/jonaskello/eslint-plugin-functional/pull/39)

### Commits
- **Breaking change:** feat(ignore options): text matching MemberExpression nodes should include the property name [`4968348`](https://github.com/jonaskello/eslint-plugin-functional/commit/496834816ac7a96a5f4c25adf9f2980d1bc24254)
## [v0.4.0](https://github.com/jonaskello/eslint-plugin-functional/compare/v0.3.0...v0.4.0) - 2019-07-19

@@ -158,6 +177,2 @@

### Fixed
- TypeScript is no longer imported unless it is available.
## [v0.2.0](https://github.com/jonaskello/eslint-plugin-functional/compare/v0.1.0...v0.2.0) - 2019-07-12

@@ -172,3 +187,3 @@

- Consistent file casing [`#5`](https://github.com/jonaskello/eslint-plugin-functional/pull/5)
- Port docs for each rule [`#3`](https://github.com/jonaskello/eslint-plugin-functional/pull/3)
- WIP: Port docs for each rule [`#3`](https://github.com/jonaskello/eslint-plugin-functional/pull/3)

@@ -179,4 +194,6 @@ ### Fixed

## [v0.1.0](https://github.com/jonaskello/eslint-plugin-functional/releases/tag/v0.1.0) - 2019-07-01
## v0.1.0 - 2019-07-01
This is the first release and everything is experimental at this point.
### Merged
- Update readme for eslint [`#2`](https://github.com/jonaskello/eslint-plugin-functional/pull/2)

@@ -10,5 +10,4 @@ 'use strict';

var experimentalUtils = require('@typescript-eslint/experimental-utils');
var tslib_1 = require('tslib');
var config = {
const config = {
rules: {

@@ -41,3 +40,3 @@ "functional/functional-parameters": "error",

var config$1 = {
const config$1 = {
rules: {

@@ -48,3 +47,3 @@ "functional/functional-parameters": "error"

var config$2 = {
const config$2 = {
rules: {

@@ -72,3 +71,3 @@ "prefer-const": "error",

var config$3 = {
const config$3 = {
rules: {

@@ -89,3 +88,3 @@ "functional/no-let": "error",

var config$4 = {
const config$4 = {
rules: {

@@ -97,3 +96,3 @@ "functional/no-throw-statement": "error",

var config$5 = {
const config$5 = {
rules: {

@@ -114,3 +113,3 @@ "functional/no-this-expression": "error",

var config$6 = {
const config$6 = {
rules: {

@@ -131,3 +130,3 @@ "functional/no-expression-statement": "error",

var config$7 = deepMerge.all([
const config$7 = deepMerge.all([
config$1,

@@ -140,3 +139,3 @@ config$3,

var config$8 = deepMerge__default(config$7, {
const config$8 = deepMerge__default(config$7, {
rules: {

@@ -156,3 +155,3 @@ "functional/no-conditional-statement": "off",

// Conditionally loaded TypeScript but only if it is avaliable.
var ts = (function () {
var ts = (() => {
try {

@@ -303,5 +302,3 @@ return require("typescript");

}
function isArrayType(type, assumeType, node) {
if (assumeType === void 0) { assumeType = false; }
if (node === void 0) { node = null; }
function isArrayType(type, assumeType = false, node = null) {
return assumeType === true && type === null

@@ -312,7 +309,5 @@ ? node !== null

(isUnionType(type) &&
type.types.some(function (t) { return isArrayType(t, false, null); })));
type.types.some(t => isArrayType(t, false, null))));
}
function isArrayConstructorType(type, assumeType, node) {
if (assumeType === void 0) { assumeType = false; }
if (node === void 0) { node = null; }
function isArrayConstructorType(type, assumeType = false, node = null) {
return assumeType === true && type === null

@@ -323,7 +318,5 @@ ? node !== null && isIdentifier(node) && node.name === "Array"

(isUnionType(type) &&
type.types.some(function (t) { return isArrayConstructorType(t, false, null); })));
type.types.some(t => isArrayConstructorType(t, false, null))));
}
function isObjectConstructorType(type, assumeType, node) {
if (assumeType === void 0) { assumeType = false; }
if (node === void 0) { node = null; }
function isObjectConstructorType(type, assumeType = false, node = null) {
return assumeType === true && type === null

@@ -334,10 +327,9 @@ ? node !== null && isIdentifier(node) && node.name === "Object"

(isUnionType(type) &&
type.types.some(function (t) { return isObjectConstructorType(t, false, null); })));
type.types.some(t => isObjectConstructorType(t, false, null))));
}
/**
* Return the parent that meets the given check criteria.
* Return the first ancestor that meets the given check criteria.
*/
function getParentOfType(checker, node, child) {
if (child === void 0) { child = null; }
function getAncestorOfType(checker, node, child = null) {
return checker(node, child)

@@ -347,3 +339,3 @@ ? node

? null
: getParentOfType(checker, node.parent, node);
: getAncestorOfType(checker, node.parent, node);
}

@@ -354,3 +346,3 @@ /**

function inFunctionBody(node) {
return (getParentOfType(function (n, c) { return isFunctionLike(n) && n.body === c; }, node) !== null);
return (getAncestorOfType((n, c) => isFunctionLike(n) && n.body === c, node) !== null);
}

@@ -361,3 +353,3 @@ /**

function inClass(node) {
return getParentOfType(isClassLike, node) !== null;
return getAncestorOfType(isClassLike, node) !== null;
}

@@ -368,3 +360,3 @@ /**

function inInterface(node) {
return getParentOfType(isTSInterfaceBody, node) !== null;
return getAncestorOfType(isTSInterfaceBody, node) !== null;
}

@@ -375,3 +367,3 @@ /**

function inConstructor(node) {
var methodDefinition = getParentOfType(isMethodDefinition, node);
const methodDefinition = getAncestorOfType(isMethodDefinition, node);
return (methodDefinition !== null &&

@@ -385,7 +377,5 @@ isIdentifier(methodDefinition.key) &&

function isInReturnType(node) {
return (getParentOfType(function (n) {
return n.parent != undefined &&
isFunctionLike(n.parent) &&
n.parent.returnType === n;
}, node) !== null);
return (getAncestorOfType((n) => n.parent != undefined &&
isFunctionLike(n.parent) &&
n.parent.returnType === n, node) !== null);
}

@@ -419,3 +409,3 @@ /**

// Polyfill.
var allowLocalMutationOptionSchema = {
const allowLocalMutationOptionSchema = {
type: "object",

@@ -429,3 +419,3 @@ properties: {

};
var ignorePatternOptionSchema = {
const ignorePatternOptionSchema = {
type: "object",

@@ -442,3 +432,3 @@ properties: {

};
var ignoreAccessorPatternOptionSchema = {
const ignoreAccessorPatternOptionSchema = {
type: "object",

@@ -455,3 +445,3 @@ properties: {

};
var ignoreClassOptionSchema = {
const ignoreClassOptionSchema = {
type: "object",

@@ -465,3 +455,3 @@ properties: {

};
var ignoreInterfaceOptionSchema = {
const ignoreInterfaceOptionSchema = {
type: "object",

@@ -490,3 +480,3 @@ properties: {

: isMemberExpression(node)
? getNodeIdentifierText(node.object, context) + "." + getNodeIdentifierText(node.property, context)
? `${getNodeIdentifierText(node.object, context)}.${getNodeIdentifierText(node.property, context)}`
: isThisExpression(node)

@@ -512,6 +502,4 @@ ? "this"

return (isVariableDeclaration(node)
? node.declarations.flatMap(function (declarator) {
return getNodeIdentifierText(declarator, context);
})
: [getNodeIdentifierText(node, context)]).filter(function (text) { return text !== undefined; });
? node.declarations.flatMap(declarator => getNodeIdentifierText(declarator, context))
: [getNodeIdentifierText(node, context)]).filter((text) => text !== undefined);
}

@@ -524,7 +512,7 @@ /**

function shouldIgnoreViaPattern(text, ignorePattern) {
var patterns = Array.isArray(ignorePattern)
const patterns = Array.isArray(ignorePattern)
? ignorePattern
: [ignorePattern];
// One or more patterns match?
return patterns.some(function (pattern) { return new RegExp(pattern).test(text); });
return patterns.some(pattern => new RegExp(pattern).test(text));
}

@@ -538,5 +526,3 @@ /**

*/
function accessorPatternMatch(_a, textParts, allowExtra) {
var pattern = _a[0], remainingPatternParts = _a.slice(1);
if (allowExtra === void 0) { allowExtra = false; }
function accessorPatternMatch([pattern, ...remainingPatternParts], textParts, allowExtra = false) {
return pattern === undefined

@@ -549,6 +535,4 @@ ? allowExtra || textParts.length === 0

: Array.from({ length: textParts.length })
.map(function (_element, index) { return index; })
.some(function (offset) {
return accessorPatternMatch(remainingPatternParts, textParts.slice(offset), true);
})
.map((_element, index) => index)
.some(offset => accessorPatternMatch(remainingPatternParts, textParts.slice(offset), true))
: // Match anything?

@@ -559,3 +543,3 @@ pattern === "*"

: // Text matches pattern?
new RegExp("^" + escapeRegExp(pattern).replace(/\\\*/g, ".*") + "$").test(textParts[0]) &&
new RegExp(`^${escapeRegExp(pattern).replace(/\\\*/g, ".*")}$`).test(textParts[0]) &&
accessorPatternMatch(remainingPatternParts, textParts.slice(1), allowExtra);

@@ -569,9 +553,7 @@ }

function shouldIgnoreViaAccessorPattern(text, ignorePattern) {
var patterns = Array.isArray(ignorePattern)
const patterns = Array.isArray(ignorePattern)
? ignorePattern
: [ignorePattern];
// One or more patterns match?
return patterns.some(function (pattern) {
return accessorPatternMatch(pattern.split("."), text.split("."));
});
return patterns.some(pattern => accessorPatternMatch(pattern.split("."), text.split(".")));
}

@@ -595,19 +577,13 @@ /**

(options.ignoreInterface === true && inInterface(node)) ||
(function (texts) {
return texts.length > 0
? // Ignore if ignorePattern is set and a pattern matches.
(options.ignorePattern !== undefined &&
texts.every(function (text) {
return shouldIgnoreViaPattern(text, options.ignorePattern);
})) ||
// Ignore if ignoreAccessorPattern is set and an accessor pattern matches.
(options.ignoreAccessorPattern !== undefined &&
texts.every(function (text) {
return shouldIgnoreViaAccessorPattern(text, options.ignoreAccessorPattern);
}))
: false;
})(getNodeIdentifierTexts(node, context)));
((texts) => texts.length > 0
? // Ignore if ignorePattern is set and a pattern matches.
(options.ignorePattern !== undefined &&
texts.every(text => shouldIgnoreViaPattern(text, options.ignorePattern))) ||
// Ignore if ignoreAccessorPattern is set and an accessor pattern matches.
(options.ignoreAccessorPattern !== undefined &&
texts.every(text => shouldIgnoreViaAccessorPattern(text, options.ignoreAccessorPattern)))
: false)(getNodeIdentifierTexts(node, context)));
}
const version = "1.0.3";
const version = "2.0.0";

@@ -622,8 +598,6 @@ // This function can't be functional as it needs to interact with 3rd-party

function checkNode(check, context, options) {
return function (node) {
return (node) => {
if (!options || !shouldIgnore(node, context, options)) {
var result_1 = check(node, context, options);
result_1.descriptors.forEach(function (descriptor) {
return result_1.context.report(descriptor);
});
const result = check(node, context, options);
result.descriptors.forEach(descriptor => result.context.report(descriptor));
}

@@ -637,20 +611,11 @@ };

function createRule(name, meta, defaultOptions, ruleFunctionsMap) {
return experimentalUtils.ESLintUtils.RuleCreator(function (name) {
return "https://github.com/jonaskello/eslint-plugin-functional/blob/v" + version + "/docs/rules/" + name + ".md";
})({
name: name,
meta: meta,
return experimentalUtils.ESLintUtils.RuleCreator(name => `https://github.com/jonaskello/eslint-plugin-functional/blob/v${version}/docs/rules/${name}.md`)({
name,
meta,
defaultOptions: [defaultOptions],
create: function (context, _a) {
var options = _a[0];
return Object.entries(ruleFunctionsMap)
.map(function (_a) {
var _b;
var nodeSelector = _a[0], ruleFunction = _a[1];
return (_b = {},
_b[nodeSelector] = checkNode(ruleFunction, context, options),
_b);
})
.reduce(function (carry, object) { return (tslib_1.__assign({}, carry, object)); }, {});
}
create: (context, [options]) => Object.entries(ruleFunctionsMap)
.map(([nodeSelector, ruleFunction]) => ({
[nodeSelector]: checkNode(ruleFunction, context, options)
}))
.reduce((carry, object) => ({ ...carry, ...object }), {})
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */

@@ -663,3 +628,3 @@ });

function getTypeOfNode(node, context) {
var parserServices = context.parserServices;
const { parserServices } = context;
return parserServices === undefined ||

@@ -675,5 +640,5 @@ parserServices.program === undefined ||

// The name of this rule.
var name = "functional-parameters";
const name = "functional-parameters";
// The schema for the rule options.
var schema = [
const schema = [
deepMerge.all([

@@ -721,3 +686,3 @@ ignorePatternOptionSchema,

// The default options for the rule.
var defaultOptions = {
const defaultOptions = {
allowRestParameter: false,

@@ -731,3 +696,3 @@ allowArgumentsKeyword: false,

// The possible error messages.
var errorMessages = {
const errorMessages = {
restParam: "Unexpected rest parameter. Use a regular parameter of type array instead.",

@@ -739,3 +704,3 @@ arguments: "Unexpected use of `arguments`. Use regular function arguments instead.",

// The meta data for this rule.
var meta = {
const meta = {
type: "suggestion",

@@ -748,3 +713,3 @@ docs: {

messages: errorMessages,
schema: schema
schema
};

@@ -783,3 +748,3 @@ /**

{
node: node,
node,
messageId: "paramCountAtLeastOne"

@@ -795,3 +760,3 @@ }

{
node: node,
node,
messageId: "paramCountExactlyOne"

@@ -810,4 +775,7 @@ }

return {
context: context,
descriptors: getRestParamViolations(options.allowRestParameter, node).concat(getParamCountViolations(options.enforceParameterCount, node))
context,
descriptors: [
...getRestParamViolations(options.allowRestParameter, node),
...getParamCountViolations(options.enforceParameterCount, node)
]
};

@@ -820,3 +788,3 @@ }

return {
context: context,
context,
descriptors: !options.allowArgumentsKeyword &&

@@ -828,3 +796,3 @@ node.name === "arguments" &&

{
node: node,
node,
messageId: "arguments"

@@ -837,3 +805,3 @@ }

// Create the rule.
var rule = createRule(name, meta, defaultOptions, {
const rule = createRule(name, meta, defaultOptions, {
FunctionDeclaration: checkFunction,

@@ -850,3 +818,3 @@ FunctionExpression: checkFunction,

function isExpected(expected) {
return function (actual) { return actual === expected; };
return actual => actual === expected;
}

@@ -863,5 +831,5 @@ /**

// The name of this rule.
var name$1 = "immutable-data";
const name$1 = "immutable-data";
// The schema for the rule options.
var schema$1 = [
const schema$1 = [
deepMerge.all([

@@ -901,3 +869,3 @@ ignorePatternOptionSchema,

// The default options for the rule.
var defaultOptions$1 = {
const defaultOptions$1 = {
ignoreImmediateMutation: true,

@@ -910,3 +878,3 @@ assumeTypes: {

// The possible error messages.
var errorMessages$1 = {
const errorMessages$1 = {
generic: "Modifying an existing object/array is not allowed.",

@@ -917,3 +885,3 @@ object: "Modifying properties of existing object not allowed.",

// The meta data for this rule.
var meta$1 = {
const meta$1 = {
type: "suggestion",

@@ -933,3 +901,3 @@ docs: {

*/
var arrayMutatorMethods = [
const arrayMutatorMethods = [
"copyWithin",

@@ -951,3 +919,3 @@ "fill",

*/
var arrayNewObjectReturningMethods = [
const arrayNewObjectReturningMethods = [
"concat",

@@ -965,3 +933,3 @@ "slice",

*/
var arrayConstructorFunctions = ["from", "of"];
const arrayConstructorFunctions = ["from", "of"];
/**

@@ -972,3 +940,3 @@ * Object constructor functions that mutate an object.

*/
var objectConstructorMutatorFunctions = [
const objectConstructorMutatorFunctions = [
"assign",

@@ -984,7 +952,7 @@ "defineProperties",

return {
context: context,
context,
descriptors: isMemberExpression(node.left) &&
// Allow if in a constructor - allow for field initialization.
!inConstructor(node)
? [{ node: node, messageId: "generic" }]
? [{ node, messageId: "generic" }]
: []

@@ -998,5 +966,5 @@ };

return {
context: context,
context,
descriptors: node.operator === "delete" && isMemberExpression(node.argument)
? [{ node: node, messageId: "generic" }]
? [{ node, messageId: "generic" }]
: []

@@ -1010,5 +978,5 @@ };

return {
context: context,
context,
descriptors: isMemberExpression(node.argument)
? [{ node: node, messageId: "generic" }]
? [{ node, messageId: "generic" }]
: []

@@ -1029,12 +997,12 @@ };

// Check for: new Array()
((isNewExpression(node.object) &&
(isNewExpression(node.object) &&
isArrayConstructorType(getTypeOfNode(node.object.callee, context), assumeArrayTypes, node.object.callee)) ||
(isCallExpression(node.object) &&
isMemberExpression(node.object.callee) &&
isIdentifier(node.object.callee.property) &&
// Check for: Array.from(iterable)
((arrayConstructorFunctions.some(isExpected(node.object.callee.property.name)) &&
isArrayConstructorType(getTypeOfNode(node.object.callee.object, context), assumeArrayTypes, node.object.callee.object)) ||
// Check for: array.slice(0)
arrayNewObjectReturningMethods.some(isExpected(node.object.callee.property.name))))));
(isCallExpression(node.object) &&
isMemberExpression(node.object.callee) &&
isIdentifier(node.object.callee.property) &&
// Check for: Array.from(iterable)
((arrayConstructorFunctions.some(isExpected(node.object.callee.property.name)) &&
isArrayConstructorType(getTypeOfNode(node.object.callee.object, context), assumeArrayTypes, node.object.callee.object)) ||
// Check for: array.slice(0)
arrayNewObjectReturningMethods.some(isExpected(node.object.callee.property.name)))));
}

@@ -1045,8 +1013,8 @@ /**

function checkCallExpression(node, context, options) {
var assumeTypesForArrays = options.assumeTypes === true ||
const assumeTypesForArrays = options.assumeTypes === true ||
(options.assumeTypes !== false && options.assumeTypes.forArrays === true);
var assumeTypesForObjects = options.assumeTypes === true ||
const assumeTypesForObjects = options.assumeTypes === true ||
(options.assumeTypes !== false && options.assumeTypes.forObjects === true);
return {
context: context,
context,
descriptors:

@@ -1058,17 +1026,13 @@ // Potential object mutation?

!shouldIgnore(node.callee.object, context, options) &&
arrayMutatorMethods.some(function (m) {
return m ===
node.callee
.property.name;
}) &&
arrayMutatorMethods.some(m => m ===
node.callee
.property.name) &&
(!options.ignoreImmediateMutation ||
!isInChainCallAndFollowsNew(node.callee, context, assumeTypesForArrays)) &&
isArrayType(getTypeOfNode(node.callee.object, context), assumeTypesForArrays, node.callee.object)
? [{ node: node, messageId: "array" }]
? [{ node, messageId: "array" }]
: // Potential non-array object mutation (ex. Object.assign on identifier)?
objectConstructorMutatorFunctions.some(function (m) {
return m ===
node.callee
.property.name;
}) &&
objectConstructorMutatorFunctions.some(m => m ===
node.callee
.property.name) &&
node.arguments.length >= 2 &&

@@ -1080,3 +1044,3 @@ (isIdentifier(node.arguments[0]) ||

isObjectConstructorType(getTypeOfNode(node.callee.object, context), assumeTypesForObjects, node.callee.object)
? [{ node: node, messageId: "object" }]
? [{ node, messageId: "object" }]
: []

@@ -1087,3 +1051,3 @@ : []

// Create the rule.
var rule$1 = createRule(name$1, meta$1, defaultOptions$1, {
const rule$1 = createRule(name$1, meta$1, defaultOptions$1, {
AssignmentExpression: checkAssignmentExpression,

@@ -1096,13 +1060,13 @@ UnaryExpression: checkUnaryExpression,

// The name of this rule.
var name$2 = "no-class";
const name$2 = "no-class";
// The schema for the rule options.
var schema$2 = [];
const schema$2 = [];
// The default options for the rule.
var defaultOptions$2 = {};
const defaultOptions$2 = {};
// The possible error messages.
var errorMessages$2 = {
const errorMessages$2 = {
generic: "Unexpected class, use functions not classes."
};
// The meta data for this rule.
var meta$2 = {
const meta$2 = {
type: "suggestion",

@@ -1122,11 +1086,11 @@ docs: {

// All class nodes violate this rule.
return { context: context, descriptors: [{ node: node, messageId: "generic" }] };
return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
var rule$2 = createRule(name$2, meta$2, defaultOptions$2, { ClassDeclaration: checkClass, ClassExpression: checkClass });
const rule$2 = createRule(name$2, meta$2, defaultOptions$2, { ClassDeclaration: checkClass, ClassExpression: checkClass });
// The name of this rule.
var name$3 = "no-conditional-statement";
const name$3 = "no-conditional-statement";
// The schema for the rule options.
var schema$3 = [
const schema$3 = [
{

@@ -1151,5 +1115,5 @@ type: "object",

// The default options for the rule.
var defaultOptions$3 = { allowReturningBranches: false };
const defaultOptions$3 = { allowReturningBranches: false };
// The possible error messages.
var errorMessages$3 = {
const errorMessages$3 = {
incompleteBranch: "Incomplete branch, every branch in a conditional statement must contain a return statement.",

@@ -1162,3 +1126,3 @@ incompleteIf: "Incomplete if, it must have an else statement and every branch must contain a return statement.",

// The meta data for this rule.
var meta$3 = {
const meta$3 = {
type: "suggestion",

@@ -1178,16 +1142,12 @@ docs: {

function getIfBranchViolations(node) {
var nodes = [node.consequent, node.alternate].reduce(function (carry, branch) {
return branch === null ||
isReturnStatement(branch) ||
(isBlockStatement(branch) &&
branch.body.some(function (statement) {
return isReturnStatement(statement) ||
// Another instance of this rule will check nested if statements.
isIfStatement(statement);
})) ||
isIfStatement(branch)
? carry
: carry.concat([branch]);
}, []);
return nodes.flatMap(function (node) { return [{ node: node, messageId: "incompleteBranch" }]; });
const nodes = [node.consequent, node.alternate].reduce((carry, branch) => branch === null ||
isReturnStatement(branch) ||
(isBlockStatement(branch) &&
branch.body.some(statement => isReturnStatement(statement) ||
// Another instance of this rule will check nested if statements.
isIfStatement(statement))) ||
isIfStatement(branch)
? carry
: [...carry, branch], []);
return nodes.flatMap(node => [{ node, messageId: "incompleteBranch" }]);
}

@@ -1199,11 +1159,9 @@ /**

function getSwitchViolations(node) {
var nodes = node.cases.reduce(function (carry, branch) {
return branch.consequent.length === 0 ||
branch.consequent.some(isReturnStatement) ||
(branch.consequent.every(isBlockStatement) &&
branch.consequent[branch.consequent.length - 1].body.some(isReturnStatement))
? carry
: carry.concat([branch]);
}, []);
return nodes.flatMap(function (node) { return [{ node: node, messageId: "incompleteBranch" }]; });
const nodes = node.cases.reduce((carry, branch) => branch.consequent.length === 0 ||
branch.consequent.some(isReturnStatement) ||
(branch.consequent.every(isBlockStatement) &&
branch.consequent[branch.consequent.length - 1].body.some(isReturnStatement))
? carry
: [...carry, branch], []);
return nodes.flatMap(node => [{ node, messageId: "incompleteBranch" }]);
}

@@ -1224,3 +1182,3 @@ /**

// No default case defined.
node.cases.every(function (c) { return c.test !== null; }));
node.cases.every(c => c.test !== null));
}

@@ -1232,10 +1190,10 @@ /**

return {
context: context,
context,
descriptors: options.allowReturningBranches
? options.allowReturningBranches === "ifExhaustive"
? isExhaustiveIfViolation(node)
? [{ node: node, messageId: "incompleteIf" }]
? [{ node, messageId: "incompleteIf" }]
: getIfBranchViolations(node)
: getIfBranchViolations(node)
: [{ node: node, messageId: "unexpectedIf" }]
: [{ node, messageId: "unexpectedIf" }]
};

@@ -1248,14 +1206,14 @@ }

return {
context: context,
context,
descriptors: options.allowReturningBranches
? options.allowReturningBranches === "ifExhaustive"
? isExhaustiveSwitchViolation(node)
? [{ node: node, messageId: "incompleteSwitch" }]
? [{ node, messageId: "incompleteSwitch" }]
: getSwitchViolations(node)
: getSwitchViolations(node)
: [{ node: node, messageId: "unexpectedSwitch" }]
: [{ node, messageId: "unexpectedSwitch" }]
};
}
// Create the rule.
var rule$3 = createRule(name$3, meta$3, defaultOptions$3, {
const rule$3 = createRule(name$3, meta$3, defaultOptions$3, {
IfStatement: checkIfStatement,

@@ -1266,13 +1224,13 @@ SwitchStatement: checkSwitchStatement

// The name of this rule.
var name$4 = "no-expression-statement";
const name$4 = "no-expression-statement";
// The schema for the rule options.
var schema$4 = [ignorePatternOptionSchema];
const schema$4 = [ignorePatternOptionSchema];
// The default options for the rule.
var defaultOptions$4 = {};
const defaultOptions$4 = {};
// The possible error messages.
var errorMessages$4 = {
const errorMessages$4 = {
generic: "Using expressions to cause side-effects not allowed."
};
// The meta data for this rule.
var meta$4 = {
const meta$4 = {
type: "suggestion",

@@ -1292,10 +1250,10 @@ docs: {

return {
context: context,
context,
descriptors:
// Allow specifying directive prologues.
isDirectivePrologue(node) ? [] : [{ node: node, messageId: "generic" }]
isDirectivePrologue(node) ? [] : [{ node, messageId: "generic" }]
};
}
// Create the rule.
var rule$4 = createRule(name$4, meta$4, defaultOptions$4, {
const rule$4 = createRule(name$4, meta$4, defaultOptions$4, {
ExpressionStatement: checkExpressionStatement

@@ -1305,17 +1263,17 @@ });

// The name of this rule.
var name$5 = "no-let";
const name$5 = "no-let";
// The schema for the rule options.
var schema$5 = [
const schema$5 = [
deepMerge.all([allowLocalMutationOptionSchema, ignorePatternOptionSchema])
];
// The default options for the rule.
var defaultOptions$5 = {
const defaultOptions$5 = {
allowLocalMutation: false
};
// The possible error messages.
var errorMessages$5 = {
const errorMessages$5 = {
generic: "Unexpected let, use const instead."
};
// The meta data for this rule.
var meta$5 = {
const meta$5 = {
type: "suggestion",

@@ -1336,8 +1294,8 @@ docs: {

return {
context: context,
descriptors: node.kind === "let" ? [{ node: node, messageId: "generic" }] : []
context,
descriptors: node.kind === "let" ? [{ node, messageId: "generic" }] : []
};
}
// Create the rule.
var rule$5 = createRule(name$5, meta$5, defaultOptions$5, {
const rule$5 = createRule(name$5, meta$5, defaultOptions$5, {
VariableDeclaration: checkVariableDeclaration

@@ -1347,13 +1305,13 @@ });

// The name of this rule.
var name$6 = "no-loop-statement";
const name$6 = "no-loop-statement";
// The schema for the rule options.
var schema$6 = [];
const schema$6 = [];
// The default options for the rule.
var defaultOptions$6 = {};
const defaultOptions$6 = {};
// The possible error messages.
var errorMessages$6 = {
const errorMessages$6 = {
generic: "Unexpected loop, use map or reduce instead."
};
// The meta data for this rule.
var meta$6 = {
const meta$6 = {
type: "suggestion",

@@ -1373,6 +1331,6 @@ docs: {

// All loops violate this rule.
return { context: context, descriptors: [{ node: node, messageId: "generic" }] };
return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
var rule$6 = createRule(name$6, meta$6, defaultOptions$6, {
const rule$6 = createRule(name$6, meta$6, defaultOptions$6, {
ForStatement: checkLoop,

@@ -1386,13 +1344,13 @@ ForInStatement: checkLoop,

// The name of this rule.
var name$7 = "no-method-signature";
const name$7 = "no-method-signature";
// The schema for the rule options.
var schema$7 = [];
const schema$7 = [];
// The default options for the rule.
var defaultOptions$7 = {};
const defaultOptions$7 = {};
// The possible error messages.
var errorMessages$7 = {
const errorMessages$7 = {
generic: "Method signature is mutable, use property signature with readonly modifier instead."
};
// The meta data for this rule.
var meta$7 = {
const meta$7 = {
type: "suggestion",

@@ -1412,6 +1370,6 @@ docs: {

// All TS method signatures violate this rule.
return { context: context, descriptors: [{ node: node, messageId: "generic" }] };
return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
var rule$7 = createRule(name$7, meta$7, defaultOptions$7, {
const rule$7 = createRule(name$7, meta$7, defaultOptions$7, {
TSMethodSignature: checkTSMethodSignature

@@ -1421,5 +1379,5 @@ });

// The name of this rule.
var name$8 = "no-mixed-type";
const name$8 = "no-mixed-type";
// The schema for the rule options.
var schema$8 = [
const schema$8 = [
{

@@ -1439,3 +1397,3 @@ type: "object",

// The default options for the rule.
var defaultOptions$8 = {
const defaultOptions$8 = {
checkInterfaces: true,

@@ -1445,7 +1403,7 @@ checkTypeLiterals: true

// The possible error messages.
var errorMessages$8 = {
const errorMessages$8 = {
generic: "Only the same kind of members allowed in types."
};
// The meta data for this rule.
var meta$8 = {
const meta$8 = {
type: "suggestion",

@@ -1464,5 +1422,5 @@ docs: {

function getTypeElementViolations(typeElements) {
return typeElements.reduce(function (carry, member) {
var memberType = member.type;
var memberTypeAnnotation = isTSPropertySignature(member) && member.typeAnnotation !== undefined
return typeElements.reduce((carry, member) => {
const memberType = member.type;
const memberTypeAnnotation = isTSPropertySignature(member) && member.typeAnnotation !== undefined
? member.typeAnnotation.typeAnnotation.type

@@ -1484,3 +1442,4 @@ : undefined;

memberTypeAnnotation === experimentalUtils.AST_NODE_TYPES.TSFunctionType)))
? carry.violations.concat([{ node: member, messageId: "generic" }]) : carry.violations
? [...carry.violations, { node: member, messageId: "generic" }]
: carry.violations
};

@@ -1498,3 +1457,3 @@ }, {

return {
context: context,
context,
descriptors: options.checkInterfaces

@@ -1510,3 +1469,3 @@ ? getTypeElementViolations(node.body.body)

return {
context: context,
context,
descriptors: options.checkTypeLiterals && isTSTypeLiteral(node.typeAnnotation)

@@ -1518,3 +1477,3 @@ ? getTypeElementViolations(node.typeAnnotation.members)

// Create the rule.
var rule$8 = createRule(name$8, meta$8, defaultOptions$8, {
const rule$8 = createRule(name$8, meta$8, defaultOptions$8, {
TSInterfaceDeclaration: checkTSInterfaceDeclaration,

@@ -1525,13 +1484,13 @@ TSTypeAliasDeclaration: checkTSTypeAliasDeclaration

// The name of this rule.
var name$9 = "no-promise-reject";
const name$9 = "no-promise-reject";
// The schema for the rule options.
var schema$9 = [];
const schema$9 = [];
// The default options for the rule.
var defaultOptions$9 = {};
const defaultOptions$9 = {};
// The possible error messages.
var errorMessages$9 = {
const errorMessages$9 = {
generic: "Unexpected reject, return an error instead."
};
// The meta data for this rule.
var meta$9 = {
const meta$9 = {
type: "suggestion",

@@ -1551,3 +1510,3 @@ docs: {

return {
context: context,
context,
descriptors: isMemberExpression(node.callee) &&

@@ -1558,3 +1517,3 @@ isIdentifier(node.callee.object) &&

node.callee.property.name === "reject"
? [{ node: node, messageId: "generic" }]
? [{ node, messageId: "generic" }]
: []

@@ -1564,3 +1523,3 @@ };

// Create the rule.
var rule$9 = createRule(name$9, meta$9, defaultOptions$9, {
const rule$9 = createRule(name$9, meta$9, defaultOptions$9, {
CallExpression: checkCallExpression$1

@@ -1570,5 +1529,5 @@ });

// The name of this rule.
var name$a = "no-return-void";
const name$a = "no-return-void";
// The schema for the rule options.
var schema$a = [
const schema$a = [
{

@@ -1588,3 +1547,3 @@ type: "object",

// The default options for the rule.
var defaultOptions$a = {
const defaultOptions$a = {
allowNull: true,

@@ -1594,7 +1553,7 @@ allowUndefined: true

// The possible error messages.
var errorMessages$a = {
const errorMessages$a = {
generic: "Function must return a value."
};
// The meta data for this rule.
var meta$a = {
const meta$a = {
type: "suggestion",

@@ -1614,3 +1573,3 @@ docs: {

return {
context: context,
context,
descriptors: node.returnType !== undefined &&

@@ -1627,3 +1586,3 @@ (isTSVoidKeyword(node.returnType.typeAnnotation) ||

// Create the rule.
var rule$a = createRule(name$a, meta$a, defaultOptions$a, {
const rule$a = createRule(name$a, meta$a, defaultOptions$a, {
FunctionDeclaration: checkFunction$1,

@@ -1636,13 +1595,13 @@ FunctionExpression: checkFunction$1,

// The name of this rule.
var name$b = "no-this-expression";
const name$b = "no-this-expression";
// The schema for the rule options.
var schema$b = [];
const schema$b = [];
// The default options for the rule.
var defaultOptions$b = {};
const defaultOptions$b = {};
// The possible error messages.
var errorMessages$b = {
const errorMessages$b = {
generic: "Unexpected this, use functions not classes."
};
// The meta data for this rule.
var meta$b = {
const meta$b = {
type: "suggestion",

@@ -1662,6 +1621,6 @@ docs: {

// All throw statements violate this rule.
return { context: context, descriptors: [{ node: node, messageId: "generic" }] };
return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
var rule$b = createRule(name$b, meta$b, defaultOptions$b, {
const rule$b = createRule(name$b, meta$b, defaultOptions$b, {
ThisExpression: checkThisExpression

@@ -1671,13 +1630,13 @@ });

// The name of this rule.
var name$c = "no-throw-statement";
const name$c = "no-throw-statement";
// The schema for the rule options.
var schema$c = [];
const schema$c = [];
// The default options for the rule.
var defaultOptions$c = {};
const defaultOptions$c = {};
// The possible error messages.
var errorMessages$c = {
const errorMessages$c = {
generic: "Unexpected throw, throwing exceptions is not functional."
};
// The meta data for this rule.
var meta$c = {
const meta$c = {
type: "suggestion",

@@ -1697,6 +1656,6 @@ docs: {

// All throw statements violate this rule.
return { context: context, descriptors: [{ node: node, messageId: "generic" }] };
return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
var rule$c = createRule(name$c, meta$c, defaultOptions$c, {
const rule$c = createRule(name$c, meta$c, defaultOptions$c, {
ThrowStatement: checkThrowStatement

@@ -1706,5 +1665,5 @@ });

// The name of this rule.
var name$d = "no-try-statement";
const name$d = "no-try-statement";
// The schema for the rule options.
var schema$d = [
const schema$d = [
{

@@ -1724,3 +1683,3 @@ type: "object",

// The default options for the rule.
var defaultOptions$d = {
const defaultOptions$d = {
allowCatch: false,

@@ -1730,3 +1689,3 @@ allowFinally: false

// The possible error messages.
var errorMessages$d = {
const errorMessages$d = {
catch: "Unexpected try-catch, this pattern is not functional.",

@@ -1736,3 +1695,3 @@ finally: "Unexpected try-finally, this pattern is not functional."

// The meta data for this rule.
var meta$d = {
const meta$d = {
type: "suggestion",

@@ -1752,7 +1711,7 @@ docs: {

return {
context: context,
context,
descriptors: !options.allowCatch && node.handler !== null
? [{ node: node, messageId: "catch" }]
? [{ node, messageId: "catch" }]
: !options.allowFinally && node.finalizer !== null
? [{ node: node, messageId: "finally" }]
? [{ node, messageId: "finally" }]
: []

@@ -1762,3 +1721,3 @@ };

// Create the rule.
var rule$d = createRule(name$d, meta$d, defaultOptions$d, {
const rule$d = createRule(name$d, meta$d, defaultOptions$d, {
TryStatement: checkTryStatement

@@ -1769,5 +1728,5 @@ });

// The name of this rule.
var name$e = "prefer-readonly-type";
const name$e = "prefer-readonly-type";
// The schema for the rule options.
var schema$e = [
const schema$e = [
deepMerge.all([

@@ -1793,3 +1752,3 @@ allowLocalMutationOptionSchema,

// The default options for the rule.
var defaultOptions$e = {
const defaultOptions$e = {
checkImplicit: false,

@@ -1802,3 +1761,3 @@ ignoreClass: false,

// The possible error messages.
var errorMessages$e = {
const errorMessages$e = {
array: "Only readonly arrays allowed.",

@@ -1811,3 +1770,3 @@ implicit: "Implicitly a mutable array. Only readonly arrays allowed.",

// The meta data for this rule.
var meta$e = {
const meta$e = {
type: "suggestion",

@@ -1823,3 +1782,7 @@ docs: {

};
var mutableToImmutableTypes = new Map([["Array", "ReadonlyArray"], ["Map", "ReadonlyMap"], ["Set", "ReadonlySet"]]);
const mutableToImmutableTypes = new Map([
["Array", "ReadonlyArray"],
["Map", "ReadonlyMap"],
["Set", "ReadonlySet"]
]);
/**

@@ -1830,3 +1793,3 @@ * Check if the given ArrayType or TupleType violates this rule.

return {
context: context,
context,
descriptors: (!node.parent ||

@@ -1838,10 +1801,10 @@ !isTSTypeOperator(node.parent) ||

{
node: node,
node,
messageId: isTSTupleType(node) ? "tuple" : "array",
fix: node.parent && isTSArrayType(node.parent)
? function (fixer) { return [
? fixer => [
fixer.insertTextBefore(node, "(readonly "),
fixer.insertTextAfter(node, ")")
]; }
: function (fixer) { return fixer.insertTextBefore(node, "readonly "); }
]
: fixer => fixer.insertTextBefore(node, "readonly ")
}

@@ -1857,12 +1820,12 @@ ]

if (isIdentifier(node.typeName)) {
var immutableType_1 = mutableToImmutableTypes.get(node.typeName.name);
const immutableType = mutableToImmutableTypes.get(node.typeName.name);
return {
context: context,
descriptors: immutableType_1 &&
context,
descriptors: immutableType &&
(!options.allowMutableReturnType || !isInReturnType(node))
? [
{
node: node,
node,
messageId: "type",
fix: function (fixer) { return fixer.replaceText(node.typeName, immutableType_1); }
fix: fixer => fixer.replaceText(node.typeName, immutableType)
}

@@ -1875,3 +1838,3 @@ ]

return {
context: context,
context,
descriptors: []

@@ -1886,3 +1849,3 @@ };

return {
context: context,
context,
descriptors: node.readonly

@@ -1892,9 +1855,9 @@ ? []

{
node: node,
node,
messageId: "property",
fix: isTSIndexSignature(node)
? function (fixer) { return fixer.insertTextBefore(node, "readonly "); }
? fixer => fixer.insertTextBefore(node, "readonly ")
: isTSParameterProperty(node)
? function (fixer) { return fixer.insertTextBefore(node.parameter, "readonly "); }
: function (fixer) { return fixer.insertTextBefore(node.key, "readonly "); }
? fixer => fixer.insertTextBefore(node.parameter, "readonly ")
: fixer => fixer.insertTextBefore(node.key, "readonly ")
}

@@ -1909,39 +1872,31 @@ ]

if (options.checkImplicit) {
var declarators = isFunctionLike(node)
const declarators = isFunctionLike(node)
? node.params
.map(function (param) {
return isAssignmentPattern(param)
? {
id: param.left,
init: param.right,
node: param
.map(param => isAssignmentPattern(param)
? {
id: param.left,
init: param.right,
node: param
}
: undefined)
.filter((param) => param !== undefined)
: node.declarations.map(declaration => ({
id: declaration.id,
init: declaration.init,
node: declaration
}));
return {
context,
descriptors: declarators.flatMap(declarator => isIdentifier(declarator.id) &&
declarator.id.typeAnnotation === undefined &&
declarator.init !== null &&
isArrayType(getTypeOfNode(declarator.init, context))
? [
{
node: declarator.node,
messageId: "implicit",
fix: fixer => fixer.insertTextAfter(declarator.id, ": readonly unknown[]")
}
: undefined;
})
.filter(function (param) { return param !== undefined; })
: node.declarations.map(function (declaration) {
return ({
id: declaration.id,
init: declaration.init,
node: declaration
});
});
return {
context: context,
descriptors: declarators.flatMap(function (declarator) {
return isIdentifier(declarator.id) &&
declarator.id.typeAnnotation === undefined &&
declarator.init !== null &&
isArrayType(getTypeOfNode(declarator.init, context))
? [
{
node: declarator.node,
messageId: "implicit",
fix: function (fixer) {
return fixer.insertTextAfter(declarator.id, ": readonly unknown[]");
}
}
]
: [];
})
]
: [])
};

@@ -1951,3 +1906,3 @@ }

return {
context: context,
context,
descriptors: []

@@ -1958,3 +1913,3 @@ };

// Create the rule.
var rule$e = createRule(name$e, meta$e, defaultOptions$e, {
const rule$e = createRule(name$e, meta$e, defaultOptions$e, {
TSArrayType: checkArrayOrTupleType,

@@ -1974,17 +1929,17 @@ TSTupleType: checkArrayOrTupleType,

// The name of this rule.
var name$f = "prefer-type-literal";
const name$f = "prefer-type-literal";
// The schema for the rule options.
var schema$f = [
const schema$f = [
deepMerge.all([allowLocalMutationOptionSchema, ignorePatternOptionSchema])
];
// The default options for the rule.
var defaultOptions$f = {
const defaultOptions$f = {
allowLocalMutation: false
};
// The possible error messages.
var errorMessages$f = {
const errorMessages$f = {
generic: "Unexpected interface, use a type literal instead."
};
// The meta data for this rule.
var meta$f = {
const meta$f = {
type: "suggestion",

@@ -2005,21 +1960,20 @@ docs: {

return {
context: context,
context,
descriptors: [
{
node: node,
node,
messageId: "generic",
fix: node.extends === undefined ||
node.extends.every(function (type) { return isIdentifier(type.expression); })
? function (fixer) { return [
node.extends.every(type => isIdentifier(type.expression))
? fixer => [
fixer.replaceTextRange([node.range[0], node.range[0] + "interface".length], "type"),
fixer.insertTextBefore(node.body, "= ")
].concat((node.extends === undefined
? []
: [
fixer.replaceTextRange([node.id.range[1], node.body.range[0]], " ")
].concat(node.extends.map(function (type) {
return fixer.insertTextBefore(node.body, type.expression.name + " & ");
}))), [
fixer.insertTextBefore(node.body, "= "),
...(node.extends === undefined
? []
: [
fixer.replaceTextRange([node.id.range[1], node.body.range[0]], " "),
...node.extends.map(type => fixer.insertTextBefore(node.body, `${type.expression.name} & `))
]),
fixer.insertTextAfter(node, ";")
]); }
]
: undefined

@@ -2031,31 +1985,30 @@ }

// Create the rule.
var rule$f = createRule(name$f, meta$f, defaultOptions$f, {
const rule$f = createRule(name$f, meta$f, defaultOptions$f, {
TSInterfaceDeclaration: checkInterface
});
var _a;
/**
* All of the custom rules.
*/
var rules = (_a = {},
_a[name] = rule,
_a[name$1] = rule$1,
_a[name$2] = rule$2,
_a[name$3] = rule$3,
_a[name$4] = rule$4,
_a[name$5] = rule$5,
_a[name$6] = rule$6,
_a[name$7] = rule$7,
_a[name$8] = rule$8,
_a[name$9] = rule$9,
_a[name$a] = rule$a,
_a[name$b] = rule$b,
_a[name$c] = rule$c,
_a[name$d] = rule$d,
_a[name$e] = rule$e,
_a[name$f] = rule$f,
_a);
const rules = {
[name]: rule,
[name$1]: rule$1,
[name$2]: rule$2,
[name$3]: rule$3,
[name$4]: rule$4,
[name$5]: rule$5,
[name$6]: rule$6,
[name$7]: rule$7,
[name$8]: rule$8,
[name$9]: rule$9,
[name$a]: rule$a,
[name$b]: rule$b,
[name$c]: rule$c,
[name$d]: rule$d,
[name$e]: rule$e,
[name$f]: rule$f
};
var config$9 = {
rules: rules,
const config$9 = {
rules,
configs: {

@@ -2062,0 +2015,0 @@ all: config,

{
"name": "eslint-plugin-functional",
"version": "2.0.0",
"version": "3.0.0",
"description": "ESLint rules to disable mutation and promote fp in TypeScript.",
"main": "lib/index.js",
"module": "lib/index.mjs",
"repository": {
"type": "git",
"url": "git+https://github.com/jonaskello/eslint-plugin-functional"
},
"keywords": [
"eslint",
"eslint plugin",
"immutable",
"immutability",
"fp",
"functional",
"functional programming",
"fp"
"immutability",
"immutable"
],
"homepage": "https://github.com/jonaskello/eslint-plugin-functional#readme",
"bugs": {
"url": "https://github.com/jonaskello/eslint-plugin-functional/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jonaskello/eslint-plugin-functional"
},
"license": "MIT",
"author": "Jonas Kello",

@@ -27,7 +30,2 @@ "contributors": [

],
"license": "MIT",
"bugs": {
"url": "https://github.com/jonaskello/eslint-plugin-functional/issues"
},
"homepage": "https://github.com/jonaskello/eslint-plugin-functional#readme",
"files": [

@@ -40,6 +38,39 @@ "/lib",

],
"exports": {
"import": "./lib/index.mjs",
"require": "./lib/index.js",
"default": "./lib/index.js"
},
"main": "lib/index.js",
"scripts": {
"build": "yarn rimraf lib && yarn compile",
"build-tests": "yarn rimraf build && yarn compile-tests",
"compile": "yarn rollup -c",
"compile-tests": "yarn tsc -p tsconfig.tests.json && cp ./tests/helpers/tsconfig.json ./build/tests/helpers/",
"prelint": "yarn build && yarn link && yarn link 'eslint-plugin-functional'",
"lint": "yarn eslint './{src,tests}/**/*.ts' --ext .ts -f visualstudio",
"report-coverage": "yarn codecov -f coverage/lcov.info",
"test": "yarn jest --testPathIgnorePatterns _work.test",
"test-compiled": "USE_COMPLIED=1 yarn test",
"test-work": "yarn jest tests/rules/_work.test.ts",
"verify": "yarn build && yarn lint && yarn build-tests && yarn test-compiled && rimraf build",
"preversion": "yarn verify",
"postversion": "yarn auto-changelog -p && git add CHANGELOG.md && git commit -m \"docs(changelog): update changelog for v$npm_package_version\" && git push --tags && yarn publish --new-version $npm_package_version && git push && echo \"Successfully released version $npm_package_version!\""
},
"husky": {
"hooks": {
"pre-commit": "yarn lint-staged"
}
},
"lint-staged": {
"./{src,tests}/**/*.{ts,json}": [
"yarn prettier --write",
"git add"
],
"./{src,tests}/**/*.{ts}": "eslint"
},
"dependencies": {
"@typescript-eslint/experimental-utils": "^1.11.0",
"array.prototype.flatmap": "^1.2.1",
"deepmerge": "^3.3.0",
"@typescript-eslint/experimental-utils": "^2.15.0",
"array.prototype.flatmap": "^1.2.3",
"deepmerge": "^4.2.2",
"escape-string-regexp": "^2.0.0"

@@ -49,4 +80,4 @@ },

"@types/dedent": "^0.7.0",
"@types/eslint": "^4.16.6",
"@types/estree": "^0.0.39",
"@types/eslint": "^6.1.3",
"@types/estree": "^0.0.42",
"@types/glob": "^7.1.1",

@@ -57,27 +88,28 @@ "@types/jest": "^24.0.15",

"@typescript-eslint/parser": "^2.3.1",
"auto-changelog": "^1.16.2",
"babel-eslint": "^10.0.2",
"codecov": "^3.5.0",
"dedent": "^0.7.0",
"eslint": "^6.5.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-eslint-plugin": "^2.1.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-jest": "^22.7.1",
"eslint-plugin-jsdoc": "^15.5.3",
"eslint-plugin-prettier": "^3.1.0",
"glob": "^7.1.4",
"husky": "^2.4.1",
"jest": "^24.8.0",
"json-schema": "^0.2.3",
"lint-staged": "^8.2.1",
"prettier": "^1.18.2",
"rimraf": "^2.6.3",
"rollup": "^1.16.2",
"rollup-plugin-commonjs": "^10.0.1",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.9.0",
"eslint-plugin-eslint-plugin": "^2.2.0",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-jest": "^23.4.0",
"eslint-plugin-jsdoc": "^20.0.5",
"eslint-plugin-prettier": "^3.1.2",
"glob": "^7.1.6",
"husky": "^4.0.6",
"jest": "^24.9.0",
"json-schema": "^0.2.5",
"lint-staged": "^9.5.0",
"prettier": "^1.19.1",
"rimraf": "^3.0.0",
"rollup": "^1.29.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.1.0",
"rollup-plugin-typescript2": "^0.21.2",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-typescript2": "^0.25.3",
"shelljs": "^0.8.3",
"ts-jest": "^24.0.2",
"typescript": "^3.5.2"
"ts-jest": "^24.3.0",
"typescript": "^3.7.4"
},

@@ -93,29 +125,5 @@ "peerDependencies": {

},
"scripts": {
"compile": "rollup -c",
"compile-tests": "tsc -p tsconfig.tests.json && cp ./tests/helpers/tsconfig.json ./build/tests/helpers/",
"build-tests": "rimraf build && yarn compile-tests",
"build": "rimraf lib && yarn compile",
"prelint": "yarn build && yarn link && yarn link 'eslint-plugin-functional'",
"lint": "eslint './{src,tests}/**/*.ts' --ext .ts -f visualstudio",
"test": "jest --testPathIgnorePatterns _work.test",
"test-work": "jest tests/rules/_work.test.ts",
"test-compiled": "USE_COMPLIED=1 yarn test",
"verify": "yarn build && yarn lint && yarn build-tests && yarn test-compiled && rimraf build",
"report-coverage": "codecov -f coverage/lcov.info",
"preversion": "yarn verify",
"postversion": "git push --tags && yarn publish --new-version $npm_package_version && git push && echo \"Successfully released version $npm_package_version!\""
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"./{src,tests}/**/*.{ts}": "eslint",
"./{src,tests}/**/*.{ts,json}": [
"prettier --write",
"git add"
]
"engines": {
"node": ">=10.18.0"
}
}

@@ -0,20 +1,22 @@

<div align="center">
![eslint-logo](docs/assets/eslint-logo.svg)
# eslint-plugin-functional
[![npm version][version-image]][version-url]
[![travis build][travis-image]][travis-url]
[![Coverage Status][codecov-image]][codecov-url]
[![code style: prettier][prettier-image]][prettier-url]
[![MIT license][license-image]][license-url]
[![Join the community on Spectrum][spectrum-image]][spectrum-url]
[![npm version](https://img.shields.io/npm/v/eslint-plugin-functional.svg?style=flat)](https://www.npmjs.com/package/eslint-plugin-functional)
[![travis build](https://travis-ci.com/jonaskello/eslint-plugin-functional.svg?branch=master&amp;style=flat)](https://travis-ci.com/jonaskello/eslint-plugin-functional)
[![Coverage Status](https://codecov.io/gh/jonaskello/eslint-plugin-functional/branch/master/graph/badge.svg)](https://codecov.io/gh/jonaskello/eslint-plugin-functional)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat)](https://github.com/prettier/prettier)
[![MIT license](https://img.shields.io/github/license/jonaskello/eslint-plugin-functional.svg?style=flat)](https://opensource.org/licenses/MIT)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/eslint-functional)
[ESLint](https://eslint.org/) rules to disable mutation and promote functional programming in JavaScript and TypeScript.
An [ESLint](http://eslint.org) plugin to disable mutation and promote functional programming in JavaScript and TypeScript.
## Introduction
</div>
> :wave: If you previously used the rules in [tslint-immutable](https://www.npmjs.com/package/tslint-immutable), this package is the eslint version of those rules. Please see the [migration guide](docs/user-guide/migrating-from-tslint.md) for how to migrate.
This package has a collection of eslint rules to promote functional programming style concepts. Note that you can use this package to enforce only some aspects of functional programming, for example only immutability. There are also options for the rules that allow you to gradually adopt a functional style. Most rules can be used both for JavaScript and TypeScript, however some rules, for example enforcing the `readonly` keyword, is of course only available for TypeScript.
## Features
We've identified the following areas that need to be linted in order to promote functional style in TypeScript/JavaScript:
- [No mutations](#no-mutations)

@@ -28,10 +30,4 @@ - [No object-orientation](#no-object-orientation)

In some applications it is important to not mutate any data, for example when using Redux to store state in a React application. Moreover immutable data structures have a lot of advantages in general so I want to use them everywhere in my applications.
One aim of this project is to leverage the type system in TypeScript to enforce immutability at compile-time while still using regular objects and arrays. Additionally, this project will also aim to support disabling mutability for vanilla JavaScript where possible.
I originally used [immutablejs](https://github.com/facebook/immutable-js/) for this purpose. It is a really nice library but I found it had some drawbacks. Specifically when debugging it was hard to see the structure, creating JSON was not straightforward, and passing parameters to other libraries required converting to regular mutable arrays and objects. The [seamless-immutable](https://github.com/rtfeldman/seamless-immutable) project seems to have the same conclusions and they use regular objects and arrays and check for immutability at run-time. This solves all the aformentioned drawbacks but introduces a new drawback of only being enforced at run-time. (Although you lose the structural sharing feature of immutablejs with this solution so you would have to consider if that is something you need).
Then TypeScript 2.0 came along and introduced [readonly](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#read-only-properties-and-index-signatures) options for properties, indexers and arrays. TypeScript 3.0 has continued to add support immutability enforcing syntax. This enables us to use regular objects and arrays and have the immutability enforced at compile time instead of run-time. Now the only drawback is that there is nothing enforcing the use of readonly in TypeScript.
This can be solved by using linting rules. So one aim of this project is to leverage the type system in TypeScript to enforce immutability at compile-time while still using regular objects and arrays. Additionally, this project will also aim to support disabling mutability for vanilla JavaScript where possible.
### No object-orientation

@@ -53,14 +49,27 @@

## Installing
## Installation
### JavaScript
```sh
# Install with npm
npm install eslint eslint-plugin-functional --save-dev
# Install with yarn
yarn add -D eslint eslint-plugin-functional
```
**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-functional` globally.
**Note:** If you installed ESLint globally (using the `-g` flag with npm or `global` with yarn) then you must also install `eslint-plugin-functional` globally.
To use this plugin with TypeScript, additionally install [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser).
### TypeScript
To use this plugin with TypeScript, a TypeScript parser for eslint is needed.
We recommend [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser).
```sh
# Install with npm
npm install eslint @typescript-eslint/parser eslint-plugin-functional --save-dev
# Install with yarn
yarn add -D eslint @typescript-eslint/parser eslint-plugin-functional
```

@@ -72,3 +81,3 @@

```json
```jsonc
{

@@ -84,8 +93,11 @@ "plugins": ["functional"],

[See below](#rulesets) for what they are and what rules are including in each.
Enable rulesets via the "extends" property of your `.eslintrc` configuration file.
You can enable one of these rulesets like so:
```json
```jsonc
{
"extends": ["plugin:functional/recommended"]
// ...
"extends": [
"plugin:functional/external-recommended",
"plugin:functional/recommended"
]
}

@@ -96,6 +108,6 @@ ```

`@typescript-eslint/parser` is needed to parse TypeScript code; add `@typescript-eslint/parser` to the "parser" filed in your `.eslintrc` configuration file.
Additionally, for this plugin to use type information, you will need to specify a path to your tsconfig.json file in the "project" property of "parserOptions".
Add `@typescript-eslint/parser` to the "parser" filed in your `.eslintrc` configuration file.
To use type information, you will need to specify a path to your `tsconfig.json` file in the "project" property of "parserOptions".
```json
```jsonc
{

@@ -105,6 +117,2 @@ "parser": "@typescript-eslint/parser",

"project": "./tsconfig.json"
},
"plugins": ["functional"],
"rules": {
"functional/rule-name": "error"
}

@@ -114,4 +122,29 @@ }

See [@typescript-eslint/parser's README.md](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#readme) for more information on the available "parserOptions".
See [@typescript-eslint/parser's README.md](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#readme) for more information on the available parser options.
### Example Config
```jsonc
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json"
},
"env": {
"es6": true
},
"plugins": [
"@typescript-eslint",
"functional"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:functional/external-recommended",
"plugin:functional/recommended"
]
}
```
**Note: Make sure to use `eslint --ext .js,.ts` since by [default](https://eslint.org/docs/user-guide/command-line-interface#--ext) `eslint` will only search for .js files.**

@@ -210,3 +243,3 @@

Each of these rules are enabled by default in the rulesets this plugin provides.
These rules are all included in the *external-recommended* rulesets.

@@ -237,25 +270,2 @@ ### [no-var](https://eslint.org/docs/rules/no-var)

## Minimal Recommended Config
```json
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "functional"],
"env": {
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:functional/external-recommended",
"plugin:functional/recommended"
],
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
}
}
```
## How to contribute

@@ -284,16 +294,1 @@

This project started off as a port of [tslint-immutable](https://github.com/jonaskello/tslint-immutable) which was originally inspired by [eslint-plugin-immutable](https://github.com/jhusain/eslint-plugin-immutable).
[version-image]: https://img.shields.io/npm/v/eslint-plugin-functional.svg?style=flat
[version-url]: https://www.npmjs.com/package/eslint-plugin-functional
[travis-image]: https://travis-ci.com/jonaskello/eslint-plugin-functional.svg?branch=master&style=flat
[travis-url]: https://travis-ci.com/jonaskello/eslint-plugin-functional
[codecov-image]: https://codecov.io/gh/jonaskello/eslint-plugin-functional/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/jonaskello/eslint-plugin-functional
[license-image]: https://img.shields.io/github/license/jonaskello/eslint-plugin-functional.svg?style=flat
[license-url]: https://opensource.org/licenses/MIT
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat
[prettier-url]: https://github.com/prettier/prettier
[type-info-badge]: https://img.shields.io/badge/type_info-required-d51313.svg?style=flat
[type-info-url]: https://palantir.github.io/tslint/usage/type-checking
[spectrum-image]: https://withspectrum.github.io/badge/badge.svg
[spectrum-url]: https://spectrum.chat/eslint-functional

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc