Skip to content

Commit 3e76971

Browse files
author
Ricky C
committed
feat: Add support for TypeScript scripts
Both of the .cts and .mts flavors. Because this action is written in CommonJS both have to compile to CommonJS in order to execute. As it is TypeScript there's already an expectation of some slowness, so I went with the approach of running the script via the node VM module. While a cleaner approach, it has the caveat that root level await in the script doesn't work. That should become available if actions#457 is completed.
1 parent ccf1a8e commit 3e76971

File tree

7 files changed

+178658
-363
lines changed

7 files changed

+178658
-363
lines changed

__test__/interpret-script.test.ts

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
3+
import {SupportedLanguage, interpretScript} from '../src/interpret-script'
4+
5+
const scripts: Record<SupportedLanguage, string> = {
6+
[SupportedLanguage.cjs]: `
7+
const FS = require('node:fs') // Proof that we are in CommonJS.
8+
var a // Proof that we are NOT in TypeScript.
9+
return foo // Proof that we executed correctly. Also, this is the pre-existing function-style syntax.
10+
`,
11+
[SupportedLanguage.cts]: `
12+
const FS = require('node:fs') // Proof that we are in CommonJS.
13+
let a: string // Proof that we are in TypeScript.
14+
exports = foo // Proof that we executed correctly.
15+
`,
16+
[SupportedLanguage.mts]: `
17+
import FS from 'node:fs' // Proof that we are in an ES Module.
18+
let a: string // Proof that we are in TypeScript.
19+
export default foo // Proof that we executed correctly.
20+
`
21+
}
22+
23+
describe(interpretScript.name, () => {
24+
describe(`language set to ${SupportedLanguage.cjs}`, () => {
25+
test(`throws when given a ${SupportedLanguage.cts} script`, async () => {
26+
return expect(
27+
interpretScript(
28+
SupportedLanguage.cjs,
29+
{foo: 'bar', require} as any,
30+
scripts.cts
31+
)
32+
).rejects
33+
})
34+
35+
test(`throws when given an ${SupportedLanguage.mts} script`, async () => {
36+
return expect(
37+
interpretScript(
38+
SupportedLanguage.cjs,
39+
{foo: 'bar', require} as any,
40+
scripts.mts
41+
)
42+
).rejects
43+
})
44+
45+
test(`interprets a ${SupportedLanguage.cjs} script`, async () => {
46+
return expect(
47+
interpretScript(
48+
SupportedLanguage.cjs,
49+
{foo: 'bar', require} as any,
50+
scripts.cjs
51+
)
52+
).resolves
53+
})
54+
55+
test(`when given a ${SupportedLanguage.cjs} script returns a function that can run it correctly`, async () => {
56+
const result = await interpretScript(
57+
SupportedLanguage.cjs,
58+
{foo: 'bar', require} as any,
59+
scripts.cjs
60+
)
61+
return expect(result()).resolves.toEqual('bar')
62+
})
63+
})
64+
65+
describe(`language set to ${SupportedLanguage.cts}`, () => {
66+
test(`throws when given a ${SupportedLanguage.cjs} script`, async () => {
67+
return expect(
68+
interpretScript(
69+
SupportedLanguage.cts,
70+
{foo: 'bar', require} as any,
71+
scripts.cjs
72+
)
73+
).rejects
74+
})
75+
76+
test(`throws when given an ${SupportedLanguage.mts} script`, async () => {
77+
return expect(
78+
interpretScript(
79+
SupportedLanguage.cts,
80+
{foo: 'bar', require} as any,
81+
scripts.mts
82+
)
83+
).rejects
84+
})
85+
86+
test(`interprets a ${SupportedLanguage.cts} script`, async () => {
87+
return expect(
88+
interpretScript(
89+
SupportedLanguage.cts,
90+
{foo: 'bar', require} as any,
91+
scripts.cts
92+
)
93+
).resolves
94+
})
95+
96+
test(`when given a ${SupportedLanguage.cts} script returns a function that can run it correctly`, async () => {
97+
const result = await interpretScript(
98+
SupportedLanguage.cts,
99+
{foo: 'bar', require} as any,
100+
scripts.cts
101+
)
102+
return expect(result()).resolves.toEqual('bar')
103+
})
104+
})
105+
106+
describe(`language set to ${SupportedLanguage.mts}`, () => {
107+
test(`throws when given a ${SupportedLanguage.cjs} script`, async () => {
108+
return expect(
109+
interpretScript(SupportedLanguage.mts, {foo: 'bar'} as any, scripts.cjs)
110+
).rejects
111+
})
112+
113+
test(`throws when given a ${SupportedLanguage.cts} script`, async () => {
114+
return expect(
115+
interpretScript(SupportedLanguage.mts, {foo: 'bar'} as any, scripts.cts)
116+
).rejects
117+
})
118+
119+
test(`interprets an ${SupportedLanguage.mts} script`, async () => {
120+
return expect(
121+
interpretScript(SupportedLanguage.mts, {foo: 'bar'} as any, scripts.mts)
122+
).resolves
123+
})
124+
125+
test(`when given an ${SupportedLanguage.mts} script returns a function that can run it correctly`, async () => {
126+
const result = await interpretScript(
127+
SupportedLanguage.mts,
128+
{foo: 'bar'} as any,
129+
scripts.mts
130+
)
131+
return expect(result()).resolves.toEqual('bar')
132+
})
133+
134+
test(`can access console`, async () => {
135+
const result = await interpretScript(
136+
SupportedLanguage.mts,
137+
{} as any,
138+
`console`
139+
)
140+
return expect(result()).resolves.toBeUndefined
141+
})
142+
143+
test(`can access process`, async () => {
144+
const result = await interpretScript(
145+
SupportedLanguage.mts,
146+
{} as any,
147+
`process`
148+
)
149+
return expect(result()).resolves.toBeUndefined
150+
})
151+
152+
test(`a script that returns an object`, async () => {
153+
const result = await interpretScript(
154+
SupportedLanguage.mts,
155+
{} as any,
156+
`export default {a: 'b'}`
157+
)
158+
return expect(result()).resolves.toEqual({a: 'b'})
159+
})
160+
161+
test.skip(`a script that uses a root level await`, async () => {
162+
// Will not work until we can actually run in ESM. Current code is transpiling the mts to cjs, so we don't get root level awaits yet.
163+
const result = await interpretScript(
164+
SupportedLanguage.mts,
165+
{} as any,
166+
`await Promise.resolve()`
167+
)
168+
return expect(result()).resolves.toBeUndefined
169+
})
170+
})
171+
})

action.yml

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ inputs:
3232
base-url:
3333
description: An optional GitHub REST API URL to connect to a different GitHub instance. For example, https://my.github-enterprise-server.com/api/v3
3434
required: false
35+
language:
36+
description: The language to interpret the script as. Pick from "cjs", "cts", "mts".
37+
default: "cjs"
3538
outputs:
3639
result:
3740
description: The return value of the script, stringified with `JSON.stringify`

0 commit comments

Comments
 (0)