From 8a7c7867c79315c6c30a3d57648ab4e863bec3e1 Mon Sep 17 00:00:00 2001 From: ricardo Date: Tue, 4 May 2021 15:35:41 -0400 Subject: [PATCH] :sparkles: Markdown Node --- .../nodes/Markdown/Markdown.node.ts | 181 ++++++++++++++++++ .../nodes-base/nodes/Markdown/markdown.svg | 6 + packages/nodes-base/package.json | 3 + 3 files changed, 190 insertions(+) create mode 100644 packages/nodes-base/nodes/Markdown/Markdown.node.ts create mode 100644 packages/nodes-base/nodes/Markdown/markdown.svg diff --git a/packages/nodes-base/nodes/Markdown/Markdown.node.ts b/packages/nodes-base/nodes/Markdown/Markdown.node.ts new file mode 100644 index 0000000000000..4478d2f60f201 --- /dev/null +++ b/packages/nodes-base/nodes/Markdown/Markdown.node.ts @@ -0,0 +1,181 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; + +//@ts-expect-error +import * as showdown from 'showdown'; + +//@ts-expect-error +import * as jsdom from 'jsdom'; + +const dom = new jsdom.JSDOM(); + +const converter = new showdown.Converter(); + +import { + set, +} from 'lodash'; + +export class Markdown implements INodeType { + description: INodeTypeDescription = { + displayName: 'Markdown', + name: 'markdown', + icon: 'file:markdown.svg', + group: ['output'], + version: 1, + subtitle: '={{$parameter["mode"]==="markdownToHtml" ? "Markdown to HTML" : "HTML to Markdown"}}', + description: 'Move data between Markdown and HTML.', + defaults: { + name: 'Markdown', + color: '#000000', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [], + properties: [ + { + displayName: 'Mode', + name: 'mode', + type: 'options', + options: [ + { + name: 'Markdown to HTML', + value: 'markdownToHtml', + description: 'Move data from MarkdoWN to HTML', + }, + { + name: 'HTML to Markdown', + value: 'htmlToMarkdown', + description: 'Move data from HTML to Markdown.', + }, + ], + default: 'htmlToMarkdown', + description: 'From and to where data should be moved.', + }, + { + displayName: 'HTML', + name: 'html', + type: 'string', + displayOptions: { + show: { + mode: [ + 'htmlToMarkdown', + ], + }, + }, + default: '', + required: true, + description: 'The HTML to be converted.', + }, + { + displayName: 'Markdown', + name: 'markdown', + type: 'string', + displayOptions: { + show: { + mode: [ + 'markdownToHtml', + ], + }, + }, + default: '', + required: true, + description: 'The Markdown to be converted.', + }, + { + displayName: 'Destination Key', + name: 'destinationKey', + type: 'string', + displayOptions: { + show: { + mode: [ + 'markdownToHtml', + 'htmlToMarkdown', + ], + }, + }, + default: 'data', + required: true, + placeholder: '', + description: 'The name the JSON key to copy data to. It is also possible
to define deep keys by using dot-notation like for example:
"level1.level2.newKey"', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + options: [ + { + displayName: 'Flavor', + name: 'flavor', + type: 'options', + options: [ + { + name: 'Github', + value: 'github', + description: 'GFM (GitHub Flavored Markdown)', + }, + { + name: 'Vanilla', + value: 'vanilla', + description: 'Showdown base flavor', + }, + { + name: 'Original', + value: 'original', + description: `Original markdown flavor as in John Gruber's spec`, + }, + ], + displayOptions: { + show: { + '/mode': [ + 'htmlToMarkdown', + ], + }, + }, + default: 'vanilla', + }, + ], + }, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: INodeExecutionData[] = []; + const length = items.length as unknown as number; + const newItem: INodeExecutionData = { json: {} }; + const mode = this.getNodeParameter('mode', 0) as string; + + for (let i = 0; i < length; i++) { + if (mode === 'htmlToMarkdown') { + const options = this.getNodeParameter('options', i) as IDataObject; + const destinationKey = this.getNodeParameter('destinationKey', i) as string; + converter.setFlavor(options.flavor as showdown.Flavor || 'vanilla'); + const html = this.getNodeParameter('html', i) as string; + const md = converter.makeMarkdown(html, dom.window.document); + newItem.json = JSON.parse(JSON.stringify(items[i].json)); + set(newItem.json, destinationKey, md); + returnData.push(newItem); + } + + if (mode === 'markdownToHtml') { + const markdown = this.getNodeParameter('markdown', i) as string; + const html = converter.makeHtml(markdown); + const destinationKey = this.getNodeParameter('destinationKey', i) as string; + newItem.json = JSON.parse(JSON.stringify(items[i].json)); + set(newItem.json, destinationKey, html); + returnData.push(newItem); + } + } + return this.prepareOutputData(returnData); + } +} diff --git a/packages/nodes-base/nodes/Markdown/markdown.svg b/packages/nodes-base/nodes/Markdown/markdown.svg new file mode 100644 index 0000000000000..24f62fb3298bf --- /dev/null +++ b/packages/nodes-base/nodes/Markdown/markdown.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 6056f40f71320..cb623cfd865fb 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -420,6 +420,7 @@ "dist/nodes/Mailjet/Mailjet.node.js", "dist/nodes/Mailjet/MailjetTrigger.node.js", "dist/nodes/Mandrill/Mandrill.node.js", + "dist/nodes/Markdown/Markdown.node.js", "dist/nodes/Matrix/Matrix.node.js", "dist/nodes/Mattermost/Mattermost.node.js", "dist/nodes/Mautic/Mautic.node.js", @@ -607,6 +608,7 @@ "iconv-lite": "^0.6.2", "imap-simple": "^4.3.0", "iso-639-1": "^2.1.3", + "jsdom": "^16.5.3", "jsonwebtoken": "^8.5.1", "kafkajs": "^1.14.0", "lodash.get": "^4.4.2", @@ -630,6 +632,7 @@ "request": "^2.88.2", "rhea": "^1.0.11", "rss-parser": "^3.7.0", + "showdown": "^1.9.1", "snowflake-sdk": "^1.5.3", "ssh2-sftp-client": "^5.2.1", "tmp-promise": "^3.0.2",