diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..8ac6b8c
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml
index 1b288e3..a0a3966 100644
--- a/.github/workflows/deno.yml
+++ b/.github/workflows/deno.yml
@@ -2,9 +2,11 @@ name: Deno app build and testing
on:
push:
- branches: [ main ]
+ branches:
+ - main
pull_request:
- branches: [ main ]
+ branches:
+ - main
jobs:
deno:
@@ -18,7 +20,7 @@ jobs:
- name: Setup Deno
uses: denoland/setup-deno@v1
with:
- deno-version: v1.x
+ deno-version: v2.x
- name: Verify formatting
run: deno fmt --check
diff --git a/.gitignore b/.gitignore
index baa4baa..87503bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
dist
package
.DS_Store
-.slack/apps.dev.json
.env
diff --git a/.slack/.gitignore b/.slack/.gitignore
new file mode 100644
index 0000000..973ba60
--- /dev/null
+++ b/.slack/.gitignore
@@ -0,0 +1,2 @@
+apps.dev.json
+cache/
diff --git a/slack.json b/.slack/hooks.json
similarity index 100%
rename from slack.json
rename to .slack/hooks.json
diff --git a/README.md b/README.md
index 32e8f97..831c31a 100644
--- a/README.md
+++ b/README.md
@@ -198,11 +198,9 @@ $ slack activity --tail
Contains `apps.dev.json` and `apps.json`, which include installation details for
development and deployed apps.
-### `datastores/`
-
-[Datastores](https://api.slack.com/automation/datastores) securely store data
-for your application on Slack infrastructure. Required scopes to use datastores
-include `datastore:write` and `datastore:read`.
+Contains `hooks.json` used by the CLI to interact with the project's SDK
+dependencies. It contains script hooks that are executed by the CLI and
+implemented by the SDK.
### `functions/`
@@ -230,11 +228,6 @@ continuing to the next step.
The [app manifest](https://api.slack.com/automation/manifest) contains the app's
configuration. This file defines attributes like app name and description.
-### `slack.json`
-
-Used by the CLI to interact with the project's SDK dependencies. It contains
-script hooks that are executed by the CLI and implemented by the SDK.
-
## Resources
To learn more about developing automations on Slack, visit the following:
diff --git a/deno.jsonc b/deno.jsonc
index 56029c4..051c2bf 100644
--- a/deno.jsonc
+++ b/deno.jsonc
@@ -1,5 +1,5 @@
{
- "$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
+ "$schema": "https://raw.githubusercontent.com/denoland/deno/main/cli/schemas/config-file.v1.json",
"fmt": {
"include": [
"README.md",
@@ -13,7 +13,6 @@
"workflows"
]
},
- "importMap": "import_map.json",
"lint": {
"include": [
"datastores",
@@ -28,6 +27,12 @@
},
"lock": false,
"tasks": {
- "test": "deno fmt --check && deno lint && deno test --allow-read --allow-none"
+ "test": "deno fmt --check && deno lint && deno test --allow-read"
+ },
+ "imports": {
+ "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.15.0/",
+ "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.8.0/",
+ "@std/testing": "jsr:@std/testing@^1.0.12",
+ "@std/assert": "jsr:@std/assert@^1.0.13"
}
}
diff --git a/functions/detect_lang_test.ts b/functions/detect_lang_test.ts
index abc4ff4..f8d2714 100644
--- a/functions/detect_lang_test.ts
+++ b/functions/detect_lang_test.ts
@@ -1,5 +1,5 @@
import { SlackFunctionTester } from "deno-slack-sdk/mod.ts";
-import { assertEquals } from "std/testing/asserts.ts";
+import { assertEquals } from "@std/assert";
import handler from "./detect_lang.ts";
const { createContext } = SlackFunctionTester("my-function");
diff --git a/functions/translate.ts b/functions/translate.ts
index f2d11c9..fb63df8 100644
--- a/functions/translate.ts
+++ b/functions/translate.ts
@@ -1,5 +1,5 @@
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";
-import { SlackAPIClient } from "deno-slack-sdk/types.ts";
+import type { SlackAPIClient } from "deno-slack-sdk/types.ts";
import { isDebugMode } from "./internals/debug_mode.ts";
export const def = DefineFunction({
@@ -52,7 +52,7 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
return { error };
}
- if (translationTargetResponse.messages.length == 0) {
+ if (translationTargetResponse.messages.length === 0) {
console.log("No message found");
return emptyOutputs; // this is not an error
}
@@ -81,7 +81,7 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
if (match.match(/^[#@].*$/)) {
const matched = match.match(/^([#@].*)$/);
if (matched != null) {
- return "" + matched[1] + "";
+ return `${matched[1]}`;
}
return "";
}
@@ -93,7 +93,7 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
if (match.match(/^!date.*$/)) {
const matched = match.match(/^(!date.*)$/);
if (matched != null) {
- return "" + matched[1] + "";
+ return `${matched[1]}`;
}
return "";
}
@@ -101,7 +101,7 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
if (match.match(/^!.*$/)) {
const matched = match.match(/^!(.*?)(?:\|.*)?$/);
if (matched != null) {
- return "@" + matched[1] + "";
+ return `@${matched[1]}`;
}
return "@[special mention]";
}
@@ -109,16 +109,16 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
if (match.match(/^.*?\|.*$/)) {
const matched = match.match(/^(.*?)\|(.*)$/);
if (matched != null) {
- return '' + matched[2] + "";
+ return `${matched[2]}`;
}
return "";
}
// fallback (raw link or unforeseen formatting)
- return "" + match + "";
+ return `${match}`;
// match emoji
})
.replace(/:([a-z0-9_-]+):/g, (_: unknown, match: string) => {
- return "" + match + "";
+ return `${match}`;
});
body.append("text", targetText);
body.append("tag_handling", "xml");
@@ -133,8 +133,8 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
},
body,
});
- if (deeplResponse.status != 200) {
- if (deeplResponse.status == 403) {
+ if (deeplResponse.status !== 200) {
+ if (deeplResponse.status === 403) {
// If the status code is 403, the given auth key is not valid
const error =
`Translating a message failed! Please make sure if the DEEPL_AUTH_KEY is correct. - (status: ${deeplResponse.status}, target text: ${
@@ -170,11 +170,11 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
const translatedText = translationResult.translations[0].text
// Parse encoding tags to restore the original special syntax
.replace(/([a-z0-9_-]+)<\/emoji>/g, (_: unknown, match: string) => {
- return ":" + match + ":";
+ return `:${match}:`;
// match ...
})
.replace(/(.*?)<\/mrkdwn>/g, (_: unknown, match: string) => {
- return "<" + match + ">";
+ return `<${match}>`;
// match ...
})
.replace(
@@ -182,7 +182,7 @@ export default SlackFunction(def, async ({ inputs, client, env }) => {
(_: unknown, match: string) => {
const matched = match.match(/(.*?)<\/a>/);
if (matched != null) {
- return "<" + matched[1] + "|" + matched[2] + ">";
+ return `<${matched[1]}|${matched[2]}>`;
}
return "";
// match ...
diff --git a/functions/translate_test.ts b/functions/translate_test.ts
index 8038596..2b0e71b 100644
--- a/functions/translate_test.ts
+++ b/functions/translate_test.ts
@@ -1,81 +1,100 @@
-import * as mf from "mock-fetch/mod.ts";
import { SlackFunctionTester } from "deno-slack-sdk/mod.ts";
-import { assertEquals } from "std/testing/asserts.ts";
+import { assertEquals } from "@std/assert";
+import { stub } from "@std/testing/mock";
import handler from "./translate.ts";
-// Replaces globalThis.fetch with the mocked copy
-mf.install();
+function stubFetch() {
+ // Replaces globalThis.fetch with the mocked copy
+ return stub(
+ globalThis,
+ "fetch",
+ async (url: string | URL | Request, options?: RequestInit) => {
+ const req = url instanceof Request ? url : new Request(url, options);
-mf.mock("POST@/api/conversations.replies", (args) => {
- const authHeader = args.headers.get("Authorization");
- if (authHeader === "Bearer empty-response") {
- return new Response(JSON.stringify({ ok: true, messages: [] }), {
- status: 200,
- });
- }
- return new Response(
- JSON.stringify({
- "ok": true,
- "oldest": "1670566778.964519",
- "messages": [
- {
- "type": "message",
- "text":
- "Make work life simpler, more pleasant and more productive.\n\nSlack is the collaboration hub that brings the right people, information, and tools together to get work done. From Fortune 100 companies to corner markets, millions of people around the world use Slack to connect their teams, unify their systems, and drive their business forward.",
- "user": "U03E94MK0",
- "ts": "1670566778.964519",
- "team": "T03E94MJU",
- "thread_ts": "1670566778.964519",
- "reply_count": 3,
- "reply_users_count": 1,
- "latest_reply": "1670570301.090889",
- "reply_users": ["U04EJMQQEFN"],
- "is_locked": false,
- "subscribed": false,
- "reactions": [{ "name": "jp", "users": ["U03E94MK0"], "count": 1 }],
- },
- ],
- "has_more": false,
- "pin_count": 0,
- "channel_actions_ts": null,
- "channel_actions_count": 0,
- }),
- {
- status: 200,
- },
- );
-});
+ assertEquals(req.method, "POST");
-mf.mock("POST@/api/chat.postMessage", () => {
- return new Response(JSON.stringify({ ok: true, ts: "1111.2222" }), {
- status: 200,
- });
-});
-
-mf.mock("POST@/v2/translate", async (args) => {
- const body = await args.formData();
- if (body.get("auth_key") !== "valid") {
- return new Response("", { status: 403 });
- }
- return new Response(
- JSON.stringify({
- translations: [
- {
- detected_source_language: "EN",
- text:
- "ワークライフをよりシンプルに、より快適に、より生産的にする。\n\nSlack は、適切な人、情報、ツールを集めて仕事を成し遂げるためのコラボレーション ハブです。フォーチュン100の企業から片隅の市場ま...",
- },
- ],
- }),
- {
- status: 200,
+ switch (req.url) {
+ case "https://slack.com/api/conversations.replies":
+ if (req.headers.get("Authorization") === "Bearer empty-response") {
+ return new Response(JSON.stringify({ ok: true, messages: [] }), {
+ status: 200,
+ });
+ }
+ return new Response(
+ JSON.stringify({
+ "ok": true,
+ "oldest": "1670566778.964519",
+ "messages": [
+ {
+ "type": "message",
+ "text":
+ "Make work life simpler, more pleasant and more productive.\n\nSlack is the collaboration hub that brings the right people, information, and tools together to get work done. From Fortune 100 companies to corner markets, millions of people around the world use Slack to connect their teams, unify their systems, and drive their business forward.",
+ "user": "U03E94MK0",
+ "ts": "1670566778.964519",
+ "team": "T03E94MJU",
+ "thread_ts": "1670566778.964519",
+ "reply_count": 3,
+ "reply_users_count": 1,
+ "latest_reply": "1670570301.090889",
+ "reply_users": ["U04EJMQQEFN"],
+ "is_locked": false,
+ "subscribed": false,
+ "reactions": [{
+ "name": "jp",
+ "users": ["U03E94MK0"],
+ "count": 1,
+ }],
+ },
+ ],
+ "has_more": false,
+ "pin_count": 0,
+ "channel_actions_ts": null,
+ "channel_actions_count": 0,
+ }),
+ {
+ status: 200,
+ },
+ );
+ case "https://slack.com/api/chat.postMessage": {
+ return new Response(JSON.stringify({ ok: true, ts: "1111.2222" }), {
+ status: 200,
+ });
+ }
+ case "https://api.deepl.com/v2/translate": {
+ const body = await req.formData();
+ if (body.get("auth_key") === "valid") {
+ return new Response(
+ JSON.stringify({
+ translations: [
+ {
+ detected_source_language: "EN",
+ text:
+ "ワークライフをよりシンプルに、より快適に、より生産的にする。\n\nSlack は、適切な人、情報、ツールを集めて仕事を成し遂げるためのコラボレーション ハブです。フォーチュン100の企業から片隅の市場ま...",
+ },
+ ],
+ }),
+ {
+ status: 200,
+ },
+ );
+ }
+ return new Response("", { status: 403 });
+ }
+ default:
+ throw Error(
+ `No stub found for ${req.method} ${req.url}\nHeaders: ${
+ JSON.stringify(Object.fromEntries(req.headers.entries()))
+ }`,
+ );
+ }
},
);
-});
+}
const { createContext } = SlackFunctionTester("my-function");
Deno.test("No message found", async () => {
+ using _stubFetch = stubFetch();
const inputs = {
channelId: "C111",
messageTs: "1670566778.964519",
@@ -88,6 +107,7 @@ Deno.test("No message found", async () => {
});
Deno.test("Translate a message successfully", async () => {
+ using _stubFetch = stubFetch();
const inputs = {
channelId: "C123",
messageTs: "1670566778.964519",
@@ -100,6 +120,7 @@ Deno.test("Translate a message successfully", async () => {
});
Deno.test("Fail to translate with an invalid auth key", async () => {
+ using _stubFetch = stubFetch();
const inputs = {
channelId: "C111",
messageTs: "1670566778.964519",
diff --git a/import_map.json b/import_map.json
deleted file mode 100644
index 8144976..0000000
--- a/import_map.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "imports": {
- "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.15.0/",
- "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.8.0/",
- "std/": "https://deno.land/std@0.224.0/",
- "mock-fetch/": "https://deno.land/x/mock_fetch@0.3.0/"
- }
-}
diff --git a/triggers/reaction_added_trigger.ts b/triggers/reaction_added_trigger.ts
index f1a5f90..e521c08 100644
--- a/triggers/reaction_added_trigger.ts
+++ b/triggers/reaction_added_trigger.ts
@@ -1,4 +1,4 @@
-import { Trigger } from "deno-slack-sdk/types.ts";
+import type { Trigger } from "deno-slack-sdk/types.ts";
import {
TriggerContextData,
TriggerEventTypes,