Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: select external #118

Merged
merged 2 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions .utils/slack-dom-to-rustdoc.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
/*
What this script does: Convert slack documentation HTML to rustdoc comments.

How to use this script:
- In Slack API Docs, e.g. https://api.slack.com/reference/block-kit/composition-objects#option
1. right click > inspect element on description, e.g. for `text` (A text object that defines...)
2. select <td> wrapping the paragraph, right click > copy inner HTML
3. in shell, do `echo 'PASTE HTML' | node .utils/slack-dom-to-rustdoc.js`
4. Rustdoc comments are printed to standard output
*/

// Slack raw HTML string from stdin
let contents = '';

// Read `contents` from stdin
process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
let chunk = process.stdin.read();
while (chunk) {
contents += chunk;
chunk = process.stdin.read();
}
const storeNextChunk = () => {
const chunk = process.stdin.read();

if (chunk) { contents += chunk; }

return chunk ? storeNextChunk() : {};
};

storeNextChunk();
});

process.stdin.on('end', () => {
Expand All @@ -28,7 +43,7 @@ process.stdin.on('end', () => {

// ex. <a src="/link">Text</a> -> [Text 🔗] [Text 🔗]: https://api.slack.com/link
escapeLinks,

// Move MD link definitions to the bottom
moveLinkDefsToBottom,

Expand All @@ -38,6 +53,8 @@ process.stdin.on('end', () => {
// ex. <strong>blah</strong> -> **blah**
escapeStrong,

removeEmptyLines,

// Prepend each line with ///
docComment,
];
Expand All @@ -57,30 +74,26 @@ const ord = {
};

const helpers = {
// Test if a string is a markdown link definition,
// for example: '[Test]: ...' would return true.

// isLink :: String -> Boolean
// Test if a string is a markdown link definition,
// for example: '[Test]: ...' would return true.
// isLink :: String -> Boolean
isLink: str => (/\[.*?\]\:/i).test(str),

// Accepts a Regex pattern, replacement string, and input String
// Returns the input string with String#replace applied.

// replace :: (RegExp, String) -> String -> String
// Accepts a Regex pattern, replacement string, and input String
// Returns the input string with String#replace applied.
// replace :: (RegExp, String) -> String -> String
replace: (pat, replace) => contents => {
const output = contents.replace(pat, replace);
return output;
},

// Accepts an input String and String -> String fn,
// Returns the input string with the mapping fn applied to each line.

// eachLine :: (String -> String) -> String -> String
eachLine: map => contents =>
contents
.split('\n')
.map(map)
.join('\n'),
// Accepts an input String and String -> String fn,
// Returns the input string with the mapping fn applied to each line.
// eachLine :: (String -> String) -> String -> String
eachLine: map => contents => contents
.split('\n')
.map(map)
.join('\n'),
}

// # Transformers
Expand Down Expand Up @@ -110,7 +123,7 @@ const escapeCode = helpers.replace(/<code>(.*?)<\/code>/gi, '`$1`');
const escapeStrong = helpers.replace(/<strong>(.*?)<\/strong>/gi, '**$1**');

// appendNewlineToPeriods :: String -> String
const appendNewlineToPeriods = helpers.replace(/\./gi, '.\n');
const appendNewlineToPeriods = helpers.replace(/\. /gi, '.\n');

// moveLinkDefsToBottom :: String -> String
const moveLinkDefsToBottom = c =>
Expand All @@ -123,5 +136,8 @@ const moveLinkDefsToBottom = c =>
)
.join('');

// removeEmptyLines :: String -> String
const removeEmptyLines = contents => contents.split('\n').filter(s => s !== '').join('\n');

// docComment :: String -> String
const docComment = helpers.eachLine(c => '/// ' + c);
6 changes: 6 additions & 0 deletions src/block_elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub enum BlockElement<'a> {

#[serde(rename = "users_select")]
SelectUser(select::User<'a>),

#[serde(rename = "external_select")]
SelectExternal(select::External<'a>),
}

impl<'a> BlockElement<'a> {
Expand All @@ -52,6 +55,7 @@ impl<'a> BlockElement<'a> {
Self::SelectPublicChannel(cts) => cts.validate(),
Self::SelectConversation(cts) => cts.validate(),
Self::SelectUser(cts) => cts.validate(),
Self::SelectExternal(cts) => cts.validate(),
rest => todo!("validation not implemented for {:?}", rest),
}
}
Expand All @@ -64,10 +68,12 @@ convert!(impl<'a> From<Select<'a>> for BlockElement<'a>
Select::PublicChannel(s) => s.into(),
Select::Conversation(s) => s.into(),
Select::User(s) => s.into(),
Select::External(s) => s.into(),
_ => todo!()
}
);

convert!(impl<'a> From<select::External<'a>> for BlockElement<'a> => |s| BlockElement::SelectExternal(s));
convert!(impl<'a> From<select::PublicChannel<'a>> for BlockElement<'a> => |s| BlockElement::SelectPublicChannel(s));
convert!(impl<'a> From<select::Conversation<'a>> for BlockElement<'a> => |s| BlockElement::SelectConversation(s));
convert!(impl<'a> From<select::User<'a>> for BlockElement<'a> => |s| BlockElement::SelectUser(s));
32 changes: 32 additions & 0 deletions src/block_elements/select/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::compose::Confirm;
use crate::text;

use super::Conversation;
use super::External;
use super::PublicChannel;
use super::User;

Expand Down Expand Up @@ -189,4 +190,35 @@ impl<'a> SelectBuilder<'a> {
None => sel,
}
}

/// Users will choose from an external data source. See docs for `select::External` for more info.
///
/// # Example
/// ```
/// use std::iter;
/// use std::convert::TryFrom;
///
/// use slack_blocks::{
/// text,
/// text::ToSlackPlaintext,
/// blocks::{Block, Section, Actions},
/// block_elements::{BlockElement, select::Select},
/// };
///
/// let select: BlockElement = Select::from_placeholder_and_action_id("Pick your favorite cheese", "cheese_chosen")
/// .choose_from_external()
/// .into();
///
/// let blocks: Block = Actions::try_from(select).unwrap().into();
///
/// // <send `blocks` to slack's API>
/// ```
pub fn choose_from_external(self) -> External<'a> {
let sel = External::from_placeholder_and_action_id(self.placeholder, self.action_id);

match self.confirm {
Some(confirm) => sel.with_confirm(confirm),
None => sel,
}
}
}
Loading