Skip to content
This repository was archived by the owner on Apr 24, 2023. It is now read-only.

Commit 1f79e7a

Browse files
Enforce Function File Contract earlier (#27)
1 parent daf2b41 commit 1f79e7a

File tree

8 files changed

+139
-8
lines changed

8 files changed

+139
-8
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ _**Note:** The examples below use version `0.1.0` of `deno-slack-builder`; check
1212

1313
In a directory that contains a valid manifest file (`manifest.json`, `manifest.js`, or `manifest.ts`), run the following:
1414

15-
```
15+
```bash
1616
deno run --allow-write --allow-read "https://deno.land/x/deno_slack_builder@0.1.0/mod.ts"
1717
```
1818

@@ -31,12 +31,14 @@ The top level `mod.ts` file is executed as a Deno program, and takes up to three
3131
### Example Usage
3232

3333
**Only generate a valid Run On Slack manifest file:**
34-
```
34+
35+
```bash
3536
deno run --allow-write --allow-read "https://deno.land/x/deno_slack_builder@0.1.0/mod.ts" --manifest
3637
```
3738

3839
**Generate a Run On Slack project from a /src directory:**
39-
```
40+
41+
```bash
4042
deno run --allow-write --allow-read "https://deno.land/x/deno_slack_builder@0.1.0/mod.ts" --source src
4143
```
4244

@@ -55,6 +57,7 @@ Allows for flexibility with how you define your manifest.
5557
* If no `manifest.ts` exists, looks for a `manifest.js` file, and follows the same logic as `manifest.ts` does.
5658

5759
## Function Bundling
60+
5861
* For each entry in the `functions` where `remote_environment=slack` it looks for a `source_file` property, which should be a relative path to the corresponding function file. This is then bundled for the Run on Slack Deno runtime. The `reverse` function defined below indicates there should be a corresponding function file in the project located at `functions/reverse.ts`.
5962

6063
```json
@@ -89,11 +92,15 @@ Allows for flexibility with how you define your manifest.
8992

9093
If you make changes to this repo, or just want to make sure things are working as desired, you can run:
9194

92-
deno task test
95+
```bash
96+
deno task test
97+
```
9398

9499
To get a full test coverage report, run:
95100

96-
deno task coverage
101+
```bash
102+
deno task coverage
103+
```
97104

98105
---
99106

deno.jsonc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
}
1111
},
1212
"tasks": {
13-
"test": "deno fmt --check && deno lint && deno test src",
14-
"coverage": "deno test --coverage=.coverage src && deno coverage --exclude=fixtures --exclude=test .coverage"
13+
"test": "deno fmt --check && deno lint && deno test --allow-read src",
14+
"coverage": "deno test --coverage=.coverage --allow-read src && deno coverage --exclude=fixtures --exclude=test .coverage"
1515
}
1616
}

src/dev_deps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export {
22
assertEquals,
33
assertExists,
4+
assertRejects,
45
} from "https://deno.land/std@0.134.0/testing/asserts.ts";

src/functions.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ export const validateAndCreateFunctions = async (
4242
}
4343
};
4444

45+
const functionPathHasDefaultExport = async (
46+
functionFilePath: string,
47+
) => {
48+
const functionModule = await import(`file://${functionFilePath}`);
49+
return functionModule.default
50+
? typeof functionModule.default == "function"
51+
: false;
52+
};
53+
4554
const getValidFunctionPath = async (
4655
options: Options,
4756
fnId: string,
@@ -70,6 +79,12 @@ const getValidFunctionPath = async (
7079
}
7180
throw new Error(e);
7281
}
82+
83+
if (!await functionPathHasDefaultExport(fnFilePath)) {
84+
throw new Error(
85+
`File: ${fnFilePath}, containing your function does not define a default export handler.`,
86+
);
87+
}
7388
return fnFilePath;
7489
};
7590

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default () => {
2+
console.log("this is my slack function");
3+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const func = () => {
2+
console.log("this is my slack function");
3+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default "hello";

src/tests/functions_test.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,107 @@
11
import { validateAndCreateFunctions } from "../functions.ts";
2-
import { assertExists } from "../dev_deps.ts";
2+
import { assertEquals, assertExists, assertRejects } from "../dev_deps.ts";
3+
import { Options } from "../types.ts";
34

45
Deno.test("validateAndCreateFunctions", () => {
56
assertExists(validateAndCreateFunctions);
67
});
8+
9+
Deno.test("validateAndCreateFunctions should not throw an exception when fed a function file that has a default export", async () => {
10+
const captured_log: string[] = [];
11+
const options: Options = {
12+
manifestOnly: true,
13+
workingDirectory: Deno.cwd(),
14+
log: (x) => {
15+
captured_log.push(x);
16+
},
17+
};
18+
const manifest = {
19+
"functions": {
20+
"test_function": {
21+
"title": "Test function",
22+
"description": "this is a test",
23+
"source_file": "src/tests/functions/test_function_file.ts",
24+
"input_parameters": {
25+
"required": [],
26+
"properties": {},
27+
},
28+
"output_parameters": {
29+
"required": [],
30+
"properties": {},
31+
},
32+
},
33+
},
34+
};
35+
36+
await validateAndCreateFunctions(
37+
options,
38+
manifest,
39+
);
40+
assertEquals("", captured_log.join(""));
41+
});
42+
43+
Deno.test("Function files with no default export should get an error", async () => {
44+
const captured_log: string[] = [];
45+
const options: Options = {
46+
manifestOnly: true,
47+
workingDirectory: Deno.cwd(),
48+
log: (x) => {
49+
captured_log.push(x);
50+
},
51+
};
52+
const manifest = {
53+
"functions": {
54+
"test_function": {
55+
"title": "Test function",
56+
"description": "this is a test",
57+
"source_file": "src/tests/functions/test_function_no_export_file.ts",
58+
"input_parameters": {
59+
"required": [],
60+
"properties": {},
61+
},
62+
"output_parameters": {
63+
"required": [],
64+
"properties": {},
65+
},
66+
},
67+
},
68+
};
69+
await assertRejects(
70+
() => validateAndCreateFunctions(options, manifest),
71+
Error,
72+
"default export handler",
73+
);
74+
});
75+
76+
Deno.test("Function files not exporting a function should get an error", async () => {
77+
const captured_log: string[] = [];
78+
const options: Options = {
79+
manifestOnly: true,
80+
workingDirectory: Deno.cwd(),
81+
log: (x) => {
82+
captured_log.push(x);
83+
},
84+
};
85+
const manifest = {
86+
"functions": {
87+
"test_function": {
88+
"title": "Test function",
89+
"description": "this is a test",
90+
"source_file": "src/tests/functions/test_function_not_function_file.ts",
91+
"input_parameters": {
92+
"required": [],
93+
"properties": {},
94+
},
95+
"output_parameters": {
96+
"required": [],
97+
"properties": {},
98+
},
99+
},
100+
},
101+
};
102+
await assertRejects(
103+
() => validateAndCreateFunctions(options, manifest),
104+
Error,
105+
"default export handler",
106+
);
107+
});

0 commit comments

Comments
 (0)