eslint-plugin-snarkyjs
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -12,3 +12,5 @@ "use strict"; | ||
'no-constructor-in-smart-contract', | ||
'always-export-in-smart-contract', | ||
]; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const snarkyJSRuleModules = {}; | ||
@@ -23,5 +25,7 @@ exports.rules = snarkyJSRuleModules; | ||
const { meta: { docs: { recommended }, }, } = snarkyJSRuleModules[rule]; | ||
configs.recommended.rules[`snarkyjs/${rule}`] = | ||
recommended === false ? 'off' : recommended; | ||
if (configs.recommended.rules) { | ||
configs.recommended.rules[`snarkyjs/${rule}`] = | ||
recommended === false ? 'off' : recommended; | ||
} | ||
}); | ||
//# sourceMappingURL=index.js.map |
"use strict"; | ||
const typescript_estree_1 = require("@typescript-eslint/typescript-estree"); | ||
const types_1 = require("../types"); | ||
const ast_utils_1 = require("../utils/ast-utils"); | ||
const selectors_1 = require("../utils/selectors"); | ||
const MAX_CONTRACT_STATES = 8; | ||
const SnarkyJSPrimitiveNames = [ | ||
'Field', | ||
'Bool', | ||
'UInt32', | ||
'Uint64', | ||
'Scalar', | ||
'PrivateKey', | ||
'Group', | ||
'PublicKey', | ||
'Signature', | ||
]; | ||
const isSnarkyJSPrimitive = (p) => SnarkyJSPrimitiveNames.includes(p); | ||
const SnarkyJSPrimitiveSizeInfo = { | ||
Field: { size: 1 }, | ||
Bool: { size: 1 }, | ||
Scalar: { size: 1 }, | ||
UInt32: { size: 1 }, | ||
Uint64: { size: 1 }, | ||
PrivateKey: { size: 1 }, | ||
Group: { size: 2 }, | ||
PublicKey: { size: 2 }, | ||
Signature: { size: 2 }, | ||
}; | ||
// A map containing all Smart Contracts that we can immediately derive state count from | ||
const knownContractState = new Map(); | ||
// A map containing all Smart Contracts that need their state to be derived from other Smart Contracts | ||
const unknownContractState = new Map(); | ||
const rule = { | ||
meta: { | ||
messages: { | ||
noGreaterStorageLimitInCircuit: `A circuit can only have ${MAX_CONTRACT_STATES} allowed storage fields.`, | ||
noGreaterStorageLimitInCircuit: `A Smart Contract can only have ${types_1.MAX_CONTRACT_STATES} allowed storage fields.`, | ||
}, | ||
@@ -37,3 +17,3 @@ schema: [], | ||
docs: { | ||
description: `A circuit can only have ${MAX_CONTRACT_STATES} allowed storage fields.`, | ||
description: `A Smart Contract can only have ${types_1.MAX_CONTRACT_STATES} allowed storage fields.`, | ||
recommended: 'error', | ||
@@ -44,95 +24,56 @@ url: '', | ||
create(context) { | ||
// Store SmartContact class name as the key and a list of `CircuitDecoratorInfo` that represents each storage state | ||
let smartContractMap = new Map(); | ||
// Store CircuitValue class name as the key and a list of `CircuitDecoratorInfo` that represents each storage state | ||
let circuitValueMap = new Map(); | ||
return { | ||
'Program:exit': function (_) { | ||
smartContractMap.forEach((circuitDecorators, _) => { | ||
let stateCount = 0; | ||
circuitDecorators.forEach((circuitDecorator) => { | ||
var _a; | ||
// Check if the state decorator is held within a CircuitValue class | ||
// otherwise check if it is a SnarkyJS primitive to get it's state size | ||
if (circuitValueMap.has(circuitDecorator.decoratorType)) { | ||
const circuitValueStates = (_a = circuitValueMap.get(circuitDecorator.decoratorType)) !== null && _a !== void 0 ? _a : []; | ||
circuitValueStates.forEach((circuitValueState) => { | ||
if (circuitValueState.typeSize) | ||
stateCount += circuitValueState.typeSize; | ||
}); | ||
'Program:exit': function () { | ||
let derivedUnknownState = true; | ||
// Continue to derive unknown states if we can succesfully derive a previous unknown state. | ||
while (derivedUnknownState) { | ||
derivedUnknownState = false; // Assume we can't derive an unknown state to break out of the while | ||
unknownContractState.forEach((stateInfo, className) => { | ||
stateInfo = stateInfo.map((state) => { | ||
var _a; | ||
if (state.kind === 'UnknownStateInfo') { | ||
const { dependsOn, type, node } = state; | ||
const contractState = (_a = knownContractState.get(dependsOn)) !== null && _a !== void 0 ? _a : []; | ||
const contractStateCount = calculateContractState(contractState); | ||
// Succesfully derived an unknown state, continue looping in the parent while loop | ||
if (contractStateCount > 0) { | ||
derivedUnknownState = true; | ||
return { | ||
kind: 'KnownStateInfo', | ||
size: contractStateCount, | ||
type, | ||
node, | ||
}; | ||
} | ||
} | ||
return state; | ||
}); | ||
const unknownRemaining = stateInfo.filter((state) => { | ||
return state.kind === 'UnknownStateInfo'; | ||
}).length; | ||
if (unknownRemaining === 0) { | ||
unknownContractState.delete(className); | ||
knownContractState.set(className, stateInfo); | ||
} | ||
else if (isSnarkyJSPrimitive(circuitDecorator.decoratorType)) { | ||
const stateSize = SnarkyJSPrimitiveSizeInfo[circuitDecorator.decoratorType].size; | ||
stateCount += stateSize; | ||
} | ||
if (stateCount > MAX_CONTRACT_STATES) { | ||
}); | ||
} | ||
for (const [, contractState] of knownContractState) { | ||
const stateDecoratorInfo = getStateDecoratorInfo(contractState); | ||
const contractStateCount = calculateContractState(contractState); | ||
if (stateDecoratorInfo && !stateDecoratorInfo.reported) { | ||
if (contractStateCount > types_1.MAX_CONTRACT_STATES) { | ||
context.report({ | ||
messageId: `noGreaterStorageLimitInCircuit`, | ||
loc: circuitDecorator.node.loc, | ||
loc: stateDecoratorInfo.node.loc, | ||
}); | ||
stateDecoratorInfo.reported = true; // Set reported to true to avoid reporting same error in multiple files | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
}, | ||
[selectors_1.SMART_CONTRACT_DEFINITION]: function (smartContractNode) { | ||
var _a, _b; | ||
let circuitStates = []; | ||
(0, typescript_estree_1.simpleTraverse)(smartContractNode, { | ||
enter: (node) => { | ||
var _a; | ||
const decorators = (0, ast_utils_1.getDecorators)(node); | ||
const stateDecorator = (0, ast_utils_1.getSpecifiedDecorator)(decorators, 'state'); | ||
if (stateDecorator) { | ||
const decoratorType = (_a = (0, ast_utils_1.getFirstDecoratorValue)(stateDecorator)) !== null && _a !== void 0 ? _a : (0, ast_utils_1.getPropertyType)(node); | ||
if (decoratorType) { | ||
circuitStates.push({ | ||
decoratorType, | ||
decoratorKind: 'state', | ||
node, | ||
}); | ||
} | ||
} | ||
}, | ||
}); | ||
if ((_a = smartContractNode.id) === null || _a === void 0 ? void 0 : _a.name) | ||
smartContractMap.set((_b = smartContractNode.id) === null || _b === void 0 ? void 0 : _b.name, circuitStates); | ||
findKnownAndUnknownStates(smartContractNode); | ||
}, | ||
[selectors_1.CIRCUIT_VALUE_DEFINITION]: function (circuitValueNode) { | ||
var _a, _b; | ||
let circuitStates = []; | ||
(0, typescript_estree_1.simpleTraverse)(circuitValueNode, { | ||
enter: (node) => { | ||
var _a, _b; | ||
const decorators = (0, ast_utils_1.getDecorators)(node); | ||
const propDecorator = (0, ast_utils_1.getSpecifiedDecorator)(decorators, 'prop'); | ||
const arrayPropDecorator = (0, ast_utils_1.getSpecifiedDecorator)(decorators, 'arrayProp'); | ||
if (propDecorator) { | ||
const decoratorType = (_a = (0, ast_utils_1.getFirstDecoratorValue)(propDecorator)) !== null && _a !== void 0 ? _a : (0, ast_utils_1.getPropertyType)(node); | ||
if (decoratorType) { | ||
const typeSize = SnarkyJSPrimitiveSizeInfo[decoratorType].size; | ||
circuitStates.push({ | ||
decoratorType, | ||
decoratorKind: 'prop', | ||
typeSize, | ||
node: circuitValueNode, | ||
}); | ||
} | ||
} | ||
else if (arrayPropDecorator) { | ||
const decoratorType = (_b = (0, ast_utils_1.getFirstDecoratorValue)(arrayPropDecorator)) !== null && _b !== void 0 ? _b : (0, ast_utils_1.getPropertyType)(node); | ||
if (decoratorType) { | ||
const size = SnarkyJSPrimitiveSizeInfo[decoratorType].size; | ||
circuitStates.push({ | ||
decoratorType, | ||
decoratorKind: 'arrayProp', | ||
typeSize: (0, ast_utils_1.getSecondDecoratorValue)(arrayPropDecorator) * | ||
size, | ||
node: circuitValueNode, | ||
}); | ||
} | ||
} | ||
}, | ||
}); | ||
if ((_a = circuitValueNode.id) === null || _a === void 0 ? void 0 : _a.name) | ||
circuitValueMap.set((_b = circuitValueNode.id) === null || _b === void 0 ? void 0 : _b.name, circuitStates); | ||
findKnownAndUnknownStates(circuitValueNode); | ||
}, | ||
@@ -142,3 +83,100 @@ }; | ||
}; | ||
function calculateContractState(contractState) { | ||
return contractState.reduce((acc, state) => { | ||
if (state.type.kind === 'arrayProp') { | ||
return acc + state.size * state.type.arrayPropLength; | ||
} | ||
else { | ||
return acc + state.size; | ||
} | ||
}, 0); | ||
} | ||
function getStateDecoratorInfo(stateInfo) { | ||
return stateInfo.find((state) => { | ||
return state.type.kind === 'state'; | ||
}); | ||
} | ||
function findKnownAndUnknownStates(smartContractNode) { | ||
var _a, _b, _c, _d; | ||
const stateInfo = []; | ||
const classBody = (_a = (0, ast_utils_1.getClassBodyStatements)(smartContractNode)) !== null && _a !== void 0 ? _a : []; | ||
let isAllPrimitiveState = true; | ||
for (const classStatement of classBody) { | ||
// Get the kind of decorator (`prop`, `state` or `arrayProp`) as well as the TS decorator node | ||
const decorator = (0, ast_utils_1.getValidDecorator)(classStatement); | ||
if (!decorator) { | ||
continue; | ||
} | ||
// Get the user specified type from the decorator node (e.g `Field`, `Group` or a CircuitValue) | ||
const snarkyDecoratorType = (_b = (0, ast_utils_1.getFirstDecoratorValue)(decorator.decorator)) !== null && _b !== void 0 ? _b : (0, ast_utils_1.getPropertyType)(classStatement); | ||
if (!snarkyDecoratorType) { | ||
continue; | ||
} | ||
// If the decorator type is a SnarkyJS primitive, get it's value | ||
const primitive = (0, types_1.getSnarkyJSPrimitive)(snarkyDecoratorType); | ||
if (!primitive) { | ||
isAllPrimitiveState = false; | ||
} | ||
if (decorator.kind === 'prop' || decorator.kind === 'state') { | ||
if (primitive) { | ||
const { size } = types_1.SnarkyJSPrimitiveSizeInfo[primitive]; | ||
stateInfo.push({ | ||
kind: 'KnownStateInfo', | ||
type: { kind: decorator.kind }, | ||
node: smartContractNode, | ||
reported: false, | ||
size, | ||
}); | ||
} | ||
else { | ||
stateInfo.push({ | ||
kind: 'UnknownStateInfo', | ||
type: { | ||
kind: decorator.kind, | ||
}, | ||
node: smartContractNode, | ||
dependsOn: snarkyDecoratorType, | ||
}); | ||
} | ||
} | ||
else if (decorator.kind === 'arrayProp') { | ||
const arrayPropLength = (_c = (0, ast_utils_1.getSecondDecoratorValue)(decorator.decorator)) !== null && _c !== void 0 ? _c : 0; | ||
if (primitive) { | ||
const { size } = types_1.SnarkyJSPrimitiveSizeInfo[primitive]; | ||
stateInfo.push({ | ||
kind: 'KnownStateInfo', | ||
type: { | ||
kind: decorator.kind, | ||
arrayPropLength, | ||
}, | ||
node: smartContractNode, | ||
reported: false, | ||
size, | ||
}); | ||
} | ||
else { | ||
stateInfo.push({ | ||
kind: 'UnknownStateInfo', | ||
type: { | ||
kind: decorator.kind, | ||
arrayPropLength, | ||
}, | ||
node: smartContractNode, | ||
dependsOn: snarkyDecoratorType, | ||
}); | ||
} | ||
} | ||
} | ||
// If all decorators are a SnarkyJS primitive, we can calculate the Smart Contract state count and | ||
// insert it into the `knownContractStateMap`. If the user specifies a CircuitValue, we store the state info | ||
// in `unknownContractState` to derive it's state count later. | ||
const className = (_d = (0, ast_utils_1.getClassName)(smartContractNode)) !== null && _d !== void 0 ? _d : ''; | ||
if (isAllPrimitiveState) { | ||
knownContractState.set(className, stateInfo); | ||
} | ||
else { | ||
unknownContractState.set(className, stateInfo); | ||
} | ||
} | ||
module.exports = rule; | ||
//# sourceMappingURL=no-greater-storage-limit-in-circuit.js.map |
@@ -19,7 +19,7 @@ "use strict"; | ||
create(context) { | ||
let snarkyCircuitMap = new Map(); | ||
let ifSet = new Set(); | ||
let callees = {}; | ||
let callStack = []; | ||
let currentFunction = () => callStack[callStack.length - 1]; | ||
const snarkyCircuitMap = new Map(); | ||
const ifSet = new Set(); | ||
const callees = {}; | ||
const callStack = []; | ||
const currentFunction = () => callStack[callStack.length - 1]; | ||
function callsIf(functionName) { | ||
@@ -30,4 +30,4 @@ var _a; | ||
return { | ||
'Program:exit': function (_node) { | ||
for (let circuitNode of snarkyCircuitMap.values()) { | ||
'Program:exit': function () { | ||
for (const circuitNode of snarkyCircuitMap.values()) { | ||
(0, typescript_estree_1.simpleTraverse)(circuitNode, { | ||
@@ -62,3 +62,3 @@ enter: (node) => { | ||
IfStatement() { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName) | ||
@@ -68,5 +68,5 @@ ifSet.add(functionName); | ||
CallExpression(node) { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName && (0, node_utils_1.isIdentifier)(node.callee)) { | ||
let currentCallees = callees[functionName] || (callees[functionName] = []); | ||
const currentCallees = callees[functionName] || (callees[functionName] = []); | ||
currentCallees.push(node.callee.name); | ||
@@ -73,0 +73,0 @@ } |
@@ -21,7 +21,7 @@ "use strict"; | ||
const bannedFunctions = new Set(['stringify', 'parse']); | ||
let snarkyCircuitMap = new Map(); | ||
let jsonSet = new Set(); | ||
let callees = {}; | ||
let callStack = []; | ||
let currentFunction = () => callStack[callStack.length - 1]; | ||
const snarkyCircuitMap = new Map(); | ||
const jsonSet = new Set(); | ||
const callees = {}; | ||
const callStack = []; | ||
const currentFunction = () => callStack[callStack.length - 1]; | ||
function callsJSON(functionName) { | ||
@@ -32,4 +32,4 @@ var _a; | ||
return { | ||
'Program:exit': function (_) { | ||
for (let circuitNode of snarkyCircuitMap.values()) { | ||
'Program:exit': function () { | ||
for (const circuitNode of snarkyCircuitMap.values()) { | ||
(0, typescript_estree_1.simpleTraverse)(circuitNode, { | ||
@@ -68,3 +68,3 @@ enter: (node) => { | ||
CallExpression(node) { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName && | ||
@@ -75,3 +75,3 @@ (0, ast_utils_1.isBannedCallExpression)(node, bannedImports, bannedFunctions)) { | ||
if (functionName && (0, node_utils_1.isIdentifier)(node.callee)) { | ||
let currentCallees = callees[functionName] || (callees[functionName] = []); | ||
const currentCallees = callees[functionName] || (callees[functionName] = []); | ||
currentCallees.push(node.callee.name); | ||
@@ -78,0 +78,0 @@ } |
@@ -25,7 +25,7 @@ "use strict"; | ||
]); | ||
let snarkyCircuitMap = new Map(); | ||
let randomSet = new Set(); | ||
let callees = {}; | ||
let callStack = []; | ||
let currentFunction = () => callStack[callStack.length - 1]; | ||
const snarkyCircuitMap = new Map(); | ||
const randomSet = new Set(); | ||
const callees = {}; | ||
const callStack = []; | ||
const currentFunction = () => callStack[callStack.length - 1]; | ||
function callsRandom(functionName) { | ||
@@ -37,4 +37,4 @@ var _a; | ||
return { | ||
'Program:exit': function (_) { | ||
for (let circuitNode of snarkyCircuitMap.values()) { | ||
'Program:exit': function () { | ||
for (const circuitNode of snarkyCircuitMap.values()) { | ||
(0, typescript_estree_1.simpleTraverse)(circuitNode, { | ||
@@ -73,3 +73,3 @@ enter: (node) => { | ||
CallExpression(node) { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName && | ||
@@ -80,3 +80,3 @@ (0, ast_utils_1.isBannedCallExpression)(node, bannedImports, bannedFunctions)) { | ||
if (functionName && (0, node_utils_1.isIdentifier)(node.callee)) { | ||
let currentCallees = callees[functionName] || (callees[functionName] = []); | ||
const currentCallees = callees[functionName] || (callees[functionName] = []); | ||
currentCallees.push(node.callee.name); | ||
@@ -83,0 +83,0 @@ } |
@@ -19,7 +19,7 @@ "use strict"; | ||
create(context) { | ||
let snarkyCircuitMap = new Map(); | ||
let ternarySet = new Set(); | ||
let callees = {}; | ||
let callStack = []; | ||
let currentFunction = () => callStack[callStack.length - 1]; | ||
const snarkyCircuitMap = new Map(); | ||
const ternarySet = new Set(); | ||
const callees = {}; | ||
const callStack = []; | ||
const currentFunction = () => callStack[callStack.length - 1]; | ||
function callsTernary(functionName) { | ||
@@ -31,4 +31,4 @@ var _a; | ||
return { | ||
'Program:exit': function (_node) { | ||
for (let circuitNode of snarkyCircuitMap.values()) { | ||
'Program:exit': function () { | ||
for (const circuitNode of snarkyCircuitMap.values()) { | ||
(0, typescript_estree_1.simpleTraverse)(circuitNode, { | ||
@@ -66,3 +66,3 @@ enter: (node) => { | ||
ConditionalExpression() { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName) | ||
@@ -72,5 +72,5 @@ ternarySet.add(functionName); | ||
CallExpression(node) { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName && (0, node_utils_1.isIdentifier)(node.callee)) { | ||
let currentCallees = callees[functionName] || (callees[functionName] = []); | ||
const currentCallees = callees[functionName] || (callees[functionName] = []); | ||
currentCallees.push(node.callee.name); | ||
@@ -77,0 +77,0 @@ } |
@@ -19,7 +19,7 @@ "use strict"; | ||
create(context) { | ||
let snarkyCircuitMap = new Map(); | ||
let throwSet = new Set(); | ||
let callees = {}; | ||
let callStack = []; | ||
let currentFunction = () => callStack[callStack.length - 1]; | ||
const snarkyCircuitMap = new Map(); | ||
const throwSet = new Set(); | ||
const callees = {}; | ||
const callStack = []; | ||
const currentFunction = () => callStack[callStack.length - 1]; | ||
function callsThrow(functionName) { | ||
@@ -30,4 +30,4 @@ var _a; | ||
return { | ||
'Program:exit': function (_) { | ||
for (let circuitNode of snarkyCircuitMap.values()) { | ||
'Program:exit': function () { | ||
for (const circuitNode of snarkyCircuitMap.values()) { | ||
(0, typescript_estree_1.simpleTraverse)(circuitNode, { | ||
@@ -62,3 +62,3 @@ enter: (node) => { | ||
ThrowStatement() { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName) | ||
@@ -68,5 +68,5 @@ throwSet.add(functionName); | ||
CallExpression(node) { | ||
let functionName = currentFunction(); | ||
const functionName = currentFunction(); | ||
if (functionName && (0, node_utils_1.isIdentifier)(node.callee)) { | ||
let currentCallees = callees[functionName] || (callees[functionName] = []); | ||
const currentCallees = callees[functionName] || (callees[functionName] = []); | ||
currentCallees.push(node.callee.name); | ||
@@ -73,0 +73,0 @@ } |
import type { TSESTree } from '@typescript-eslint/experimental-utils'; | ||
/** | ||
* Returns all decorators of a node if they exist, otherwise returns an empty list. | ||
* @param node Node to get decorators from | ||
* @returns A list of decorators or an empty list | ||
* Get a list of all decorators on a node. | ||
* @param node Node to get decorators from | ||
* @returns A list of decorators. Returns an empty list if none are found. | ||
*/ | ||
export declare function getDecorators(node: TSESTree.Node): TSESTree.Decorator[]; | ||
/** | ||
* For a given list of decorators, find a decorator by name. Returns `undefined` if not found. | ||
* @param decorators A list of decorators to search | ||
* @param decoratorToFind The name of the decorator to find | ||
* @returns The specified decorator or undefined | ||
* Return an object that contains what kind of SnarkyJS decorator was used | ||
* (e.g `@state` `@prop`, or `@arrayProp`) | ||
* and the decorator node. | ||
* @param node The node to get the decorators from | ||
* @returns An object indicating what decorator was used and the node | ||
*/ | ||
export declare function getSpecifiedDecorator(decorators: TSESTree.Decorator[], decoratorToFind: string): TSESTree.Decorator | undefined; | ||
export declare function getValidDecorator(node: TSESTree.Node): { | ||
kind: "prop" | "arrayProp" | "state"; | ||
decorator: TSESTree.Decorator; | ||
} | undefined; | ||
/** | ||
@@ -50,2 +54,4 @@ * Gets the first value of a decorator expression if it has one, otherwiser returns `undefined`. | ||
*/ | ||
export declare let isBannedCallExpression: (node: TSESTree.CallExpression, bannedImports: Set<string>, bannedFunctions: Set<string>) => boolean; | ||
export declare function isBannedCallExpression(node: TSESTree.CallExpression, bannedImports: Set<string>, bannedFunctions: Set<string>): boolean; | ||
export declare function getClassBodyStatements(node: TSESTree.Node): TSESTree.ClassElement[] | undefined; | ||
export declare function getClassName(node: TSESTree.Node): string | undefined; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isBannedCallExpression = exports.getFunctionName = exports.getPropertyType = exports.getSecondDecoratorValue = exports.getFirstDecoratorValue = exports.getSpecifiedDecorator = exports.getDecorators = void 0; | ||
exports.getClassName = exports.getClassBodyStatements = exports.isBannedCallExpression = exports.getFunctionName = exports.getPropertyType = exports.getSecondDecoratorValue = exports.getFirstDecoratorValue = exports.getValidDecorator = exports.getDecorators = void 0; | ||
const types_1 = require("../types"); | ||
const node_utils_1 = require("./node-utils"); | ||
/** | ||
* Returns all decorators of a node if they exist, otherwise returns an empty list. | ||
* @param node Node to get decorators from | ||
* @returns A list of decorators or an empty list | ||
* Get a list of all decorators on a node. | ||
* @param node Node to get decorators from | ||
* @returns A list of decorators. Returns an empty list if none are found. | ||
*/ | ||
@@ -19,23 +20,36 @@ function getDecorators(node) { | ||
/** | ||
* For a given list of decorators, find a decorator by name. Returns `undefined` if not found. | ||
* @param decorators A list of decorators to search | ||
* @param decoratorToFind The name of the decorator to find | ||
* @returns The specified decorator or undefined | ||
* Return an object that contains what kind of SnarkyJS decorator was used | ||
* (e.g `@state` `@prop`, or `@arrayProp`) | ||
* and the decorator node. | ||
* @param node The node to get the decorators from | ||
* @returns An object indicating what decorator was used and the node | ||
*/ | ||
function getSpecifiedDecorator(decorators, decoratorToFind) { | ||
return decorators.find((decorator) => { | ||
// Check if we hit a decorator with no call expression (e.g. `@prop`) | ||
function getValidDecorator(node) { | ||
const decorators = getDecorators(node); | ||
for (const decorator of decorators) { | ||
if ((0, node_utils_1.isIdentifier)(decorator.expression)) { | ||
return decorator.expression.name === decoratorToFind; | ||
const decoratorName = decorator.expression.name; | ||
const validDecorator = (0, types_1.findValidContractType)(decoratorName); | ||
if (validDecorator) { | ||
return { | ||
kind: validDecorator, | ||
decorator, | ||
}; | ||
} | ||
} | ||
// Check if we hit a decorator with a call expression (e.g. `@state(T)`) | ||
else if ((0, node_utils_1.isCallExpression)(decorator.expression) && | ||
(0, node_utils_1.isIdentifier)(decorator.expression.callee)) { | ||
return decorator.expression.callee.name === decoratorToFind; | ||
const decoratorName = decorator.expression.callee.name; | ||
const validDecorator = (0, types_1.findValidContractType)(decoratorName); | ||
if (validDecorator) { | ||
return { | ||
kind: validDecorator, | ||
decorator, | ||
}; | ||
} | ||
} | ||
else | ||
return false; | ||
}); | ||
} | ||
return undefined; | ||
} | ||
exports.getSpecifiedDecorator = getSpecifiedDecorator; | ||
exports.getValidDecorator = getValidDecorator; | ||
/** | ||
@@ -128,3 +142,3 @@ * Gets the first value of a decorator expression if it has one, otherwiser returns `undefined`. | ||
*/ | ||
let isBannedCallExpression = (node, bannedImports, bannedFunctions) => { | ||
function isBannedCallExpression(node, bannedImports, bannedFunctions) { | ||
if ((0, node_utils_1.isMemberExpression)(node.callee)) { | ||
@@ -143,4 +157,19 @@ if ((0, node_utils_1.isIdentifier)(node.callee.property) && | ||
return false; | ||
}; | ||
} | ||
exports.isBannedCallExpression = isBannedCallExpression; | ||
function getClassBodyStatements(node) { | ||
if ((0, node_utils_1.isClassDeclaration)(node)) { | ||
return node.body.body; | ||
} | ||
return undefined; | ||
} | ||
exports.getClassBodyStatements = getClassBodyStatements; | ||
function getClassName(node) { | ||
var _a; | ||
if ((0, node_utils_1.isClassDeclaration)(node)) { | ||
return (_a = node.id) === null || _a === void 0 ? void 0 : _a.name; | ||
} | ||
return undefined; | ||
} | ||
exports.getClassName = getClassName; | ||
//# sourceMappingURL=ast-utils.js.map |
@@ -19,1 +19,2 @@ import type { TSESTree } from '@typescript-eslint/experimental-utils'; | ||
export declare function isTSArrayType(node: TSESTree.Node): node is TSESTree.TSArrayType; | ||
export declare function hasExportNamedDeclaration(node: TSESTree.Node): boolean; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isTSArrayType = exports.isTSTypeReference = exports.isProgramStatement = exports.isPropertyDefinition = exports.isClassDeclaration = exports.isThrowStatement = exports.isIfStatement = exports.isConditionalExpression = exports.isMemberExpression = exports.isCallExpression = exports.isVariableDeclarator = exports.isArrowFunctionExpression = exports.isMethodDefinition = exports.isFunctionExpression = exports.isFunctionDeclaration = exports.isLiteral = exports.isIdentifier = void 0; | ||
exports.hasExportNamedDeclaration = exports.isTSArrayType = exports.isTSTypeReference = exports.isProgramStatement = exports.isPropertyDefinition = exports.isClassDeclaration = exports.isThrowStatement = exports.isIfStatement = exports.isConditionalExpression = exports.isMemberExpression = exports.isCallExpression = exports.isVariableDeclarator = exports.isArrowFunctionExpression = exports.isMethodDefinition = exports.isFunctionExpression = exports.isFunctionDeclaration = exports.isLiteral = exports.isIdentifier = void 0; | ||
function isIdentifier(node) { | ||
@@ -72,2 +72,6 @@ return node !== undefined && node.type === 'Identifier'; | ||
exports.isTSArrayType = isTSArrayType; | ||
function hasExportNamedDeclaration(node) { | ||
return node !== undefined && node.type === 'ExportNamedDeclaration'; | ||
} | ||
exports.hasExportNamedDeclaration = hasExportNamedDeclaration; | ||
//# sourceMappingURL=node-utils.js.map |
@@ -8,3 +8,3 @@ "use strict"; | ||
const no_greater_storage_limit_in_circuit_1 = __importDefault(require("../../src/rules/no-greater-storage-limit-in-circuit")); | ||
const message = 'noGreaterStorageLimitInCircuit'; | ||
const messageId = 'noGreaterStorageLimitInCircuit'; | ||
rule_tester_1.ruleTester.run('no-greater-storage-limit-in-circuit', no_greater_storage_limit_in_circuit_1.default, { | ||
@@ -15,3 +15,3 @@ valid: [ | ||
class A extends SmartContract { | ||
@state(Field) state1: State<Field>; | ||
@state(Field) state1 = State<Field>(); | ||
}`, | ||
@@ -22,10 +22,10 @@ }, | ||
class A extends SmartContract { | ||
@state(Field) state1: State<Field>; | ||
@state(Field) state2: State<Field>; | ||
@state(Field) state3: State<Field>; | ||
@state(Field) state4: State<Field>; | ||
@state(Field) state5: State<Field>; | ||
@state(Field) state6: State<Field>; | ||
@state(Field) state7: State<Field>; | ||
@state(Field) state8: State<Field>; | ||
@state(Field) state1 = State<Field>(); | ||
@state(Field) state2 = State<Field>(); | ||
@state(Field) state3 = State<Field>(); | ||
@state(Field) state4 = State<Field>(); | ||
@state(Field) state5 = State<Field>(); | ||
@state(Field) state6 = State<Field>(); | ||
@state(Field) state7 = State<Field>(); | ||
@state(Field) state8 = State<Field>(); | ||
}`, | ||
@@ -39,3 +39,3 @@ }, | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
@@ -56,3 +56,3 @@ }, | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
@@ -67,4 +67,4 @@ }, | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(Field) value1: Field; | ||
@state(A) state1 = State<A>(); | ||
@state(Field) value1 = State<Field>(); | ||
}`, | ||
@@ -75,6 +75,16 @@ }, | ||
class A extends CircuitValue { | ||
@arrayProp(PublicKey, 4) arrayProp1: PublicKey[]; | ||
@prop prop1: Field; | ||
@arrayProp(Field, 8) prop2: Field[]; | ||
} | ||
class B extends CircuitValue { | ||
@prop a: A; | ||
}`, | ||
}, | ||
{ | ||
code: ` | ||
class A extends CircuitValue { | ||
@arrayProp(PublicKey, 4) arrayProp1 = State<PublicKey[]>(); | ||
} | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
@@ -88,6 +98,18 @@ }, | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(Field) state1: Field; | ||
@state(A) state1 = State<A>(); | ||
@state(Field) state1 = Field(); | ||
}`, | ||
}, | ||
{ | ||
code: ` | ||
class C extends CircuitValue { | ||
@prop prop1: Field; | ||
} | ||
class B extends CircuitValue { | ||
@arrayProp(C, 8) prop1: C[]; | ||
} | ||
class A extends SmartContract { | ||
@state(B) state1 = State<B>(); | ||
}`, | ||
}, | ||
], | ||
@@ -97,17 +119,75 @@ invalid: [ | ||
code: ` | ||
class C extends CircuitValue { | ||
@prop prop1: Field; | ||
@prop prop2: Field; | ||
} | ||
class B extends CircuitValue { | ||
@arrayProp(C, 5) values: C[]; | ||
} | ||
class A extends SmartContract { | ||
@state(Field) state1: State<Field>; | ||
@state(Field) state2: State<Field>; | ||
@state(Field) state3: State<Field>; | ||
@state(Field) state4: State<Field>; | ||
@state(Field) state5: State<Field>; | ||
@state(Field) state6: State<Field>; | ||
@state(Field) state7: State<Field>; | ||
@state(Field) state8: State<Field>; | ||
@state(Field) state9: State<Field>; | ||
@state(B) state = State<B>(); | ||
}`, | ||
errors: [{ messageId: message }], | ||
errors: [{ messageId }], | ||
}, | ||
{ | ||
code: ` | ||
class C extends CircuitValue { | ||
@prop prop1: Field; | ||
@prop prop2: Field; | ||
} | ||
class B extends CircuitValue { | ||
@arrayProp(C, 4) values: C[]; | ||
@prop prop2: Field; | ||
} | ||
class A extends SmartContract{ | ||
@state(B) state = State<B>(); | ||
}`, | ||
errors: [{ messageId }], | ||
}, | ||
{ | ||
code: ` | ||
class E extends CircuitValue { | ||
@prop prop1: Field; | ||
} | ||
class D extends CircuitValue { | ||
@arrayProp(D, 1) values: D[]; | ||
@prop prop2: Field; | ||
} | ||
class C extends CircuitValue { | ||
@arrayProp(C, 1) values: C[]; | ||
@prop prop2: Field; | ||
} | ||
class B extends CircuitValue { | ||
@arrayProp(B, 3) values: B[]; | ||
@prop prop2: Field; | ||
} | ||
class A extends SmartContract{ | ||
@state(B) state = State<B>(); | ||
}`, | ||
errors: [{ messageId }], | ||
}, | ||
{ | ||
code: ` | ||
class A extends SmartContract{ | ||
@state(B) state = State<B>(); | ||
} | ||
class B extends CircuitValue { | ||
@arrayProp(B, 3) values: B[]; | ||
@prop prop2: Field; | ||
} | ||
class C extends CircuitValue { | ||
@arrayProp(C, 1) values: C[]; | ||
@prop prop2: Field; | ||
} | ||
class E extends CircuitValue { | ||
@prop prop1: Field; | ||
} | ||
class D extends CircuitValue { | ||
@arrayProp(D, 1) values: D[]; | ||
@prop prop2: Field; | ||
}`, | ||
errors: [{ messageId }], | ||
}, | ||
{ | ||
code: ` | ||
class A extends CircuitValue { | ||
@@ -125,5 +205,5 @@ @prop prop1: Field; | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
errors: [{ messageId: message }], | ||
errors: [{ messageId }], | ||
}, | ||
@@ -136,17 +216,17 @@ { | ||
} | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
class B extends SmartContract { | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
errors: [{ messageId: message }], | ||
errors: [{ messageId }], | ||
}, | ||
{ | ||
code: ` | ||
class A extends CircuitValue { | ||
class B extends CircuitValue { | ||
@arrayProp(Field, 8) arrayProp1: Field[]; | ||
} | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(Field) value1: Field; | ||
class A extends SmartContract { | ||
@state(B) state1 = State<B>(); | ||
@state(Field) value1 = State<Field>(); | ||
}`, | ||
errors: [{ messageId: message }], | ||
errors: [{ messageId }], | ||
}, | ||
@@ -159,5 +239,5 @@ { | ||
class B extends SmartContract { | ||
@state(A) state1: State<A>; | ||
@state(A) state1 = State<A>(); | ||
}`, | ||
errors: [{ messageId: message }], | ||
errors: [{ messageId }], | ||
}, | ||
@@ -164,0 +244,0 @@ ], |
@@ -39,3 +39,3 @@ "use strict"; | ||
class Foo { | ||
@method async bar() { | ||
@method async bar() { | ||
if (true) {}; | ||
@@ -42,0 +42,0 @@ } |
{ | ||
"name": "eslint-plugin-snarkyjs", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "SnarkyJS rules for ESLint", | ||
@@ -10,2 +10,3 @@ "main": "build/src/index.js", | ||
"test": "jest", | ||
"lint": "eslint . --ext .ts", | ||
"typecheck": "tsc -p tsconfig.json", | ||
@@ -29,6 +30,7 @@ "format": "prettier --write ." | ||
"@types/node": "^16.11.13", | ||
"@typescript-eslint/eslint-plugin": "^5.21.0", | ||
"@typescript-eslint/experimental-utils": "^5.7.0", | ||
"@typescript-eslint/parser": "^5.21.0", | ||
"@typescript-eslint/typescript-estree": "^5.7.0", | ||
"@typescript-eslint/experimental-utils": "^5.7.0", | ||
"@typescript-eslint/parser": "^5.7.0", | ||
"eslint": "^8.4.1", | ||
"eslint": "^8.14.0", | ||
"jest": "^27.4.5", | ||
@@ -38,4 +40,3 @@ "prettier": "2.5.1", | ||
"typescript": "^4.5.4" | ||
}, | ||
"dependencies": {} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
118060
72
1946
0
12