{"id":18586361,"url":"https://github.com/cardinalby/js-eval-action","last_synced_at":"2025-06-25T01:39:35.555Z","repository":{"id":57283078,"uuid":"437626831","full_name":"cardinalby/js-eval-action","owner":"cardinalby","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-03T16:52:42.000Z","size":789,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-04T20:57:41.816Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cardinalby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-12T18:38:36.000Z","updated_at":"2022-11-15T08:54:52.000Z","dependencies_parsed_at":"2024-10-25T08:13:20.912Z","dependency_job_id":null,"html_url":"https://github.com/cardinalby/js-eval-action","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/cardinalby/js-eval-action","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fjs-eval-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fjs-eval-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fjs-eval-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fjs-eval-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cardinalby","download_url":"https://codeload.github.com/cardinalby/js-eval-action/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cardinalby%2Fjs-eval-action/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260768802,"owners_count":23059940,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T00:37:58.854Z","updated_at":"2025-06-25T01:39:35.523Z","avatar_url":"https://github.com/cardinalby.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![test](https://github.com/cardinalby/js-eval-action/actions/workflows/test.yml/badge.svg)](https://github.com/cardinalby/js-eval-action/actions/workflows/test.yml)\n[![build](https://github.com/cardinalby/js-eval-action/actions/workflows/build.yml/badge.svg)](https://github.com/cardinalby/js-eval-action/actions/workflows/build.yml)\n[![publish-context-types](https://github.com/cardinalby/js-eval-action/actions/workflows/publish-context-types.yml/badge.svg)](https://github.com/cardinalby/js-eval-action/actions/workflows/publish-context-types.yml)\n\n## Eval JS expression as a workflow step\n\nIt's a GitHub Action for evaluating small pieces of JavaScript code passed as `expression` input \nor placed to a separate file. \n\nCan be handy for implementing easy logic, math and string manipulation instead of using bash scripts.\n\nAlso, you can make own composite actions on base of _js-eval-action_ by creating a single `action.yml` file.\nIf you want to extract JS code to a file and get code completion and type checks you can install\n[js-eval-action-expression-context](https://www.npmjs.com/package/js-eval-action-expression-context) package.\nLook at [example](https://github.com/cardinalby/js-eval-action/tree/master/example) dir to see this approach.\n\n## Examples\n\n### Do simple math:\n```yaml\n- id: getNextAttemptNumber\n  uses: cardinalby/js-eval-action@v1\n  env:\n    STEP_SIZE: 2\n  with:\n    data: '8'\n    expression: \"parseInt(inputs.data) + parseInt(env.STEP_SIZE)\"\n\n# steps.getNextAttemptNumber.outputs.result == \"10\"\n```\n\n### Compare the new version with the old one\n```yaml\n- id: checkNewVersion\n  uses: cardinalby/js-eval-action@v1\n  env:\n    OLD_VERSION: 1.2.3\n    NEW_VERSION: 1.3.0\n  with:\n    expression: |\n      ({ \n        greater: semver.gte(env.NEW_VERSION, env.OLD_VERSION), \n        compatible: semver.major(env.NEW_VERSION) === semver.major(env.OLD_VERSION)\n      })\n    extractOutputs: 'true'  \n\n# steps.checkNewVersion.outputs.greater == \"true\"\n# steps.checkNewVersion.outputs.compatible == \"true\"\n```\n\n### Export env variables from .env file to a job env\n\n```yaml\n- name: Export env variables\n  uses: ./\n  env:\n    ENV_FILE: 'constants.env'\n  with:\n    jsFile: 'exportEnvs.js'\n```\n\n_exportEnvs.js:_\n\n```js\nObject.entries(\n    dotenv.parse(fs.readFileSync(env.ENV_FILE).toString())\n).forEach(\n    e =\u003e core.exportVariable(e[0], e[1])\n)\n```\n\nLook at [example](https://github.com/cardinalby/js-eval-action/tree/master/example) dir to see the same\ncode extracted as a composite action.\n\n### Validate [dispatched_workflow](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#workflow_dispatch) inputs\n\n```yaml\n- name: Validate workflow_dispatch inputs\n  uses: ./\n  env:\n    attempt: ${{ github.event.inputs.attemptNumber }}\n    max: ${{ github.event.inputs.maxAttempts }}\n  with:\n    expression: |\n      {\n        const attempt = parseInt(env.attempt), max = parseInt(env.max);\n        assert(attempt \u0026\u0026 max \u0026\u0026 max \u003e= attempt);\n      } \n\n# Will fail if github.event.inputs are invalid\n```\n\n### Read JSON data\n```yaml\n- id: jsonExample\n  uses: cardinalby/js-eval-action@v1\n  env:\n    MY_VAR: '{\"a\": \"hello\", \"b\": \"hell\"}'\n  with:\n    jsonEnvs: MY_VAR\n    expression: \"env.MY_VAR.a.indexOf(env.MY_VAR.b) !== -1\"\n\n# steps.jsonExample.outputs.result == \"true\"\n```\n\n### Get default branch by octokit request\n```yaml\n- id: getDefaultBranch\n  uses: cardinalby/js-eval-action@v1\n  env:\n    # Required to use octokit\n    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \n  with:\n    expression: | \n      (await octokit.rest.repos.get({\n        owner: context.repo.owner, \n        repo: context.repo.repo\n      })).data.default_branch\n\n# steps.getDefaultBranch.outputs.result == \"master\"\n```\nFor this particular case you can use a dedicated [octokit/request-action](https://github.com/marketplace/actions/github-api-request).\n\n### Parse yaml\n```yaml\n- id: readYamlExample\n  uses: cardinalby/js-eval-action@v1  \n  with:\n    expression: 'yaml.parse((await fs.readFile(\"fileInRepo.yml\")).toString()).myProperty'\n\n# steps.readYamlExample.outputs.result == \"property value\"\n```\n\n### More examples \n\nActual self-test functional examples are in `.github/workflows/test.yml`\n\n## Inputs\n\n### `expression`\nJS expression that returns a value. \n* You have to set either `expression` input or `jsFile`\n* By default, (if `extractOutputs` input is `false`) \nthe value will be [serialized](#output-serialization) to string and put to `result` output. \nIf `extractOutputs` iss `true`, the value has to be an object. Each property of it will be considered \nas a separate output and [serialized](#output-serialization) to string.\n* Expression will be put to `async () =\u003e %EXPRESSION%` wrapper.\n* You can use `await` in the expression and return a Promise. When it is fulfilled, \nit's result will be taken.\n* You can use curly braces with return statement: `{ let x = 5; x += 2; return x; }` \n* To return the object directly wrap it into parentheses: `({out1: 5, out2: 10})`; \n* Do not pass untrusted string to `expression`!\n\n### `jsFile`\nPath to a file containing JS code that will be evaluated. Use instead of `expression` if you want to \nextract JavaScript code to the separate file. \n\n* You have to set either `expression` input or `jsFile`\n* **This code is not wrapped** like the `expression` input code, but evaluated directly instead and value\n  is parsed according to the same rules. It's recommended to wrap it by yourself: `(async () =\u003e 2 * 2)()`.\n  Replace `2 * 2` by your expression. \n* Look at [js-eval-action-expression-context](https://www.npmjs.com/package/js-eval-action-expression-context)\n  package for type declarations if you want to enable type checking and autocompletion in your JS file.\n\n### `extractOutputs` Default: `false`\nRequires the value returned by the expression to be an object. Each property of it will be considered\nas a separate output and [serialized](#output-serialization) to string. To return the object directly in the \nexpression wrap it into parentheses\n \n### `jsonInputs` Default: _empty_\nParse listed inputs as JSON (if you access them via `inputs.NAME` in expression). \n* Format: input names separated by `|` sign. Example: `input1|input2`.\n* Use asterisk `*` to parse all inputs as JSON.\n\n### `jsonEnvs` Default: _empty_\nParse listed env variables as JSON (if you access them via `env.NAME` in expression).\n* Format: input names separated by `|` sign. Example: `input1|input2`.\n* Use asterisk `*` to parse all inputs as JSON.\n\n### `timeoutMs` Default: _empty_\nTimeout of JS evaluation in milliseconds. No timeout if empty. If timeout reached, action fails with error\nand `timedOut` output set to `true`.\n\n### `data` Default: _empty_\nArbitrary data to be accessed inside JS expression. Doesn't have any other meaning.\n\n### Any other inputs\nYou can also set other not documented inputs and access them in JS expression using `inputs.NAME`, \nbut in this case GitHub runner will produce warnings about unknown inputs. To avoid it you can:\n* Set env variables for the step and access them as `env.NAME` in the expression\n* Set env variables with `INPUT_` prefixes. For example, `INPUT_XYZ` (upper case!) env variable is \n  considered `xyz` input and doesn't produce a warning.\n\n## Outputs\n\n### `result`\nIf `extractOutputs` input is `false` contains a result of the expression evaluation. `undefined` otherwise.\n\n### `timedOut`\nIf `timeoutMs` input is set and execution was timed out, this output contains `true`. `false` otherwise.\n\n### Any other outputs\nIf `extractOutputs` input is `true`, each property of the object returned by the expression will be\nserialized and set as a separate output.\n\n## Output serialization\nValue returned by the JS expression is serialized to string that will be set to output(s).\n* If `extractOutputs` input is `false` (default), expression result will be serialized and put to `result` output.\n* If `extractOutputs` input is `true`, expression result has to be an object. Each property of it will be\n  serialized and set as a separate output.\n\nSerialization rules:\n\n| JS value       | String           |\n|----------------|------------------|\n| true           | true             |\n| false          | false            |\n| 123            | 123              |\n| \"abc\"          | abc              |\n| undefined      | undefined        |\n| {a: 3, b: \"c\"} | {\"a\":3,\"b\":\"c\"}  |\n| [\"a\", \"b\"]     | [\"a\",\"b\"]        |\n\n## JavaScript evaluation context\n\nIn the expression you can access the following objects:\n\n### `inputs`\n\nAllows you to read inputs in form of `inputs.inputName`. Note, that input names are not case-sensitive.  \nNormally all inputs are of string type. But if the input you read is marked as JSON input by \n[`jsonInputs`](#jsoninputs-default-_empty_), it will be parsed \n(at the moment of access) and result value will be returned.\n\n### `env`\n\nAllows you to read env variables in form of `env.varName`. Note, that env variables names are case-sensitive.  \nNormally all env variables are of string type. But if the env variable you read is marked as JSON input by\n[`jsonEnvs`](#jsonenvs-default-_empty_), it will be parsed\n(at the moment of access) and result value will be returned.\n\n### `context`\n\nGitHub Actions [context](https://github.com/actions/toolkit/blob/main/packages/github/src/context.ts) object.\n\n### `octokit`\n \nContains an instance of [octokit](https://www.npmjs.com/package/@actions/github) if `GITHUB_TOKEN` \nenv variable is set. Usage example:\n```js\n(await octokit.rest.repos.get({owner: context.repo.owner, repo: context.repo.repo})).data.name\n```\n\n### `core`\n\nContains [@actions/core](https://github.com/actions/toolkit/tree/main/packages/core) library.\n\n### `semver`\n\nContains [semver](https://www.npmjs.com/package/semver) library.\n\n### `yaml`\n\nContains [yaml](https://www.npmjs.com/package/yaml) library.\n\n### `wildstring`\n\nContains [wildstring](https://www.npmjs.com/package/wildstring) library.\n\n### `dotenv`\n\nContains [dotenv](https://www.npmjs.com/package/dotenv) library.\n\n### `dotenvExpand`\n\nContains [dotenv-expand](https://www.npmjs.com/package/dotenv-expand) exported function.\n\n### `fs`\n\nContains [fs-extra](https://www.npmjs.com/package/fs-extra) library.\n\n### `path`\n\nContains NodeJS [path](https://nodejs.org/docs/latest-v20.x/api/path.html) module.\n\n### `assert`\n\nContains NodeJS [assert](https://nodejs.org/docs/latest-v16.x/api/assert.html) module.\u003cbr\u003e\nNote: `console.assert()` doesn't cause an Error in NodeJS since version 10. It's the reason to\nuse `assert(value)`, `assert.deepStrictEqual(actual, expected)`, etc. instead.\n\n### `buffer`, `Buffer`\n\nContains NodeJS [buffer](https://nodejs.org/docs/latest-v16.x/api/buffer.html) module.\u003cbr\u003e\nand `Buffer` constructor available separately from module.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcardinalby%2Fjs-eval-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcardinalby%2Fjs-eval-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcardinalby%2Fjs-eval-action/lists"}