Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

eslint-plugin-pipedream

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-pipedream - npm Package Compare versions

Comparing version 0.0.2 to 0.0.4

.eslintrc

155

index.js

@@ -19,2 +19,21 @@ function isModuleExports(node) {

// Objects can contain key names surrounded by quotes, or not
// propertyArray is the array of Property nodes in the component object
function astIncludesProperty(name, propertyArray) {
// value for Literals (quotes), name for Identifiers (no quotes)
const propertyNames = propertyArray.map((p) => p?.key?.value ?? p?.key?.name);
return propertyNames.includes(name) || propertyNames.includes(`"${name}"`);
}
// Returns the Property node matching the given name
// propertyArray is the array of Property nodes in the component object
function findPropertyWithName(name, propertyArray) {
return propertyArray.find((p) => {
return p?.key?.name === name ||
p?.key?.name === `"${name}"` ||
p?.key?.value === name ||
p?.key?.value === `"${name}"`;
});
}
// Does a component contain the right property? e.g. key, version

@@ -29,3 +48,3 @@ function componentContainsPropertyCheck(context, node, propertyName, message) {

if (!right.properties.map((p) => p?.key?.name).includes(propertyName)) {
if (!astIncludesProperty(propertyName, right.properties)) {
context.report({

@@ -38,2 +57,12 @@ node: node,

// Extract props or propDefintions from the object properties of the module
function getProps(moduleProperties) {
return moduleProperties.find((p) => {
return p?.key?.name === "props" ||
p?.key?.value === "props" ||
p?.key?.name === "propDefinitions" ||
p?.key?.value === "propDefinitions";
});
}
// Do component props contain the right properties? e.g. label, description

@@ -49,24 +78,19 @@ function componentPropsContainsPropertyCheck(context, node, propertyName) {

const { properties } = right;
const propertyNames = properties.map((p) => p?.key?.name);
if (propertyNames.includes("props") || propertyNames.includes("propDefinitions")) {
const props = properties.find((p) => p?.key?.name === "props" || p?.key?.name === "propDefinitions");
if (!isObjectWithProperties(props?.value)) return;
for (const prop of props.value?.properties) {
const {
key,
value: propDef,
} = prop;
if (!(astIncludesProperty("props", properties) || astIncludesProperty("propDefinitions", properties))) return;
const props = getProps(properties);
if (!isObjectWithProperties(props?.value)) return;
for (const prop of props.value?.properties) {
const {
key,
value: propDef,
} = prop;
// We don't want to lint app props or props that are defined in propDefinitions
if (!isObjectWithProperties(propDef)) continue;
if (!isObjectWithProperties(right)) continue;
const propProperties = propDef.properties.map((p) => p?.key?.name);
if (propProperties.includes("propDefinition")) continue;
if (!propProperties.includes(propertyName)) {
context.report({
node: prop,
message: `Component prop ${key?.name} must have a ${propertyName}. See https://pipedream.com/docs/components/guidelines/#props`,
});
}
// We don't want to lint app props or props that are defined in propDefinitions
if (!isObjectWithProperties(propDef)) continue;
if (astIncludesProperty("propDefinition", propDef.properties)) continue;
if (!astIncludesProperty(propertyName, propDef.properties)) {
context.report({
node: prop,
message: `Component prop ${key?.name ?? key?.value} must have a ${propertyName}. See https://pipedream.com/docs/components/guidelines/#props`,
});
}

@@ -85,26 +109,25 @@ }

const { properties } = right;
const propertyNames = properties.map((p) => p?.key?.name);
if (propertyNames.includes("props") || propertyNames.includes("propDefinitions")) {
const props = properties.find((p) => p?.key?.name === "props" || p?.key?.name === "propDefinitions");
if (!isObjectWithProperties(props?.value)) return;
for (const prop of props.value?.properties) {
const {
key,
value: propDef,
} = prop;
if (!(astIncludesProperty("props", properties) || astIncludesProperty("propDefinitions", properties))) return;
const props = getProps(properties);
if (!isObjectWithProperties(props?.value)) return;
for (const prop of props.value?.properties) {
const {
key,
value: propDef,
} = prop;
// We don't want to lint app props or props that are defined in propDefinitions
if (!isObjectWithProperties(propDef)) continue;
if (!isObjectWithProperties(right)) continue;
const propProperties = propDef.properties.map((p) => p?.key?.name);
if (propProperties.includes("propDefinition")) continue;
// We don't want to lint app props or props that are defined in propDefinitions
if (!isObjectWithProperties(propDef)) continue;
if (!isObjectWithProperties(right)) continue;
if (astIncludesProperty("propDefinition", right.properties)) continue;
const optionalValue = propDef.properties.find((p) => p?.key?.name === "optional")?.value?.value;
// value for Literals (quotes), name for Identifiers (no quotes)
const optionalProp = findPropertyWithName("optional", propDef.properties);
const optionalValue = optionalProp?.value?.value;
if (propProperties.includes("optional") && optionalValue && !propProperties.includes("default")) {
context.report({
node: prop,
message: `Component prop ${key?.name} is marked "optional", so it must have a "default" property. See https://pipedream.com/docs/components/guidelines/#default-values`,
});
}
if (astIncludesProperty("optional", propDef.properties) && optionalValue && !astIncludesProperty("default", propDef.properties)) {
context.report({
node: prop,
message: `Component prop ${key?.name ?? key?.value} is marked "optional", so it may need a "default" property. See https://pipedream.com/docs/components/guidelines/#default-values`,
});
}

@@ -114,2 +137,44 @@ }

// Checks to confirm the component is a source, and returns
// the node with the name specified by the user
function checkComponentIsSourceAndReturnTargetProp(node, propertyName) {
const {
left,
right,
} = node.expression;
if (!isModuleExports(left)) return;
if (!isObjectWithProperties(right)) return;
const typeProp = findPropertyWithName("type", right.properties);
// A separate rule checks the presence of the type property
if (!typeProp) return;
if (typeProp?.value?.value !== "source") return;
return findPropertyWithName(propertyName, right.properties);
}
function componentSourceNameCheck(context, node) {
const nameProp = checkComponentIsSourceAndReturnTargetProp(node, "name");
console.log("Name prop: ", nameProp);
if (!nameProp) return;
if (!nameProp?.value?.value.startsWith("New ")) {
context.report({
node: nameProp,
message: "Source names should start with \"New\". See https://pipedream.com/docs/components/guidelines/#source-name",
});
}
}
function componentSourceDescriptionCheck(context, node) {
const nameProp = checkComponentIsSourceAndReturnTargetProp(node, "description");
if (!nameProp) return;
if (!nameProp?.value?.value.startsWith("Emit new ")) {
context.report({
node: nameProp,
message: "Source descriptions should start with \"Emit new\". See https://pipedream.com/docs/components/guidelines/#source-description",
});
}
}
module.exports = {

@@ -193,3 +258,3 @@ rules: {

ExpressionStatement(node) {
componentContainsPropertyCheck(context, node, "type", "Components must export a type property (\"source\" or \"action\")");
componentSourceNameCheck(context, node);
},

@@ -203,3 +268,3 @@ };

ExpressionStatement(node) {
componentContainsPropertyCheck(context, node, "type", "Components must export a type property (\"source\" or \"action\")");
componentSourceDescriptionCheck(context, node);
},

@@ -206,0 +271,0 @@ };

{
"name": "eslint-plugin-pipedream",
"version": "0.0.2",
"version": "0.0.4",
"description": "ESLint plugin for Pipedream components: https://pipedream.com/docs/components/api/",

@@ -9,6 +9,19 @@ "main": "index.js",

},
"keywords": ["pipedream", "node.js", "integration", "api", "apis"],
"keywords": [
"pipedream",
"node.js",
"integration",
"api",
"apis"
],
"author": "Pipedream, Inc",
"license": "MIT",
"homepage": "https://github.com/PipedreamHQ/eslint-plugin-pipedream"
"homepage": "https://github.com/PipedreamHQ/eslint-plugin-pipedream",
"devDependencies": {
"eslint": "^7.32.0",
"eslint-plugin-jsonc": "^1.6.0",
"eslint-plugin-putout": "^9.2.1",
"jest": "^27.0.6",
"putout": "^19.0.2"
}
}
SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc