Skip to content

Commit

Permalink
#5172 - Formatter actions (#5430)
Browse files Browse the repository at this point in the history
* "Formatter" app structure

* pnpm lock

* Creating date-time formats

* Common date formatting for options

* Output functions for date formats

* Date Formatting action

* using temporary app for testing

* Adjusting time formatting option labels

* Add/Subtract Time action

* prop definitions for date input and formats

* Reusing code for date-time actions

* Base for number formatting actions

* Adding currencies + ESLint fixes

* "Format Number" action

* "Format number" adjustments

* "Transform Case" and adjustments

* Action "Default value" for text

* "Extract Email Address" action

* Base for text extract actions + extract number

* "Extract phone number" with predefined RegExps

* Extract by URL and Regular Expression actions

* Fixes on extract actions

* "Trim Whitespace" action

* "Split Text" action and util "buildRegExp" file

* Split Text and RegExp adjustments

* "Replace text" action with string and regex

* URL Encode and Decode actions

* HTML and Markdown conversion actions

* Renaming files to keep camelCase naming

* Creating 'compare dates' and utility date/time units

* ESLint

* Improvements

* Adding packages for 'pluralize' and 'title-case'

* RegExp fixes

* Currency and number formatting

* ESLint

* Updated list of currencies and formatting

* Number formatting adjustments

* Error catching and syntax improvements for currency formatting

* Adding 'formatting' app to actions

* Adjustments

* Changing 'formatter' folder to 'formatting'

* pnpm lock

* Adjusting value 0 as per issue #5429

* Updating package.json version

* PR review changes

* Adding app prop to actions missing it

* Bug fix

* Text Extraction actions description updates

* Name and description updates

* Adding output date format

* ESLint fixes

* Rename 'default-value' -> 'set-default-value'

* Adding option to infer integer input for dates

* Typo fixes

* Creating JSON conversion actions

* Converting input to string on number actions
  • Loading branch information
GTFalcao committed Feb 10, 2023
1 parent eec2154 commit 0ff8fb6
Show file tree
Hide file tree
Showing 36 changed files with 2,508 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { defineAction } from "@pipedream/types";
import app from "../../app/formatting.app";
import commonDateTime from "../../common/date-time/commonDateTime";
import {
DATE_FORMAT_PARSE_MAP, DEFAULT_FORMAT_VALUE,
} from "../../common/date-time/dateFormats";
import { DATE_TIME_UNITS } from "../../common/date-time/dateTimeUnits";

const OPERATION_OPTIONS = {
ADD: "Add",
SUBTRACT: "Subtract",
};

export default defineAction({
...commonDateTime,
name: "[Date/Time] Add/Subtract Time",
description: "Add or subtract time from a given input",
key: "formatting-add-subtract-time",
version: "0.0.1",
type: "action",
props: {
...commonDateTime.props,
operation: {
label: "Operation",
description: "Whether to add or subtract time.",
type: "string",
options: Object.values(OPERATION_OPTIONS),
},
duration: {
label: "Duration",
description:
"The duration for the operation. You can use the shorthand duration, for example: `1s`, `1m`, `1h`, `1d`, `1w`, `1y` equal one second, minute, hour, day, week, and year respectively",
type: "string",
},
outputFormat: {
propDefinition: [
app,
"outputFormat",
],
},
},
methods: {
...commonDateTime.methods,
getOperationMilliseconds(str: string) {
let result = 0;

const {
second, minute, hour, day, week, year,
} = DATE_TIME_UNITS;
Object.entries({
s: second,
m: minute,
h: hour,
d: day,
w: week,
y: year,
}).forEach(([
identifier,
multiplier,
]) => {
const substr = str.match(new RegExp(`[0-9]+\\s*${identifier}`))?.[0];
if (substr) {
const value = Number(substr.match(/[0-9]+/));
result += value * multiplier;
}
});

return result;
},
},
async run({ $ }): Promise<string | number> {
const {
operation, duration, outputFormat,
} = this;

const dateObj = this.getDateFromInput();

const value = dateObj.valueOf();
let amount = this.getOperationMilliseconds(duration);
if (operation === OPERATION_OPTIONS.SUBTRACT) amount *= -1;

const result = value + amount;

const format = outputFormat ?? this.inputFormat ?? DEFAULT_FORMAT_VALUE;
const { outputFn } = DATE_FORMAT_PARSE_MAP.get(format);
const output = outputFn(new Date(result));

$.export(
"$summary",
`Successfully ${
operation === OPERATION_OPTIONS.SUBTRACT
? "subtracted"
: "added"
} time`,
);
return output;
},
});
77 changes: 77 additions & 0 deletions components/formatting/actions/compare-dates/compare-dates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { defineAction } from "@pipedream/types";
import commonDateTime from "../../common/date-time/commonDateTime";
import app from "../../app/formatting.app";
import { DATE_TIME_UNITS } from "../../common/date-time/dateTimeUnits";

export default defineAction({
...commonDateTime,
name: "[Date/Time] Compare Dates",
description:
"Get the duration between two dates in days, hours, minutes, and seconds along with checking if they are the same.",
key: "formatting-compare-dates",
version: "0.0.1",
type: "action",
props: {
...commonDateTime.props,
inputDate: {
propDefinition: [
app,
"inputDate",
],
label: "Start Date",
description:
"Enter start date string, in the format defined in `Input Format`. If the start date is after the end date, these dates will be swapped and in the output `datesSwapped` will be set to `true`.",
},
endDate: {
propDefinition: [
app,
"inputDate",
],
label: "End Date",
description:
"Enter end date string, in the format defined in `Input Format`. Timezone is assumed the same for both dates if not explicitly set.",
},
},
async run({ $ }): Promise<object> {
const startDateObj = this.getDateFromInput(this.inputDate);
const endDateObj = this.getDateFromInput(this.endDate);

const startValue = startDateObj.valueOf();
const endValue = endDateObj.valueOf();

const datesSwapped = startValue > endValue;

let result = "equal";
let remainingValue = Math.abs(endValue - startValue);

if (remainingValue) {
const arrResults = [];
const arrUnits = Object.entries(DATE_TIME_UNITS).sort(
(a, b) => b[1] - a[1],
);

for (const [
word,
unit,
] of arrUnits) {
const amount = Math.floor(remainingValue / unit);
if (amount) {
arrResults.push(`${amount} ${amount === 1
? word
: `${word}s`}`);

remainingValue %= unit;
if (!remainingValue) break;
}
}

result = arrResults.join(", ");
}

$.export("$summary", "Successfully compared dates");
return {
datesSwapped,
result,
};
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineAction } from "@pipedream/types";
import showdown from "showdown";
import jsdom from "jsdom";
import app from "../../app/formatting.app";

export default defineAction({
name: "[Text] Convert HTML to Markdown",
description: "Convert valid HTML to Markdown text",
key: "formatting-convert-html-to-markdown",
version: "0.0.1",
type: "action",
props: {
app,
input: {
label: "Input",
description: "HTML string to be converted to Markdown",
type: "string",
},
},
async run({ $ }): Promise<string> {
const { input } = this;
const converter = new showdown.Converter();
const dom = new jsdom.JSDOM();
const result = converter.makeMarkdown(input, dom.window.document);

$.export("$summary", "Successfully converted to Markdown");
return result;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { defineAction } from "@pipedream/types";
import app from "../../app/formatting.app";

export default defineAction({
name: "[Data] Convert JSON to String",
description: "Convert an object to a JSON format string",
key: "formatting-convert-json-to-string",
version: "0.0.1",
type: "action",
props: {
app,
input: {
label: "Input",
description: "An object to be serialized to a JSON format string.",
type: "object",
},
},
async run({ $ }): Promise<string> {
try {
const result = JSON.stringify(this.input);
$.export("$summary", "Successfully convert object to JSON string");
return result;
} catch (err) {
throw new Error("Error serializing object to JSON string: " + err.toString());
}
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineAction } from "@pipedream/types";
import showdown from "showdown";
import jsdom from "jsdom";
import app from "../../app/formatting.app";

export default defineAction({
name: "[Text] Convert Markdown to HTML",
description: "Convert Markdown text to HTML",
key: "formatting-convert-markdown-to-html",
version: "0.0.1",
type: "action",
props: {
app,
input: {
label: "Input",
description: "Markdown string to be converted to HTML",
type: "string",
},
},
async run({ $ }): Promise<string> {
const { input } = this;
const converter = new showdown.Converter();
const dom = new jsdom.JSDOM();
const result = converter.makeHtml(input, dom.window.document);

$.export("$summary", "Successfully converted to HTML");
return result;
},
});
35 changes: 35 additions & 0 deletions components/formatting/actions/date-time-format/date-time-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { defineAction } from "@pipedream/types";
import { DATE_FORMAT_PARSE_MAP } from "../../common/date-time/dateFormats";
import commonDateTime from "../../common/date-time/commonDateTime";
import app from "../../app/formatting.app";

export default defineAction({
...commonDateTime,
name: "[Date/Time] Format",
description: "Format a date string to another date string",
key: "formatting-date-time-format",
version: "0.0.1",
type: "action",
props: {
...commonDateTime.props,
outputFormat: {
propDefinition: [
app,
"outputFormat",
],
description: "The format to convert the date to.",
optional: false,
},
},
async run({ $ }): Promise<string | number> {
const { outputFormat } = this;

const dateObj = this.getDateFromInput();

const { outputFn } = DATE_FORMAT_PARSE_MAP.get(outputFormat);
const output = outputFn(dateObj);

$.export("$summary", "Successfully formatted date/time");
return output;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { defineAction } from "@pipedream/types";
import buildRegExp from "../../common/text/buildRegExp";
import app from "../../app/formatting.app";

export default defineAction({
name: "[Text] Extract by Regular Expression",
description:
"Find a match for a regular expression pattern. Returns all matched groups with start and end position.",
key: "formatting-extract-by-regular-expression",
version: "0.0.1",
type: "action",
props: {
app,
input: {
label: "Input",
description: "Text you would like to find a pattern from",
type: "string",
},
regExpString: {
label: "Regular Expression",
description:
"Enter a string representing a [Regular Expression](https://www.w3schools.com/js/js_regexp.asp)",
type: "string",
},
},
methods: {
getRegExp(): string | RegExp {
const { regExpString } = this;
return regExpString.startsWith("/")
? buildRegExp(regExpString, [
"g",
])
: regExpString;
},
getResult(input: string) {
return [
...input.matchAll(this.getRegExp()),
].map((match) => ({
match: match[0],
startPosition: match.index,
endPosition: match.index + match[0].length,
}));
},
},
async run({ $ }) {
const input: string = this.input;
const result = this.getResult(input);

$.export(
"$summary",
result.length
? `Successfully found ${result.length} matches`
: "No matches found",
);
return result;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineAction } from "@pipedream/types";
import commonExtractText from "../../common/text/commonExtractText";

export default defineAction({
...commonExtractText,
name: "[Text] Extract Email Address",
description:
"Find an email address out of a text field. Finds the first email address only.",
key: "formatting-extract-email-address",
version: "0.0.1",
type: "action",
props: {
...commonExtractText.props,
input: {
label: "Input",
description: "String from which you'd like to extract an email address",
type: "string",
},
},
methods: {
...commonExtractText.methods,
getRegExp() {
return /[\w-.]+@([\w-]+\.)+[\w-]{2,}/;
},
getType() {
return "email address";
},
},
});

1 comment on commit 0ff8fb6

@vercel
Copy link

@vercel vercel bot commented on 0ff8fb6 Feb 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.