Skip to content

Commit c389c72

Browse files
authoredDec 4, 2024
Add CLI (#7)
* create package * add config * impl * Add build script * Add README
1 parent ee7a24f commit c389c72

File tree

10 files changed

+664
-0
lines changed

10 files changed

+664
-0
lines changed
 

‎packages/cli/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Yusuke Yamada
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎packages/cli/README.md

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# github-script checker
2+
3+
This tool checks the type of JavaScript codes written in the script element of actions/github-script.
4+
5+
## Usage
6+
7+
### Install or use npx
8+
9+
```sh
10+
# without install
11+
$ npx -p @yamachu/github-script-checker workflow-script-highlighter <path>
12+
# with install locally
13+
$ npm install @yamachu/github-script-checker
14+
$ npx workflow-script-highlighter <path>
15+
```
16+
17+
### File format
18+
19+
Enclose the code block with ````#```typescript```` and ```` #``` ```` as shown below.
20+
21+
```yaml
22+
- uses: actions/github-script@v7
23+
with:
24+
script: | #```typescript
25+
// Here is JavaScript code
26+
#```
27+
```
28+
29+
## Example
30+
31+
.github/workflows/sample.yml
32+
33+
```yaml
34+
name: sample
35+
on: push
36+
jobs:
37+
example:
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: actions/github-script@v7
41+
with:
42+
script: | #```typescript
43+
console.log('hello')
44+
await github.rest.issues.createComment({
45+
body: 'Hello, World!',
46+
issue_number: context.issue.number,
47+
owner: context.repo.owner,
48+
repo: context.repo.repo,
49+
});
50+
#```
51+
- uses: actions/github-script@v7
52+
with:
53+
script: | #```typescript
54+
core.debug('Hello, World!');
55+
github.rest.isuees ; // oops, typo
56+
// show errors, ')' expected
57+
foo.bar(;
58+
#```
59+
```
60+
61+
Run the following command.
62+
63+
```sh
64+
$ npx -p @yamachu/github-script-checker workflow-script-highlighter .github/workflows/example.yml
65+
66+
../../sample/.github/workflows/sample.yml:24:13 - error ts(2304): Cannot find name 'foo'.
67+
68+
24 foo.bar(;
69+
~~~
70+
../../sample/.github/workflows/sample.yml:22:25 - error ts(2551): Property 'isuees' does not exist on type 'RestEndpointMethods'. Did you mean 'issues'?
71+
72+
22 github.rest.isuees ; // oops, typo
73+
~~~~~~
74+
../../sample/.github/workflows/sample.yml:24:21 - error ts(1005): ')' expected.
75+
76+
24 foo.bar(;
77+
~
78+
79+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/env node
2+
require("../dist/index.js");

‎packages/cli/package.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "@yamachu/github-script-checker",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"license": "MIT",
6+
"author": {
7+
"name": "yamachu",
8+
"url": "https://github.com/yamachu"
9+
},
10+
"bin": {
11+
"github-script-checker": "./bin/github-script-checker.js"
12+
},
13+
"files": [
14+
"bin",
15+
"dist",
16+
"resources"
17+
],
18+
"dependencies": {
19+
"@volar/kit": "^2.4.10",
20+
"@yamachu/workflow-script-highlighter-core": "*",
21+
"volar-service-typescript": "volar-2.4"
22+
}
23+
}

‎packages/cli/resources/package-lock.json

+408
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/cli/resources/package.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"dependencies": {
3+
"@types/github-script": "github:actions/github-script",
4+
"typescript": "^5.7.2"
5+
}
6+
}

‎packages/cli/scripts/build.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { build } = require("esbuild");
2+
3+
build({
4+
entryPoints: ["src/index.ts"],
5+
bundle: true,
6+
platform: "node",
7+
target: "node18",
8+
outdir: "dist",
9+
external: ["typescript"],
10+
});

‎packages/cli/src/index.ts

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import * as kit from "@volar/kit";
2+
import { gitHubScriptLanguagePlugin } from "@yamachu/workflow-script-highlighter-core/src/languagePlugin";
3+
import { readdirSync, statSync } from "node:fs";
4+
import { isAbsolute, join, resolve } from "node:path";
5+
import { ScriptTarget } from "typescript";
6+
import { create as createTypeScriptServices } from "volar-service-typescript";
7+
8+
const maybePaths = process.argv.slice(2);
9+
10+
const abortController = new AbortController();
11+
12+
process.on("SIGINT", () => {
13+
abortController.abort();
14+
process.exit(1);
15+
});
16+
17+
const getScripts = (paths: string[]) =>
18+
paths
19+
.map((path) => {
20+
if (isAbsolute(path)) {
21+
return path;
22+
}
23+
24+
return resolve(path);
25+
})
26+
.reduce<string[]>((prev, curr) => {
27+
const stat = statSync(curr);
28+
if (stat.isFile()) {
29+
return [...prev, curr];
30+
}
31+
return [...prev, ...findYamlFiles(curr)];
32+
}, []);
33+
34+
const findYamlFiles = (dir: string, fileList: string[] = []): string[] => {
35+
const files = readdirSync(dir);
36+
files.forEach((file) => {
37+
const filePath = join(dir, file);
38+
const stat = statSync(filePath);
39+
if (stat.isDirectory()) {
40+
findYamlFiles(filePath, fileList);
41+
} else if (file.endsWith(".yaml") || file.endsWith(".yml")) {
42+
fileList.push(filePath);
43+
}
44+
});
45+
return fileList;
46+
};
47+
48+
const targetFiles = getScripts(maybePaths);
49+
50+
const packageRoot = resolve(__dirname, "..", "resources", "node_modules");
51+
const tsPath = resolve(packageRoot, "typescript");
52+
53+
const checker = kit.createTypeScriptInferredChecker(
54+
[gitHubScriptLanguagePlugin],
55+
createTypeScriptServices(require(tsPath)),
56+
() => targetFiles,
57+
{
58+
typeRoots: [packageRoot],
59+
checkJs: true,
60+
target: ScriptTarget.ES2022,
61+
lib: ["ES2022"],
62+
}
63+
);
64+
65+
Promise.all(
66+
checker.getRootFileNames().map((fileName) => {
67+
return Promise.race([
68+
new Promise((_, reject) => {
69+
abortController.signal.addEventListener("abort", () => {
70+
reject();
71+
});
72+
}),
73+
checker.check(fileName).then((diagnostics) => {
74+
return [fileName, diagnostics] as const;
75+
}),
76+
] as const);
77+
})
78+
)
79+
.then((results: any[]) => {
80+
results.forEach(([fileName, diagnostics]: [string, kit.Diagnostic[]]) => {
81+
console.log(checker.printErrors(fileName, diagnostics));
82+
});
83+
})
84+
.then(() => {
85+
process.exit(0);
86+
})
87+
.catch((_) => {
88+
process.exit(1);
89+
});

‎packages/cli/tsconfig.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "out",
5+
"rootDir": "src"
6+
},
7+
"include": [
8+
"src"
9+
],
10+
}

