github-action-yaml 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/CODEOWNERS +5 -0
- package/.github/FUNDING.yml +13 -0
- package/.github/actions/setup/action.yml +32 -0
- package/.github/renovate.json +9 -0
- package/.github/workflows/changeset-for-renovate.yml +29 -0
- package/.github/workflows/check-pr.yml +43 -0
- package/.github/workflows/release.yml +56 -0
- package/.github/workflows/wait-for-workflows.yaml +18 -0
- package/.node-version +1 -0
- package/CHANGELOG.md +7 -0
- package/biome.json +29 -0
- package/dist/bin/action-yaml.cjs +106 -0
- package/dist/bin/action-yaml.cjs.map +1 -0
- package/dist/bin/action-yaml.d.cts +2 -0
- package/dist/bin/action-yaml.d.ts +2 -0
- package/dist/bin/action-yaml.js +104 -0
- package/dist/bin/action-yaml.js.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
- package/src/action-to-type.ts +80 -0
- package/src/bin/action-yaml.ts +38 -0
- package/src/index.ts +30 -0
- package/src/utils.ts +19 -0
- package/tsconfig.json +10 -0
- package/tsup.config.ts +10 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
# Changesets
|
2
|
+
|
3
|
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
4
|
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
5
|
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
6
|
+
|
7
|
+
We have a quick list of common questions to get you started engaging with this project in
|
8
|
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "https://unpkg.com/@changesets/config@3.0.3/schema.json",
|
3
|
+
"changelog": "@changesets/cli/changelog",
|
4
|
+
"commit": false,
|
5
|
+
"fixed": [],
|
6
|
+
"linked": [],
|
7
|
+
"access": "restricted",
|
8
|
+
"baseBranch": "main",
|
9
|
+
"updateInternalDependencies": "patch",
|
10
|
+
"ignore": []
|
11
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# These are supported funding model platforms
|
2
|
+
|
3
|
+
github: [YutaUra] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
4
|
+
patreon: # Replace with a single Patreon username
|
5
|
+
open_collective: # Replace with a single Open Collective username
|
6
|
+
ko_fi: # Replace with a single Ko-fi username
|
7
|
+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
8
|
+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
9
|
+
liberapay: # Replace with a single Liberapay username
|
10
|
+
issuehunt: # Replace with a single IssueHunt username
|
11
|
+
otechie: # Replace with a single Otechie username
|
12
|
+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
13
|
+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
@@ -0,0 +1,32 @@
|
|
1
|
+
name: Setup
|
2
|
+
|
3
|
+
description: |
|
4
|
+
setup fot github actions
|
5
|
+
|
6
|
+
inputs:
|
7
|
+
token:
|
8
|
+
description: The token to use for the setup.
|
9
|
+
required: true
|
10
|
+
bot-app-slug:
|
11
|
+
description: The app slug for the bot.
|
12
|
+
required: true
|
13
|
+
|
14
|
+
runs:
|
15
|
+
using: composite
|
16
|
+
steps:
|
17
|
+
- name: Setup Git User
|
18
|
+
shell: bash
|
19
|
+
run: |
|
20
|
+
user_name=${{ inputs.bot-app-slug }}[bot]
|
21
|
+
user_email=$(gh api "/users/${{ inputs.bot-app-slug }}[bot]" --jq .id)+${{ inputs.bot-app-slug }}[bot]@users.noreply.github.com
|
22
|
+
echo "Setting up git user: $user_name <$user_email>"
|
23
|
+
git config --global user.name $user_name
|
24
|
+
git config --global user.email $user_email
|
25
|
+
env:
|
26
|
+
GH_TOKEN: ${{ inputs.token }}
|
27
|
+
- uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
28
|
+
with:
|
29
|
+
node-version-file: .node-version
|
30
|
+
- name: Setup pnpm
|
31
|
+
shell: bash
|
32
|
+
run: corepack enable pnpm
|
@@ -0,0 +1,9 @@
|
|
1
|
+
{
|
2
|
+
"extends": ["github>yutaura/renovate-oss-base"],
|
3
|
+
"gitIgnoredAuthors": [
|
4
|
+
"github-actions[bot]@users.noreply.github.com",
|
5
|
+
"41898282+github-actions[bot]@users.noreply.github.com",
|
6
|
+
"yutaura-bot[bot]@users.noreply.github.com",
|
7
|
+
"179370226+yutaura-bot[bot]@users.noreply.github.com"
|
8
|
+
]
|
9
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
name: create changeset for PR created by Renovate
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
default:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
# commit author should be renovate[bot]
|
12
|
+
if: startsWith(github.head_ref, 'renovate/') && github.event.pull_request.user.login == 'renovate[bot]' && github.actor == 'renovate[bot]'
|
13
|
+
steps:
|
14
|
+
- uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
|
15
|
+
id: app-token
|
16
|
+
with:
|
17
|
+
app-id: ${{ secrets.BOT_APP_ID }}
|
18
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
19
|
+
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
|
20
|
+
with:
|
21
|
+
token: ${{ steps.app-token.outputs.token }}
|
22
|
+
- uses: ./.github/actions/setup
|
23
|
+
with:
|
24
|
+
token: ${{ steps.app-token.outputs.token }}
|
25
|
+
bot-app-slug: ${{ steps.app-token.outputs.app-slug }}
|
26
|
+
- uses: YutaUra/actions/renovate-changeset@7b5494b1dbff5ee9b4dd4610ee3daf807b473149 # v0.0.5
|
27
|
+
with:
|
28
|
+
token: ${{ steps.app-token.outputs.token }}
|
29
|
+
setup-git-user: false
|
@@ -0,0 +1,43 @@
|
|
1
|
+
name: check_PR
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
push:
|
8
|
+
branches:
|
9
|
+
- main
|
10
|
+
|
11
|
+
concurrency:
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
13
|
+
cancel-in-progress: true
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
check-pr:
|
17
|
+
runs-on: ubuntu-latest
|
18
|
+
steps:
|
19
|
+
- uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
|
20
|
+
id: app-token
|
21
|
+
with:
|
22
|
+
app-id: ${{ secrets.BOT_APP_ID }}
|
23
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
24
|
+
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
25
|
+
with:
|
26
|
+
token: ${{ steps.app-token.outputs.token }}
|
27
|
+
- uses: ./.github/actions/setup
|
28
|
+
with:
|
29
|
+
token: ${{ steps.app-token.outputs.token }}
|
30
|
+
bot-app-slug: ${{ steps.app-token.outputs.app-slug }}
|
31
|
+
|
32
|
+
- uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
33
|
+
with:
|
34
|
+
distribution: "temurin"
|
35
|
+
java-version: "17"
|
36
|
+
|
37
|
+
- run: pnpm install
|
38
|
+
- run: pnpm exec biome check --fix
|
39
|
+
|
40
|
+
- uses: int128/update-generated-files-action@757376506709ed3d87f14a80ca28a98736d52236 # v2.55.0
|
41
|
+
if: always()
|
42
|
+
with:
|
43
|
+
token: ${{ steps.app-token.outputs.token }}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
name: release
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- main
|
10
|
+
paths:
|
11
|
+
- .github/workflows/release.yml
|
12
|
+
- .github/actions/setup/**
|
13
|
+
|
14
|
+
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
15
|
+
|
16
|
+
permissions:
|
17
|
+
contents: write
|
18
|
+
pull-requests: write
|
19
|
+
|
20
|
+
jobs:
|
21
|
+
release:
|
22
|
+
name: Release
|
23
|
+
runs-on: ubuntu-latest
|
24
|
+
steps:
|
25
|
+
- uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
|
26
|
+
id: app-token
|
27
|
+
with:
|
28
|
+
app-id: ${{ secrets.BOT_APP_ID }}
|
29
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
30
|
+
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
31
|
+
with:
|
32
|
+
token: ${{ steps.app-token.outputs.token }}
|
33
|
+
- uses: ./.github/actions/setup
|
34
|
+
with:
|
35
|
+
token: ${{ steps.app-token.outputs.token }}
|
36
|
+
bot-app-slug: ${{ steps.app-token.outputs.app-slug }}
|
37
|
+
|
38
|
+
- name: Install Dependencies
|
39
|
+
run: pnpm install
|
40
|
+
|
41
|
+
- name: Create Release Pull Request or Publish to npm
|
42
|
+
id: changesets
|
43
|
+
if: github.event_name == 'push'
|
44
|
+
uses: changesets/action@v1
|
45
|
+
with:
|
46
|
+
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
47
|
+
publish: pnpm publish
|
48
|
+
setupGitUser: false
|
49
|
+
env:
|
50
|
+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
51
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
52
|
+
|
53
|
+
- if: ${{ steps.changesets.outputs.pullRequestNumber != '' }}
|
54
|
+
run: gh pr merge --merge --auto "${{ steps.changesets.outputs.pullRequestNumber}}"
|
55
|
+
env:
|
56
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
name: wait-for-workflows
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
wait-for-workflows:
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
timeout-minutes: 30
|
10
|
+
steps:
|
11
|
+
- uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
|
12
|
+
id: app-token
|
13
|
+
with:
|
14
|
+
app-id: ${{ secrets.BOT_APP_ID }}
|
15
|
+
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
|
16
|
+
- uses: int128/wait-for-workflows-action@a1d37b9f6c1b3a092780ec646297224afc9faf5a # v1.26.0
|
17
|
+
with:
|
18
|
+
token: ${{ steps.app-token.outputs.token }}
|
package/.node-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
20.18.0
|
package/CHANGELOG.md
ADDED
package/biome.json
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
3
|
+
"vcs": {
|
4
|
+
"enabled": true,
|
5
|
+
"clientKind": "git",
|
6
|
+
"useIgnoreFile": true
|
7
|
+
},
|
8
|
+
"formatter": {
|
9
|
+
"enabled": true,
|
10
|
+
"indentStyle": "space"
|
11
|
+
},
|
12
|
+
"organizeImports": {
|
13
|
+
"enabled": true
|
14
|
+
},
|
15
|
+
"linter": {
|
16
|
+
"enabled": true,
|
17
|
+
"rules": {
|
18
|
+
"recommended": true
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"javascript": {
|
22
|
+
"formatter": {
|
23
|
+
"quoteStyle": "double"
|
24
|
+
}
|
25
|
+
},
|
26
|
+
"files": {
|
27
|
+
"ignore": ["generated/**"]
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
// src/bin/action-yaml.ts
|
4
|
+
var import_promises2 = require("fs/promises");
|
5
|
+
var import_node_path = require("path");
|
6
|
+
var import_commander = require("commander");
|
7
|
+
var import_yaml = require("yaml");
|
8
|
+
|
9
|
+
// src/action-to-type.ts
|
10
|
+
var actionToType = (action) => {
|
11
|
+
const actionInputs = action.inputs ?? {};
|
12
|
+
const inputsType = `export type Inputs<T extends InputOptions<typeof raw> = InputOptions<typeof raw>, V extends InputsValues<typeof raw, T> = InputsValues<typeof raw,T>> = {
|
13
|
+
${Object.entries(actionInputs ?? {}).map(
|
14
|
+
([key, value]) => ` /**
|
15
|
+
* ${value.description}
|
16
|
+
*
|
17
|
+
${value.default ? ` * @default ${value.default}
|
18
|
+
` : ""}${value.deprecationMessage ? ` * @deprecated ${value.deprecationMessage}
|
19
|
+
` : ""} */
|
20
|
+
'${key}'${value.required || typeof value.default !== "undefined" ? "" : "?"}: V["${key}"];`
|
21
|
+
).join("\n")}
|
22
|
+
}`;
|
23
|
+
const outputsType = `export type Outputs = {
|
24
|
+
${Object.entries(
|
25
|
+
action.outputs ?? {}
|
26
|
+
).map(
|
27
|
+
([key, value]) => ` /**
|
28
|
+
* ${value.description}
|
29
|
+
*
|
30
|
+
*/
|
31
|
+
'${key}'?: string;`
|
32
|
+
).join("\n")}
|
33
|
+
}`;
|
34
|
+
const parseInputs = `const getInput = {
|
35
|
+
string: core.getInput,
|
36
|
+
boolean: core.getBooleanInput,
|
37
|
+
multiline: core.getMultilineInput,
|
38
|
+
};
|
39
|
+
|
40
|
+
export const parseInputs = <T extends InputOptions<typeof raw>>(options?: T): Prettify<Inputs<T>> => {
|
41
|
+
return {
|
42
|
+
${Object.keys(actionInputs ?? {}).map(
|
43
|
+
(key) => ` "${key}": getInput[options?.["${key}"]?.type ?? "string"]("${key}", {trimWhitespace: options?.cwd?.trimWhitespace}),`
|
44
|
+
).join("\n")}
|
45
|
+
} as Inputs<T>;
|
46
|
+
}`;
|
47
|
+
const dumpOutputs = `export const dumpOutputs = (outputs: Partial<Outputs>) => {
|
48
|
+
for (const [name, value] of Object.entries(outputs)) {
|
49
|
+
core.setOutput(name, value)
|
50
|
+
}
|
51
|
+
}`;
|
52
|
+
return `// @ts-ignore
|
53
|
+
import * as core from "@github/core";
|
54
|
+
import { Prettify, InputOptions, InputsValues } from "github-action-yaml"
|
55
|
+
|
56
|
+
export const raw = ${JSON.stringify(action, null, 2)} as const;
|
57
|
+
|
58
|
+
${inputsType}
|
59
|
+
|
60
|
+
${outputsType}
|
61
|
+
|
62
|
+
${parseInputs}
|
63
|
+
|
64
|
+
${dumpOutputs}
|
65
|
+
`;
|
66
|
+
};
|
67
|
+
|
68
|
+
// src/utils.ts
|
69
|
+
var import_promises = require("fs/promises");
|
70
|
+
function isUrl(input) {
|
71
|
+
try {
|
72
|
+
const url = new URL(input);
|
73
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
74
|
+
} catch {
|
75
|
+
return false;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
var universalReadFile = async (path) => {
|
79
|
+
if (isUrl(path)) {
|
80
|
+
const response = await fetch(path);
|
81
|
+
return response.text();
|
82
|
+
}
|
83
|
+
const file = await (0, import_promises.readFile)(path, "utf-8");
|
84
|
+
return file;
|
85
|
+
};
|
86
|
+
|
87
|
+
// src/bin/action-yaml.ts
|
88
|
+
var program = new import_commander.Command();
|
89
|
+
program.name("generate").description("generate typescript code from action.yaml file").argument("<file>", "output typescript file").option("-i, --input <file>", "input action.yaml file", "action.yml").option("--watch", "watch mode", false).action(async (file, options) => {
|
90
|
+
const yaml = (0, import_yaml.parse)(await universalReadFile(options.input));
|
91
|
+
await (0, import_promises2.mkdir)((0, import_node_path.dirname)(file), { recursive: true });
|
92
|
+
await (0, import_promises2.writeFile)(file, actionToType(yaml));
|
93
|
+
if (!options.watch) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
for await (const _ of (0, import_promises2.watch)(options.input)) {
|
97
|
+
const yaml2 = (0, import_yaml.parse)(
|
98
|
+
await universalReadFile(options.input)
|
99
|
+
);
|
100
|
+
await (0, import_promises2.mkdir)((0, import_node_path.dirname)(file), { recursive: true });
|
101
|
+
await (0, import_promises2.writeFile)(file, actionToType(yaml2));
|
102
|
+
console.log("Updated", file);
|
103
|
+
}
|
104
|
+
});
|
105
|
+
program.parse();
|
106
|
+
//# sourceMappingURL=action-yaml.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/bin/action-yaml.ts","../../src/action-to-type.ts","../../src/utils.ts"],"sourcesContent":["import { mkdir, watch, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { GithubAction } from \"@schemastore/github-action\";\nimport { Command } from \"commander\";\nimport { parse } from \"yaml\";\nimport { actionToType } from \"../action-to-type\";\nimport { universalReadFile } from \"../utils\";\n\nconst program = new Command();\n\nprogram\n .name(\"generate\")\n .description(\"generate typescript code from action.yaml file\")\n .argument(\"<file>\", \"output typescript file\")\n .option(\"-i, --input <file>\", \"input action.yaml file\", \"action.yml\")\n .option(\"--watch\", \"watch mode\", false)\n .action(async (file: string, options: { input: string; watch: boolean }) => {\n const yaml = parse(await universalReadFile(options.input)) as GithubAction;\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, actionToType(yaml));\n\n if (!options.watch) {\n return;\n }\n\n for await (const _ of watch(options.input)) {\n const yaml = parse(\n await universalReadFile(options.input),\n ) as GithubAction;\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, actionToType(yaml));\n console.log(\"Updated\", file);\n }\n });\n\nprogram.parse();\n","import type { GithubAction } from \"@schemastore/github-action\";\n\nexport const actionToType = (action: GithubAction) => {\n const actionInputs = action.inputs ?? {};\n\n const inputsType = `\\\nexport type Inputs<T extends InputOptions<typeof raw> = InputOptions<typeof raw>, V extends InputsValues<typeof raw, T> = InputsValues<typeof raw,T>> = {\n${Object.entries(actionInputs ?? {})\n .map(\n ([key, value]) => `\\\n /**\n * ${value.description}\n * \n${value.default ? ` * @default ${value.default}\\n` : \"\"}\\\n${value.deprecationMessage ? ` * @deprecated ${value.deprecationMessage}\\n` : \"\"}\\\n */\n '${key}'${value.required || typeof value.default !== \"undefined\" ? \"\" : \"?\"}: V[\"${key}\"];\\\n`,\n )\n .join(\"\\n\")}\n}`;\n\n const outputsType = `\\\nexport type Outputs = {\n${Object.entries(\n (action.outputs as Record<string, { description?: string }>) ?? {},\n)\n .map(\n ([key, value]) => `\\\n /**\n * ${value.description}\n * \n */\n '${key}'?: string;\\\n`,\n )\n .join(\"\\n\")}\n}`;\n\n const parseInputs = `\\\nconst getInput = {\n string: core.getInput,\n boolean: core.getBooleanInput,\n multiline: core.getMultilineInput,\n};\n\nexport const parseInputs = <T extends InputOptions<typeof raw>>(options?: T): Prettify<Inputs<T>> => {\n return {\n${Object.keys(actionInputs ?? {})\n .map(\n (key) =>\n ` \"${key}\": getInput[options?.[\"${key}\"]?.type ?? \"string\"](\"${key}\", {trimWhitespace: options?.cwd?.trimWhitespace}),`,\n )\n .join(\"\\n\")}\n } as Inputs<T>;\n}`;\n\n const dumpOutputs = `\\\nexport const dumpOutputs = (outputs: Partial<Outputs>) => {\n for (const [name, value] of Object.entries(outputs)) {\n core.setOutput(name, value)\n }\n}`;\n\n return `\\\n// @ts-ignore\nimport * as core from \"@github/core\";\nimport { Prettify, InputOptions, InputsValues } from \"github-action-yaml\"\n\nexport const raw = ${JSON.stringify(action, null, 2)} as const;\n\n${inputsType}\n\n${outputsType}\n\n${parseInputs}\n\n${dumpOutputs}\n`;\n};\n","import { readFile } from \"node:fs/promises\";\n\nfunction isUrl(input: string): boolean {\n try {\n const url = new URL(input);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport const universalReadFile = async (path: string) => {\n if (isUrl(path)) {\n const response = await fetch(path);\n return response.text();\n }\n const file = await readFile(path, \"utf-8\");\n return file;\n};\n"],"mappings":";;;AAAA,IAAAA,mBAAwC;AACxC,uBAAwB;AAExB,uBAAwB;AACxB,kBAAsB;;;ACFf,IAAM,eAAe,CAAC,WAAyB;AACpD,QAAM,eAAe,OAAO,UAAU,CAAC;AAEvC,QAAM,aAAa;AAAA,EAEnB,OAAO,QAAQ,gBAAgB,CAAC,CAAC,EAChC;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,OAEf,MAAM,WAAW;AAAA;AAAA,EAEtB,MAAM,UAAU,iBAAiB,MAAM,OAAO;AAAA,IAAO,EAAE,GACvD,MAAM,qBAAqB,oBAAoB,MAAM,kBAAkB;AAAA,IAAO,EAAE;AAAA,KAE7E,GAAG,IAAI,MAAM,YAAY,OAAO,MAAM,YAAY,cAAc,KAAK,GAAG,QAAQ,GAAG;AAAA,EAEtF,EACC,KAAK,IAAI,CAAC;AAAA;AAGX,QAAM,cAAc;AAAA,EAEpB,OAAO;AAAA,IACN,OAAO,WAAwD,CAAC;AAAA,EACnE,EACG;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,OAEf,MAAM,WAAW;AAAA;AAAA;AAAA,KAGnB,GAAG;AAAA,EAEN,EACC,KAAK,IAAI,CAAC;AAAA;AAGX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASpB,OAAO,KAAK,gBAAgB,CAAC,CAAC,EAC7B;AAAA,IACC,CAAC,QACC,QAAQ,GAAG,0BAA0B,GAAG,0BAA0B,GAAG;AAAA,EACzE,EACC,KAAK,IAAI,CAAC;AAAA;AAAA;AAIX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAOpB,SAAO;AAAA;AAAA;AAAA;AAAA,qBAKY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA,EAElD,UAAU;AAAA;AAAA,EAEV,WAAW;AAAA;AAAA,EAEX,WAAW;AAAA;AAAA,EAEX,WAAW;AAAA;AAEb;;;AC/EA,sBAAyB;AAEzB,SAAS,MAAM,OAAwB;AACrC,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO,IAAI,aAAa,WAAW,IAAI,aAAa;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,oBAAoB,OAAO,SAAiB;AACvD,MAAI,MAAM,IAAI,GAAG;AACf,UAAM,WAAW,MAAM,MAAM,IAAI;AACjC,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,QAAM,OAAO,UAAM,0BAAS,MAAM,OAAO;AACzC,SAAO;AACT;;;AFVA,IAAM,UAAU,IAAI,yBAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,gDAAgD,EAC5D,SAAS,UAAU,wBAAwB,EAC3C,OAAO,sBAAsB,0BAA0B,YAAY,EACnE,OAAO,WAAW,cAAc,KAAK,EACrC,OAAO,OAAO,MAAc,YAA+C;AAC1E,QAAM,WAAO,mBAAM,MAAM,kBAAkB,QAAQ,KAAK,CAAC;AAEzD,YAAM,4BAAM,0BAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,YAAM,4BAAU,MAAM,aAAa,IAAI,CAAC;AAExC,MAAI,CAAC,QAAQ,OAAO;AAClB;AAAA,EACF;AAEA,mBAAiB,SAAK,wBAAM,QAAQ,KAAK,GAAG;AAC1C,UAAMC,YAAO;AAAA,MACX,MAAM,kBAAkB,QAAQ,KAAK;AAAA,IACvC;AAEA,cAAM,4BAAM,0BAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,cAAM,4BAAU,MAAM,aAAaA,KAAI,CAAC;AACxC,YAAQ,IAAI,WAAW,IAAI;AAAA,EAC7B;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["import_promises","yaml"]}
|
@@ -0,0 +1,104 @@
|
|
1
|
+
// src/bin/action-yaml.ts
|
2
|
+
import { mkdir, watch, writeFile } from "node:fs/promises";
|
3
|
+
import { dirname } from "node:path";
|
4
|
+
import { Command } from "commander";
|
5
|
+
import { parse } from "yaml";
|
6
|
+
|
7
|
+
// src/action-to-type.ts
|
8
|
+
var actionToType = (action) => {
|
9
|
+
const actionInputs = action.inputs ?? {};
|
10
|
+
const inputsType = `export type Inputs<T extends InputOptions<typeof raw> = InputOptions<typeof raw>, V extends InputsValues<typeof raw, T> = InputsValues<typeof raw,T>> = {
|
11
|
+
${Object.entries(actionInputs ?? {}).map(
|
12
|
+
([key, value]) => ` /**
|
13
|
+
* ${value.description}
|
14
|
+
*
|
15
|
+
${value.default ? ` * @default ${value.default}
|
16
|
+
` : ""}${value.deprecationMessage ? ` * @deprecated ${value.deprecationMessage}
|
17
|
+
` : ""} */
|
18
|
+
'${key}'${value.required || typeof value.default !== "undefined" ? "" : "?"}: V["${key}"];`
|
19
|
+
).join("\n")}
|
20
|
+
}`;
|
21
|
+
const outputsType = `export type Outputs = {
|
22
|
+
${Object.entries(
|
23
|
+
action.outputs ?? {}
|
24
|
+
).map(
|
25
|
+
([key, value]) => ` /**
|
26
|
+
* ${value.description}
|
27
|
+
*
|
28
|
+
*/
|
29
|
+
'${key}'?: string;`
|
30
|
+
).join("\n")}
|
31
|
+
}`;
|
32
|
+
const parseInputs = `const getInput = {
|
33
|
+
string: core.getInput,
|
34
|
+
boolean: core.getBooleanInput,
|
35
|
+
multiline: core.getMultilineInput,
|
36
|
+
};
|
37
|
+
|
38
|
+
export const parseInputs = <T extends InputOptions<typeof raw>>(options?: T): Prettify<Inputs<T>> => {
|
39
|
+
return {
|
40
|
+
${Object.keys(actionInputs ?? {}).map(
|
41
|
+
(key) => ` "${key}": getInput[options?.["${key}"]?.type ?? "string"]("${key}", {trimWhitespace: options?.cwd?.trimWhitespace}),`
|
42
|
+
).join("\n")}
|
43
|
+
} as Inputs<T>;
|
44
|
+
}`;
|
45
|
+
const dumpOutputs = `export const dumpOutputs = (outputs: Partial<Outputs>) => {
|
46
|
+
for (const [name, value] of Object.entries(outputs)) {
|
47
|
+
core.setOutput(name, value)
|
48
|
+
}
|
49
|
+
}`;
|
50
|
+
return `// @ts-ignore
|
51
|
+
import * as core from "@github/core";
|
52
|
+
import { Prettify, InputOptions, InputsValues } from "github-action-yaml"
|
53
|
+
|
54
|
+
export const raw = ${JSON.stringify(action, null, 2)} as const;
|
55
|
+
|
56
|
+
${inputsType}
|
57
|
+
|
58
|
+
${outputsType}
|
59
|
+
|
60
|
+
${parseInputs}
|
61
|
+
|
62
|
+
${dumpOutputs}
|
63
|
+
`;
|
64
|
+
};
|
65
|
+
|
66
|
+
// src/utils.ts
|
67
|
+
import { readFile } from "node:fs/promises";
|
68
|
+
function isUrl(input) {
|
69
|
+
try {
|
70
|
+
const url = new URL(input);
|
71
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
72
|
+
} catch {
|
73
|
+
return false;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
var universalReadFile = async (path) => {
|
77
|
+
if (isUrl(path)) {
|
78
|
+
const response = await fetch(path);
|
79
|
+
return response.text();
|
80
|
+
}
|
81
|
+
const file = await readFile(path, "utf-8");
|
82
|
+
return file;
|
83
|
+
};
|
84
|
+
|
85
|
+
// src/bin/action-yaml.ts
|
86
|
+
var program = new Command();
|
87
|
+
program.name("generate").description("generate typescript code from action.yaml file").argument("<file>", "output typescript file").option("-i, --input <file>", "input action.yaml file", "action.yml").option("--watch", "watch mode", false).action(async (file, options) => {
|
88
|
+
const yaml = parse(await universalReadFile(options.input));
|
89
|
+
await mkdir(dirname(file), { recursive: true });
|
90
|
+
await writeFile(file, actionToType(yaml));
|
91
|
+
if (!options.watch) {
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
for await (const _ of watch(options.input)) {
|
95
|
+
const yaml2 = parse(
|
96
|
+
await universalReadFile(options.input)
|
97
|
+
);
|
98
|
+
await mkdir(dirname(file), { recursive: true });
|
99
|
+
await writeFile(file, actionToType(yaml2));
|
100
|
+
console.log("Updated", file);
|
101
|
+
}
|
102
|
+
});
|
103
|
+
program.parse();
|
104
|
+
//# sourceMappingURL=action-yaml.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/bin/action-yaml.ts","../../src/action-to-type.ts","../../src/utils.ts"],"sourcesContent":["import { mkdir, watch, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { GithubAction } from \"@schemastore/github-action\";\nimport { Command } from \"commander\";\nimport { parse } from \"yaml\";\nimport { actionToType } from \"../action-to-type\";\nimport { universalReadFile } from \"../utils\";\n\nconst program = new Command();\n\nprogram\n .name(\"generate\")\n .description(\"generate typescript code from action.yaml file\")\n .argument(\"<file>\", \"output typescript file\")\n .option(\"-i, --input <file>\", \"input action.yaml file\", \"action.yml\")\n .option(\"--watch\", \"watch mode\", false)\n .action(async (file: string, options: { input: string; watch: boolean }) => {\n const yaml = parse(await universalReadFile(options.input)) as GithubAction;\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, actionToType(yaml));\n\n if (!options.watch) {\n return;\n }\n\n for await (const _ of watch(options.input)) {\n const yaml = parse(\n await universalReadFile(options.input),\n ) as GithubAction;\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, actionToType(yaml));\n console.log(\"Updated\", file);\n }\n });\n\nprogram.parse();\n","import type { GithubAction } from \"@schemastore/github-action\";\n\nexport const actionToType = (action: GithubAction) => {\n const actionInputs = action.inputs ?? {};\n\n const inputsType = `\\\nexport type Inputs<T extends InputOptions<typeof raw> = InputOptions<typeof raw>, V extends InputsValues<typeof raw, T> = InputsValues<typeof raw,T>> = {\n${Object.entries(actionInputs ?? {})\n .map(\n ([key, value]) => `\\\n /**\n * ${value.description}\n * \n${value.default ? ` * @default ${value.default}\\n` : \"\"}\\\n${value.deprecationMessage ? ` * @deprecated ${value.deprecationMessage}\\n` : \"\"}\\\n */\n '${key}'${value.required || typeof value.default !== \"undefined\" ? \"\" : \"?\"}: V[\"${key}\"];\\\n`,\n )\n .join(\"\\n\")}\n}`;\n\n const outputsType = `\\\nexport type Outputs = {\n${Object.entries(\n (action.outputs as Record<string, { description?: string }>) ?? {},\n)\n .map(\n ([key, value]) => `\\\n /**\n * ${value.description}\n * \n */\n '${key}'?: string;\\\n`,\n )\n .join(\"\\n\")}\n}`;\n\n const parseInputs = `\\\nconst getInput = {\n string: core.getInput,\n boolean: core.getBooleanInput,\n multiline: core.getMultilineInput,\n};\n\nexport const parseInputs = <T extends InputOptions<typeof raw>>(options?: T): Prettify<Inputs<T>> => {\n return {\n${Object.keys(actionInputs ?? {})\n .map(\n (key) =>\n ` \"${key}\": getInput[options?.[\"${key}\"]?.type ?? \"string\"](\"${key}\", {trimWhitespace: options?.cwd?.trimWhitespace}),`,\n )\n .join(\"\\n\")}\n } as Inputs<T>;\n}`;\n\n const dumpOutputs = `\\\nexport const dumpOutputs = (outputs: Partial<Outputs>) => {\n for (const [name, value] of Object.entries(outputs)) {\n core.setOutput(name, value)\n }\n}`;\n\n return `\\\n// @ts-ignore\nimport * as core from \"@github/core\";\nimport { Prettify, InputOptions, InputsValues } from \"github-action-yaml\"\n\nexport const raw = ${JSON.stringify(action, null, 2)} as const;\n\n${inputsType}\n\n${outputsType}\n\n${parseInputs}\n\n${dumpOutputs}\n`;\n};\n","import { readFile } from \"node:fs/promises\";\n\nfunction isUrl(input: string): boolean {\n try {\n const url = new URL(input);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport const universalReadFile = async (path: string) => {\n if (isUrl(path)) {\n const response = await fetch(path);\n return response.text();\n }\n const file = await readFile(path, \"utf-8\");\n return file;\n};\n"],"mappings":";AAAA,SAAS,OAAO,OAAO,iBAAiB;AACxC,SAAS,eAAe;AAExB,SAAS,eAAe;AACxB,SAAS,aAAa;;;ACFf,IAAM,eAAe,CAAC,WAAyB;AACpD,QAAM,eAAe,OAAO,UAAU,CAAC;AAEvC,QAAM,aAAa;AAAA,EAEnB,OAAO,QAAQ,gBAAgB,CAAC,CAAC,EAChC;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,OAEf,MAAM,WAAW;AAAA;AAAA,EAEtB,MAAM,UAAU,iBAAiB,MAAM,OAAO;AAAA,IAAO,EAAE,GACvD,MAAM,qBAAqB,oBAAoB,MAAM,kBAAkB;AAAA,IAAO,EAAE;AAAA,KAE7E,GAAG,IAAI,MAAM,YAAY,OAAO,MAAM,YAAY,cAAc,KAAK,GAAG,QAAQ,GAAG;AAAA,EAEtF,EACC,KAAK,IAAI,CAAC;AAAA;AAGX,QAAM,cAAc;AAAA,EAEpB,OAAO;AAAA,IACN,OAAO,WAAwD,CAAC;AAAA,EACnE,EACG;AAAA,IACC,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,OAEf,MAAM,WAAW;AAAA;AAAA;AAAA,KAGnB,GAAG;AAAA,EAEN,EACC,KAAK,IAAI,CAAC;AAAA;AAGX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASpB,OAAO,KAAK,gBAAgB,CAAC,CAAC,EAC7B;AAAA,IACC,CAAC,QACC,QAAQ,GAAG,0BAA0B,GAAG,0BAA0B,GAAG;AAAA,EACzE,EACC,KAAK,IAAI,CAAC;AAAA;AAAA;AAIX,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAOpB,SAAO;AAAA;AAAA;AAAA;AAAA,qBAKY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA;AAAA,EAElD,UAAU;AAAA;AAAA,EAEV,WAAW;AAAA;AAAA,EAEX,WAAW;AAAA;AAAA,EAEX,WAAW;AAAA;AAEb;;;AC/EA,SAAS,gBAAgB;AAEzB,SAAS,MAAM,OAAwB;AACrC,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,WAAO,IAAI,aAAa,WAAW,IAAI,aAAa;AAAA,EACtD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,oBAAoB,OAAO,SAAiB;AACvD,MAAI,MAAM,IAAI,GAAG;AACf,UAAM,WAAW,MAAM,MAAM,IAAI;AACjC,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,QAAM,OAAO,MAAM,SAAS,MAAM,OAAO;AACzC,SAAO;AACT;;;AFVA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,UAAU,EACf,YAAY,gDAAgD,EAC5D,SAAS,UAAU,wBAAwB,EAC3C,OAAO,sBAAsB,0BAA0B,YAAY,EACnE,OAAO,WAAW,cAAc,KAAK,EACrC,OAAO,OAAO,MAAc,YAA+C;AAC1E,QAAM,OAAO,MAAM,MAAM,kBAAkB,QAAQ,KAAK,CAAC;AAEzD,QAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAM,UAAU,MAAM,aAAa,IAAI,CAAC;AAExC,MAAI,CAAC,QAAQ,OAAO;AAClB;AAAA,EACF;AAEA,mBAAiB,KAAK,MAAM,QAAQ,KAAK,GAAG;AAC1C,UAAMA,QAAO;AAAA,MACX,MAAM,kBAAkB,QAAQ,KAAK;AAAA,IACvC;AAEA,UAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAM,UAAU,MAAM,aAAaA,KAAI,CAAC;AACxC,YAAQ,IAAI,WAAW,IAAI;AAAA,EAC7B;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["yaml"]}
|
package/dist/index.cjs
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __defProp = Object.defineProperty;
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
8
|
+
for (let key of __getOwnPropNames(from))
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
11
|
+
}
|
12
|
+
return to;
|
13
|
+
};
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
15
|
+
|
16
|
+
// src/index.ts
|
17
|
+
var src_exports = {};
|
18
|
+
module.exports = __toCommonJS(src_exports);
|
19
|
+
//# sourceMappingURL=index.cjs.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { GithubAction as RawGitHubAction } from \"@schemastore/github-action\";\n\nexport type GithubAction = Omit<RawGitHubAction, \"runs\">;\n\nexport type Prettify<Type> = {\n [Key in keyof Type]: Type[Key];\n} & {};\n\ntype InputsKeys<T extends GithubAction> = keyof T[\"inputs\"];\n\ntype InputOption = {\n type?: \"boolean\" | \"multiline\" | \"string\";\n trimWhitespace?: boolean;\n};\n\nexport type InputOptions<T extends GithubAction> = Partial<\n Record<InputsKeys<T>, InputOption>\n>;\nexport type InputsValues<\n Action extends GithubAction,\n Option extends InputOptions<Action> = InputOptions<Action>,\n> = {\n [K in InputsKeys<Action>]: Option[K] extends { type: infer V }\n ? V extends \"boolean\"\n ? boolean\n : V extends \"multiline\"\n ? string[]\n : string\n : string;\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/index.d.cts
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import { GithubAction as GithubAction$1 } from '@schemastore/github-action';
|
2
|
+
|
3
|
+
type GithubAction = Omit<GithubAction$1, "runs">;
|
4
|
+
type Prettify<Type> = {
|
5
|
+
[Key in keyof Type]: Type[Key];
|
6
|
+
} & {};
|
7
|
+
type InputsKeys<T extends GithubAction> = keyof T["inputs"];
|
8
|
+
type InputOption = {
|
9
|
+
type?: "boolean" | "multiline" | "string";
|
10
|
+
trimWhitespace?: boolean;
|
11
|
+
};
|
12
|
+
type InputOptions<T extends GithubAction> = Partial<Record<InputsKeys<T>, InputOption>>;
|
13
|
+
type InputsValues<Action extends GithubAction, Option extends InputOptions<Action> = InputOptions<Action>> = {
|
14
|
+
[K in InputsKeys<Action>]: Option[K] extends {
|
15
|
+
type: infer V;
|
16
|
+
} ? V extends "boolean" ? boolean : V extends "multiline" ? string[] : string : string;
|
17
|
+
};
|
18
|
+
|
19
|
+
export type { GithubAction, InputOptions, InputsValues, Prettify };
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import { GithubAction as GithubAction$1 } from '@schemastore/github-action';
|
2
|
+
|
3
|
+
type GithubAction = Omit<GithubAction$1, "runs">;
|
4
|
+
type Prettify<Type> = {
|
5
|
+
[Key in keyof Type]: Type[Key];
|
6
|
+
} & {};
|
7
|
+
type InputsKeys<T extends GithubAction> = keyof T["inputs"];
|
8
|
+
type InputOption = {
|
9
|
+
type?: "boolean" | "multiline" | "string";
|
10
|
+
trimWhitespace?: boolean;
|
11
|
+
};
|
12
|
+
type InputOptions<T extends GithubAction> = Partial<Record<InputsKeys<T>, InputOption>>;
|
13
|
+
type InputsValues<Action extends GithubAction, Option extends InputOptions<Action> = InputOptions<Action>> = {
|
14
|
+
[K in InputsKeys<Action>]: Option[K] extends {
|
15
|
+
type: infer V;
|
16
|
+
} ? V extends "boolean" ? boolean : V extends "multiline" ? string[] : string : string;
|
17
|
+
};
|
18
|
+
|
19
|
+
export type { GithubAction, InputOptions, InputsValues, Prettify };
|
package/dist/index.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
{
|
2
|
+
"name": "github-action-yaml",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"type": "module",
|
5
|
+
"bin": {
|
6
|
+
"github-action-yaml": "./dist/bin/action-yaml.js"
|
7
|
+
},
|
8
|
+
"main": "./dist/index.cjs",
|
9
|
+
"module": "./dist/index.js",
|
10
|
+
"types": "./dist/index.d.ts",
|
11
|
+
"keywords": [],
|
12
|
+
"author": "YutaUra",
|
13
|
+
"license": "ISC",
|
14
|
+
"devDependencies": {
|
15
|
+
"@actions/core": "1.11.1",
|
16
|
+
"@biomejs/biome": "1.9.3",
|
17
|
+
"@changesets/cli": "2.27.9",
|
18
|
+
"@tsconfig/strictest": "2.0.5",
|
19
|
+
"@types/node": "22.7.5",
|
20
|
+
"rimraf": "6.0.1",
|
21
|
+
"tsup": "8.3.0",
|
22
|
+
"tsx": "4.19.1",
|
23
|
+
"typescript": "5.6.3"
|
24
|
+
},
|
25
|
+
"dependencies": {
|
26
|
+
"@schemastore/github-action": "0.0.5",
|
27
|
+
"commander": "12.1.0",
|
28
|
+
"yaml": "2.5.1"
|
29
|
+
},
|
30
|
+
"peerDependencies": {
|
31
|
+
"@actions/core": "1.11.1"
|
32
|
+
},
|
33
|
+
"scripts": {
|
34
|
+
"build": "tsup",
|
35
|
+
"prepublish": "pnpm run build"
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import type { GithubAction } from "@schemastore/github-action";
|
2
|
+
|
3
|
+
export const actionToType = (action: GithubAction) => {
|
4
|
+
const actionInputs = action.inputs ?? {};
|
5
|
+
|
6
|
+
const inputsType = `\
|
7
|
+
export type Inputs<T extends InputOptions<typeof raw> = InputOptions<typeof raw>, V extends InputsValues<typeof raw, T> = InputsValues<typeof raw,T>> = {
|
8
|
+
${Object.entries(actionInputs ?? {})
|
9
|
+
.map(
|
10
|
+
([key, value]) => `\
|
11
|
+
/**
|
12
|
+
* ${value.description}
|
13
|
+
*
|
14
|
+
${value.default ? ` * @default ${value.default}\n` : ""}\
|
15
|
+
${value.deprecationMessage ? ` * @deprecated ${value.deprecationMessage}\n` : ""}\
|
16
|
+
*/
|
17
|
+
'${key}'${value.required || typeof value.default !== "undefined" ? "" : "?"}: V["${key}"];\
|
18
|
+
`,
|
19
|
+
)
|
20
|
+
.join("\n")}
|
21
|
+
}`;
|
22
|
+
|
23
|
+
const outputsType = `\
|
24
|
+
export type Outputs = {
|
25
|
+
${Object.entries(
|
26
|
+
(action.outputs as Record<string, { description?: string }>) ?? {},
|
27
|
+
)
|
28
|
+
.map(
|
29
|
+
([key, value]) => `\
|
30
|
+
/**
|
31
|
+
* ${value.description}
|
32
|
+
*
|
33
|
+
*/
|
34
|
+
'${key}'?: string;\
|
35
|
+
`,
|
36
|
+
)
|
37
|
+
.join("\n")}
|
38
|
+
}`;
|
39
|
+
|
40
|
+
const parseInputs = `\
|
41
|
+
const getInput = {
|
42
|
+
string: core.getInput,
|
43
|
+
boolean: core.getBooleanInput,
|
44
|
+
multiline: core.getMultilineInput,
|
45
|
+
};
|
46
|
+
|
47
|
+
export const parseInputs = <T extends InputOptions<typeof raw>>(options?: T): Prettify<Inputs<T>> => {
|
48
|
+
return {
|
49
|
+
${Object.keys(actionInputs ?? {})
|
50
|
+
.map(
|
51
|
+
(key) =>
|
52
|
+
` "${key}": getInput[options?.["${key}"]?.type ?? "string"]("${key}", {trimWhitespace: options?.cwd?.trimWhitespace}),`,
|
53
|
+
)
|
54
|
+
.join("\n")}
|
55
|
+
} as Inputs<T>;
|
56
|
+
}`;
|
57
|
+
|
58
|
+
const dumpOutputs = `\
|
59
|
+
export const dumpOutputs = (outputs: Partial<Outputs>) => {
|
60
|
+
for (const [name, value] of Object.entries(outputs)) {
|
61
|
+
core.setOutput(name, value)
|
62
|
+
}
|
63
|
+
}`;
|
64
|
+
|
65
|
+
return `\
|
66
|
+
// @ts-ignore
|
67
|
+
import * as core from "@github/core";
|
68
|
+
import { Prettify, InputOptions, InputsValues } from "github-action-yaml"
|
69
|
+
|
70
|
+
export const raw = ${JSON.stringify(action, null, 2)} as const;
|
71
|
+
|
72
|
+
${inputsType}
|
73
|
+
|
74
|
+
${outputsType}
|
75
|
+
|
76
|
+
${parseInputs}
|
77
|
+
|
78
|
+
${dumpOutputs}
|
79
|
+
`;
|
80
|
+
};
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { mkdir, watch, writeFile } from "node:fs/promises";
|
2
|
+
import { dirname } from "node:path";
|
3
|
+
import type { GithubAction } from "@schemastore/github-action";
|
4
|
+
import { Command } from "commander";
|
5
|
+
import { parse } from "yaml";
|
6
|
+
import { actionToType } from "../action-to-type";
|
7
|
+
import { universalReadFile } from "../utils";
|
8
|
+
|
9
|
+
const program = new Command();
|
10
|
+
|
11
|
+
program
|
12
|
+
.name("generate")
|
13
|
+
.description("generate typescript code from action.yaml file")
|
14
|
+
.argument("<file>", "output typescript file")
|
15
|
+
.option("-i, --input <file>", "input action.yaml file", "action.yml")
|
16
|
+
.option("--watch", "watch mode", false)
|
17
|
+
.action(async (file: string, options: { input: string; watch: boolean }) => {
|
18
|
+
const yaml = parse(await universalReadFile(options.input)) as GithubAction;
|
19
|
+
|
20
|
+
await mkdir(dirname(file), { recursive: true });
|
21
|
+
await writeFile(file, actionToType(yaml));
|
22
|
+
|
23
|
+
if (!options.watch) {
|
24
|
+
return;
|
25
|
+
}
|
26
|
+
|
27
|
+
for await (const _ of watch(options.input)) {
|
28
|
+
const yaml = parse(
|
29
|
+
await universalReadFile(options.input),
|
30
|
+
) as GithubAction;
|
31
|
+
|
32
|
+
await mkdir(dirname(file), { recursive: true });
|
33
|
+
await writeFile(file, actionToType(yaml));
|
34
|
+
console.log("Updated", file);
|
35
|
+
}
|
36
|
+
});
|
37
|
+
|
38
|
+
program.parse();
|
package/src/index.ts
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
import type { GithubAction as RawGitHubAction } from "@schemastore/github-action";
|
2
|
+
|
3
|
+
export type GithubAction = Omit<RawGitHubAction, "runs">;
|
4
|
+
|
5
|
+
export type Prettify<Type> = {
|
6
|
+
[Key in keyof Type]: Type[Key];
|
7
|
+
} & {};
|
8
|
+
|
9
|
+
type InputsKeys<T extends GithubAction> = keyof T["inputs"];
|
10
|
+
|
11
|
+
type InputOption = {
|
12
|
+
type?: "boolean" | "multiline" | "string";
|
13
|
+
trimWhitespace?: boolean;
|
14
|
+
};
|
15
|
+
|
16
|
+
export type InputOptions<T extends GithubAction> = Partial<
|
17
|
+
Record<InputsKeys<T>, InputOption>
|
18
|
+
>;
|
19
|
+
export type InputsValues<
|
20
|
+
Action extends GithubAction,
|
21
|
+
Option extends InputOptions<Action> = InputOptions<Action>,
|
22
|
+
> = {
|
23
|
+
[K in InputsKeys<Action>]: Option[K] extends { type: infer V }
|
24
|
+
? V extends "boolean"
|
25
|
+
? boolean
|
26
|
+
: V extends "multiline"
|
27
|
+
? string[]
|
28
|
+
: string
|
29
|
+
: string;
|
30
|
+
};
|
package/src/utils.ts
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
2
|
+
|
3
|
+
function isUrl(input: string): boolean {
|
4
|
+
try {
|
5
|
+
const url = new URL(input);
|
6
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
7
|
+
} catch {
|
8
|
+
return false;
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
export const universalReadFile = async (path: string) => {
|
13
|
+
if (isUrl(path)) {
|
14
|
+
const response = await fetch(path);
|
15
|
+
return response.text();
|
16
|
+
}
|
17
|
+
const file = await readFile(path, "utf-8");
|
18
|
+
return file;
|
19
|
+
};
|
package/tsconfig.json
ADDED