Clone repo
git clone https://github.com/js07/pd-convert-actions.git
Install dependencies
cd pd-convert-actions
npm install
Run CLI
$ node bin/cli.js ./test/data/actions.csv
? Output as separate javascript files or a single CSV file? JavaScript
? Path to components directory to write files to ./test/output
? Wrap the component with `defineComponent()`? No
? Generate labels for component props without labels? No
? Convert generated component to ESM? (Y/n)
USAGE
$ bin/cli.js FILE
ARGUMENTS
FILE csv file containing legacy action configs
OPTIONS
--outputType=js/csv Output actions as a csv file or js files
--out CSV output path
--componentsDirPath Path to components directory to write js files
--defineComponent Wrap the component with defineComponent()
--createLabel Generate labels for component props without labels
--[no-]toEsm Convert generated component to ESM (default: Yes)
--appPlaceholder App name slug to use if legacy code is authless
--addPlaceholderAppProp Add an appPlaceholder app prop if no apps are found
Install
npm install @js07/pd-convert-actions
Convert action
const convert = require("@js07/pd-convert-actions");
const actionConfig = {
code: "raw legacy action code;",
title: "Title/Name of the action",
description: "Description of the action",
namespace: "component_slug",
codeConfig: "{ params_schema: { ... } }",
versionMajor: "0",
versionMinor: "2",
hashId: "a_67imr8"
};
const {
code,
appSlug,
componentSlug,
} = await convert(actionConfig);
Config
- params_schema -> props
- DEFAULT_NAMESPACE -> component-name-slug
- VERSION_MAJOR.VERSION_MINOR ->
version: "<MAJOR>.<MINOR>.1"
- TITLE -> name
auths.<app_name_slug>
-> app_name_slug (defaults toapp_placeholder
)
Code
this.$checkpoint = "value
->let stepCheckpoint = await this.db.get("scp_${uid}"); try { stepCheckpoint = "value" } finally { await this.db.set("scp_${uid}", stepCheckpoint) }
(+data_store
prop)$checkpoint = "value
->let $checkpoint = await this.db.get("$checkpoint"); try { $checkpoint = "value" } finally { await this.db.set("$checkpint", $checkpoint) }
(+data_store
prop)$send
->$.send
$respond
->$.respond
$end
->$.flow.exit
this.name = "value"
->let name; try { name = "value" } finally { $.export("name", name) }
params
->this
auths.app_name
->this.app_name.$auth
(+app_name
prop)$attachments
->steps.trigger.context.attachments
event
->steps.trigger.event
require("@pipedreamhq/platform")
->require("@pipedream/platform")
.axios(this,
->.axios($,
Fixes
- Remove unused
const axios = require("axios")
- Replace byte character with
'
- Adds declarator for undeclared variables (eslint no-undef)
- Removes unused variables (eslint no-unused-var)
- Converts variables to camelCase (eslint camelcase)
- Converts code from CommonJS to ESModules
- Fix eslint-fixable eslint errors (unsupported in browser)
The examples directory contains examples of converted actions, in addition to the ones below. Action config can be found in actions.csv.
segment-track
Before
return await require("@pipedreamhq/platform").axios(this, {
method: 'post',
url: `https://api.segment.io/v1/track`,
auth: {
username: auths.segment.write_key,
},
data: {
anonymousId: params.anonymousId,
context: params.context,
event: params.event,
integrations: params.integrations,
properties: params.properties,
timestamp: params.timestamp,
userId: params.userId,
},
})
After
// legacy_hash_id: a_2wim5R
import { axios } from "@pipedream/platform";
export default {
key: "segment-track",
name: "Track actions your users perform",
description: "Track lets you record the actions your users perform (note requires userId or anonymousId)",
version: "0.3.1",
type: "action",
props: {
segment: {
type: "app",
app: "segment",
},
anonymousId: {
type: "string",
description: "A pseudo-unique substitute for a User ID, for cases when you don't have an absolutely unique identifier. A userId or an anonymousId is required.",
optional: true,
},
context: {
type: "object",
description: "Dictionary of extra information that provides useful context about a message, but is not directly related to the API call like ip address or locale",
optional: true,
},
event: {
type: "string",
description: "Name of the action that a user has performed.",
},
integrations: {
type: "object",
description: "Dictionary of destinations to either enable or disable",
optional: true,
},
properties: {
type: "object",
description: "Free-form dictionary of properties of the event, like revenue",
optional: true,
},
timestamp: {
type: "string",
description: "ISO-8601 date string",
optional: true,
},
userId: {
type: "string",
description: "Unique identifier for the user in your database. A userId or an anonymousId is required.",
optional: true,
},
},
async run({ $ }) {
return await axios($, {
method: "post",
url: "https://api.segment.io/v1/track",
auth: {
username: this.segment.$auth.write_key,
},
data: {
anonymousId: this.anonymousId,
context: this.context,
event: this.event,
integrations: this.integrations,
properties: this.properties,
timestamp: this.timestamp,
userId: this.userId,
},
});
},
};
mailchimp-add_or_update_subscriber
Before
const axios = require('axios')
list_id = params.list_id
subscriber_hash = params.subscriber_hash
skip_merge_validation = params.skip_merge_validation
return await require("@pipedreamhq/platform").axios(this, {
url: `https://${auths.mailchimp.dc}.api.mailchimp.com/3.0/lists/${list_id}/members/${subscriber_hash}?skip_merge_validation=${skip_merge_validation}`,
headers: {
Authorization: `Bearer ${auths.mailchimp.oauth_access_token}`,
},
method: 'PUT',
data: {
"email_address": params.email_address,
"status_if_new": params.statu_if_new,
"email_type": params.email_type,
"status": params.status,
"merge_fields": params.merge_fields,
"interests": params.interests,
"language": params.language,
"vip": params.vip,
"location": {
"latitude": params.latitude,
"longitude": params.longitude
},
"marketing_permissions": [{
"marketing_permission_id": params.marketing_permission_id,
"enabled": params.marketing_permissions_enabled
}],
"ip_signup": params.ip_signup,
"timestamp_signup": params.timestamp_signup,
"ip_opt": params.ip_opt,
"timestamp_opt": params.timestamp_opt
}
})
After
// legacy_hash_id: a_RAiaJ1
import { axios } from "@pipedream/platform";
export default {
key: "mailchimp-add-or-update-subscriber",
name: "Add or Update Subscriber",
description: "Adds a new subscriber to an audience or updates existing subscriber.",
version: "0.2.1",
type: "action",
props: {
mailchimp: {
type: "app",
app: "mailchimp",
},
list_id: {
type: "string",
description: "The unique ID for the list.",
},
subscriber_hash: {
type: "string",
description: "The MD5 hash of the lowercase version of the list member's email address.",
},
skip_merge_validation: {
type: "boolean",
description: "If skip_merge_validation is true, member data will be accepted without merge field values, even if the merge field is usually required. This defaults to False.",
optional: true,
},
email_address: {
type: "string",
description: "Email address for a subscriber. This value is required only if the email address is not already present on the list.",
},
statu_if_new: {
type: "string",
description: "Subscriber's status. This value is required only if the email address is not already present on the list.",
options: [
"subscribed",
"unsubscribed",
"cleaned",
"pending",
"transactional",
],
},
email_type: {
type: "string",
description: "Type of email this member asked to get ('html' or 'text').",
optional: true,
options: [
"html",
"text",
],
},
status: {
type: "string",
description: "Subscriber's current status.",
optional: true,
options: [
"subscribed",
"unsubscribed",
"cleaned",
"pending",
"transactional",
],
},
merge_fields: {
type: "object",
description: "An individual merge var and value for a member.",
optional: true,
},
interests: {
type: "object",
description: "The key of this object's properties is the ID of the interest in question.",
optional: true,
},
language: {
type: "string",
description: "If set/detected, the subscriber's language.",
optional: true,
},
vip: {
type: "boolean",
description: "VIP status for subscriber.",
optional: true,
},
latitude: {
type: "integer",
description: "The location latitude.",
optional: true,
},
longitude: {
type: "integer",
description: "The location longitude.",
optional: true,
},
marketing_permission_id: {
type: "string",
description: "The id for the marketing permission on the list.",
optional: true,
},
marketing_permissions_enabled: {
type: "boolean",
description: "If the subscriber has opted-in to the marketing permission.",
optional: true,
},
ip_signup: {
type: "string",
description: "IP address the subscriber signed up from.",
optional: true,
},
timestamp_signup: {
type: "string",
description: "The date and time the subscriber signed up for the list in ISO 8601 format.",
optional: true,
},
ip_opt: {
type: "string",
description: "The IP address the subscriber used to confirm their opt-in status.",
optional: true,
},
timestamp_opt: {
type: "string",
description: "The date and time the subscriber confirmed their opt-in status in ISO 8601 format.",
optional: true,
},
},
async run({ $ }) {
let listId = this.list_id;
let subscriberHash = this.subscriber_hash;
let skipMergeValidation = this.skip_merge_validation;
return await axios($, {
url: `https://${this.mailchimp.$auth.dc}.api.mailchimp.com/3.0/lists/${listId}/members/${subscriberHash}?skip_merge_validation=${skipMergeValidation}`,
headers: {
Authorization: `Bearer ${this.mailchimp.$auth.oauth_access_token}`,
},
method: "PUT",
data: {
"email_address": this.email_address,
"status_if_new": this.statu_if_new,
"email_type": this.email_type,
"status": this.status,
"merge_fields": this.merge_fields,
"interests": this.interests,
"language": this.language,
"vip": this.vip,
"location": {
"latitude": this.latitude,
"longitude": this.longitude,
},
"marketing_permissions": [
{
"marketing_permission_id": this.marketing_permission_id,
"enabled": this.marketing_permissions_enabled,
},
],
"ip_signup": this.ip_signup,
"timestamp_signup": this.timestamp_signup,
"ip_opt": this.ip_opt,
"timestamp_opt": this.timestamp_opt,
},
});
},
};