‎yarn.lock

+16
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,17 @@
252252
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.95.0.tgz#484aee82c69fa2d73e29d4bf2a91191e570dbc70"
253253
integrity sha512-0LBD8TEiNbet3NvWsmn59zLzOFu/txSlGxnv5yAFHCrhG9WvAnR3IvfHzMOs2aeWqgvNjq9pO99IUw8d3n+unw==
254254

255+
"@volar/kit@^2.4.10":
256+
version "2.4.10"
257+
resolved "https://registry.yarnpkg.com/@volar/kit/-/kit-2.4.10.tgz#1e901a8406e6990028398bcc5883723ad150de6a"
258+
integrity sha512-ul+rLeO9RlFDgkY/FhPWMnpFqAsjvjkKz8VZeOY5YCJMwTblmmSBlNJtFNxSBx9t/k1q80nEthLyxiJ50ZbIAg==
259+
dependencies:
260+
"@volar/language-service" "2.4.10"
261+
"@volar/typescript" "2.4.10"
262+
typesafe-path "^0.2.2"
263+
vscode-languageserver-textdocument "^1.0.11"
264+
vscode-uri "^3.0.8"
265+
255266
"@volar/language-core@2.4.10", "@volar/language-core@~2.4.0":
256267
version "2.4.10"
257268
resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.4.10.tgz#7d57c29d27f7bce2fa7eb9f3a1fc053a3e28e53f"
@@ -1572,6 +1583,11 @@ typed-rest-client@^1.8.4:
15721583
tunnel "0.0.6"
15731584
underscore "^1.12.1"
15741585

1586+
typesafe-path@^0.2.2:
1587+
version "0.2.2"
1588+
resolved "https://registry.yarnpkg.com/typesafe-path/-/typesafe-path-0.2.2.tgz#91a436681b2f514badb114061b6a5e5c2b8943b1"
1589+
integrity sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==
1590+
15751591
typescript-auto-import-cache@^0.3.3:
15761592
version "0.3.5"
15771593
resolved "https://registry.yarnpkg.com/typescript-auto-import-cache/-/typescript-auto-import-cache-0.3.5.tgz#402f98995037734ef3fc208180331adfd5e495fc"

0 commit comments

Comments
 (0)
Please sign in to comment.