{"id":18952788,"url":"https://github.com/nickofthyme/object-remap","last_synced_at":"2025-06-21T07:07:37.147Z","repository":{"id":47390646,"uuid":"399232135","full_name":"nickofthyme/object-remap","owner":"nickofthyme","description":"Basic action utility to remap objects in github action workflow","archived":false,"fork":false,"pushed_at":"2024-11-22T03:33:01.000Z","size":463,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-04T21:30:32.060Z","etag":null,"topics":["actions","github-actions","utilities"],"latest_commit_sha":null,"homepage":"","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/nickofthyme.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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-08-23T19:57:09.000Z","updated_at":"2025-05-21T05:05:33.000Z","dependencies_parsed_at":"2025-03-02T22:01:45.222Z","dependency_job_id":"7fe660c8-cdfc-4f8d-8437-9c9c57f63d16","html_url":"https://github.com/nickofthyme/object-remap","commit_stats":{"total_commits":4,"total_committers":2,"mean_commits":2.0,"dds":0.25,"last_synced_commit":"0bfa2be8a459fc92acec5fd66e6489bf1d0c0e3e"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":"actions/typescript-action","purl":"pkg:github/nickofthyme/object-remap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickofthyme%2Fobject-remap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickofthyme%2Fobject-remap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickofthyme%2Fobject-remap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickofthyme%2Fobject-remap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickofthyme","download_url":"https://codeload.github.com/nickofthyme/object-remap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickofthyme%2Fobject-remap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260774882,"owners_count":23060944,"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":["actions","github-actions","utilities"],"created_at":"2024-11-08T13:34:37.987Z","updated_at":"2025-06-21T07:07:32.129Z","avatar_url":"https://github.com/nickofthyme.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Continuous Integration Tests](https://github.com/nickofthyme/object-remap/actions/workflows/ci.yml/badge.svg)](https://github.com/nickofthyme/object-remap/actions/workflows/ci.yml)\n\n# Object Remap Action\n\nAn action designed to make object manipulation in GitHub actions just a _little_ bit easier 🤏.\n\n## Inputs\n\nThis action uses flexible imports for users to define custom `\u003cpath\u003e:\u003cvalue\u003e` inputs to make it easy on you. There are three defined input options that are prefixed with `__` to avoid naming collisions. All defined input options will failover to their default value if an invalid option is supplied. See all three options below.\n\n### `__depth`\n\n```ts\n__depth?: number\n```\n\nThis allows you to truncate a final remapped object to a given depth if you don't need the whole value. This impacts both the user-defined path and the defined array or object values. See the [_Simple - depth_](#simple---depth) example below\n\n### `__case`\n\n```ts\n__case?: 'camel' | 'snake' | 'pascal' | 'upper' | 'lower' | 'kebab' = 'camel'\n```\n\nThis allows you override the casing used for user-defined path inputs as well as keys of object values. By default, this `__case` is applied to all user-defined paths only. You may override user-defined object values by setting `__deep_casing` to `true`. All user-defined path inputs should use `snake_case` to define the initial paths and set `__case` accordingly. See the [_Simple - casing_](#simple---casing) example below.\n\n| Word \\ Case | `'camel'` (default) | `'snake'` | `'pascal'` | `'upper'` | `'lower'` | `'kebab'`\n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| `'prop'` | `'prop'` | `'prop'` | `'Prop'` | `'PROP'` | `'prop'` | `'prop'` |\n| `'multi_prop'` | `'multiProp'` | `'multi_prop'` | `'MultiProp'` | `'MULTI_PROP'` | `'multi_prop'` | `'multi-prop'` |\n\n\u003e **NOTE:** This table of examples assumes the path inputs are defined in `snake_case`.\n\n### `__deep_casing`\n\n```ts\n__deep_casing?: boolean = false\n```\nThis input allows you to control when the casing is applied to the object or array values. By default, this is `false` and will only apply the `__case` to the path inputs. If `true` the `__case` will be applied to all keys in the path and any object/array values. See the [_Simple - deep casing_](#simple---deep-casing) example below.\n\n### User-defined inputs (e.g. `\u003cpath\u003e:\u003cvalue\u003e`)\n\nUser-defined inputs are custom `\u003cpath\u003e:\u003cvalue\u003e` pairs where the key represents the path of the property to set on an object in dot notation, think [`lodash.set`](https://lodash.com/docs/4.17.15#set). The individual property keys should be in `snake_case` (i.e. `path_to.some_prop`) to enable casing these _Unexpected_ inputs in the final output via [`__case`](#case), this does **NOT** apply to keys within the object or array values. See usage examples below.\n\nThis action also supports _unfiltering_ values using the `*` syntax as a wildcard for array indices (i.e. `people.*.name`). This is essentially the inverse of [Object filters](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#object-filters).\n\nGitHub does not fully support this which is why there are some restrictions such as using `snake_case`. This same strategy is used by [`octokit/request-action`](https://github.com/marketplace/actions/github-api-request) to assign route-specific url path parameters. Because of this, you will see a warning similar to that below in your GitHub action. This is safe to ignore.\n\n```\nWarning: Unexpected input(s) 'test', 'test.one' valid inputs are ['__depth', '__case', '__deep_casing']\n```\n\n![image](https://user-images.githubusercontent.com/19007109/132143947-58b444bc-ade8-4843-869e-3210793b0f30.png)\n\n## Outputs\n\nThere is currently only a single output value for this action.\n\n### `json`\n\nThis output value is the final [stringified](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) object per the custom user defined `\u003cpath\u003e:\u003cvalue\u003e` pairs.\n\n## Usage\n\n### Simple\n\nYou can use any type of value including `string`, `number`, `boolean` or any stringified object or array.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Simple\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          key_number: 1\n          key_string: string1\n          key_boolean: false\n          key_array: '[1, 2, 3]'\n          key_object: '{ \"can-be-any-case\": true }'\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"keyNumber\": 1,\n  \"keyString\": \"string1\",\n  \"keyBoolean\": false,\n  \"keyArray\": [1, 2, 3],\n  \"keyObject\": { \"can-be-any-case\": true }\n}\n```\n\n\u003e **NOTE:** The keys of object (or array) values can be any case, which will be left unchanged by default. This can be change by setting `__deep_casing` to `true` with a different `__case`, in which case all keys in the final remapped object output will be changed to the specified `__case`.\n\n### Simple - nested\n\nYou can use dot (`.`) separated strings to assign values to nested keys.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Simple - nested\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          top.deep.very_deep: 1\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"top\": {\n    \"deep\": {\n      \"veryDeep\": 1\n    }\n  }\n}\n```\n\n### Simple - depth\n\nYou can set `__depth` to limit the depth of the final remapped object. The default is `0` which will **NOT** alter the depth of the values.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Simple - depth\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          __depth: 2\n          one: '{ \"two\": 2 }'\n          one.too_deep: '{ \"three\": 3 }'\n          arr: '[{ \"two\" : 2, \"too_deep\": { \"three\": 3 }}]'\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"one\": {\n    \"two\": 2,\n  },\n  \"arr\": [\n    {\n      \"two\": 2,\n    }\n  ]\n}\n```\n\n\u003e **Note:** the array index is **NOT** counted as a depth. Also, any empty object `{}` path will be recursively removed. Be cautious when using this with large inputs values as you may encounter the [_Argument is too long_](#argument-is-too-long) error which will throw an error before the `__depth` is ever applied.\n\n### Simple - casing\n\nYou can set `__case` to assign the casing of the user-defined paths and object or array values. The default `__case` is `'camel'`.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Simple - casing\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          __case: kebab\n          my_key.my_nested_key: 1\n```\n\n\u003e **Note:** The case of the initial path should always be `snake_case`. This is due to a limitation with GitHub actions using flexible inputs. See [_User-defined inputs_](#user-defined-inputs-eg-pathvalue) section above.\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"my-key\": {\n    \"my-nested-key\": 1\n  }\n}\n```\n\n### Simple - deep casing\n\nYou can set `__case` to assign the casing of the user-defined paths.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Simple - deep casing\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          __case: upper\n          __deep_casing: true\n          my_key.deep: '{ \"myObjectKey\": { \"nestedKey\": 1 }}'\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"MY_KEY\": {\n    \"DEEP\": {\n      \"MY_OBJECT_KEY\": {\n        \"NESTED_KEY\": 1\n      }\n    }\n  }\n}\n```\n\n\u003e **Note:** The `__case` is applied to both the keys included in the path **AND** the object value keys. If `__deep_casing` were instead set to `false`, the `\"myObjectKey\"` and `\"nestedKey\"` keys would be unchanged.\n\n---\n\nFor the following _complex_ examples, let's assume that we receive the following object stored in the `.output` of a given `job` or `step` in our workflow.\n\n```json\n{\n  \"one\": 1,\n  \"two\": {\n    \"one\": 1,\n  },\n  \"three\": {\n    \"two\": {\n      \"one\": 1,\n    },\n  },\n  \"numbers\": [1, 2, 3],\n  \"array\": [\n    {\n      \"test\": \"key1\",\n      \"deeper\": {\n        \"deep\": 1,\n      },\n    },\n    {\n      \"test\": \"key2\",\n    },\n  ],\n}\n```\n\nSpecifically, the `\"Get mock test object\"` step will set the above object to its output (via [`$GITHUB_OUTPUT`](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter)) and makes it available via `steps.mock.outputs.json` in other steps.\n\n---\n\n### Complex - using data from other jobs/steps\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Get mock test object\n        id: mock\n        run: echo \"json={\\\"one\\\":1,\\\"two\\\":{\\\"one\\\":1},\\\"three\\\":{\\\"two\\\":{\\\"one\\\":1}},\\\"numbers\\\":[1,2,3],\\\"array\\\":[{\\\"test\\\":\\\"key1\\\",\\\"deeper\\\":{\\\"deep\\\":1}},{\\\"test\\\":\\\"key2\\\"}]}\" \u003e\u003e \"$GITHUB_OUTPUT\"\n      - name: Complex values\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          test: ${{ steps.mock.outputs.json }}\n\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"test\": {\n    \"one\": 1,\n    \"two\": {\n      \"one\": 1,\n    },\n    \"three\": {\n      \"two\": {\n        \"one\": 1,\n      },\n    },\n    \"numbers\": [1, 2, 3],\n    \"array\": [\n      {\n        \"test\": \"key1\",\n        \"deeper\": {\n          \"deep\": 1,\n        },\n      },\n      {\n        \"test\": \"key2\",\n      },\n    ],\n  }\n}\n```\n\n### Complex - using _parts_ of data from other jobs/steps\n\nUsing GitHub actions [`fromJSON`](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#fromjson) utility we can pick off only _parts_ of a value to be remapped.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Get mock test object\n        id: mock\n        run: echo \"json={\\\"one\\\":1,\\\"two\\\":{\\\"one\\\":1},\\\"three\\\":{\\\"two\\\":{\\\"one\\\":1}},\\\"numbers\\\":[1,2,3],\\\"array\\\":[{\\\"test\\\":\\\"key1\\\",\\\"deeper\\\":{\\\"deep\\\":1}},{\\\"test\\\":\\\"key2\\\"}]}\" \u003e\u003e \"$GITHUB_OUTPUT\"\n      - name: Complex values\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          test.value: ${{ fromJSON(steps.mock.outputs.json).two.one }} # value is just 1\n```\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"test\": {\n    \"value\": 1,\n  }\n}\n```\n\n### Complex - _unfiltering_ value from _filtered_ data\n\nGitHub actions have a special syntax called [Object filters](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#object-filters) which allows you to pull off individual values from a nested array of objects.\n\nTo help leverage this syntax, we added the idea of _unfiltering_, which as you'd expect, reverses an array of values into a specified key.\n\n```yml\njobs:\n  example:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Get mock test object\n        id: mock\n        run: echo \"json={\\\"one\\\":1,\\\"two\\\":{\\\"one\\\":1},\\\"three\\\":{\\\"two\\\":{\\\"one\\\":1}},\\\"numbers\\\":[1,2,3],\\\"array\\\":[{\\\"test\\\":\\\"key1\\\",\\\"deeper\\\":{\\\"deep\\\":1}},{\\\"test\\\":\\\"key2\\\"}]}\" \u003e\u003e \"$GITHUB_OUTPUT\"\n      - name: Complex values\n        id: test # used to access output in other steps\n        uses: nickofthyme/object-remap@v3\n        with:\n          test.*.key: ${{ fromJSON(steps.mock.outputs.json).array.*.test }} # value is just ['key1', 'key2`]\n```\n\n\u003e **Note:** This is limited to a single `*` in the path. Attempting to pass multiple `*` in a path (e.g. `my.*.key.*.prop`) will cause undesirable effects.\n\nThe value of `steps.test.outputs.json` would be...\n\n```json\n{\n  \"test\": [\n    {\n      \"key\": \"test1\",\n    },\n    {\n      \"key\": \"test2\",\n    }\n  ]\n}\n```\n\n## Motivation\n\nWhile developing my first GitHub action workflow, I realized how difficult it is to take an object from one step and manipulate it for use in another step. This could take the form of any verbose and overly complex bash, python or any other [allowable shell](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-a-specific-shell) script. That's assuming you find the correct way to pass and parse the desired inputs to your script accounting for line returns and special escaped characters.\n\nComing from javascript, this was very frustrating so I created this action.\n\nThis difficulty came about while attempting to create a job strategy [`matrix`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) from the response of a GitHub api request. I envisioned something similar to the [stackoverflow example](https://stackoverflow.com/a/62953566/6943587), easy right, but nesting the GH api response into the `include` key was much harder than I expected. Below is this part of the final workflow using this action to easily assign the desired matrix values.\n\n```yml\nname: 'Validate PRs'\n\non:\n  schedule:\n    - cron:  '0 0 * * *' # once a day\n\njobs:\n  fetch:\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.save.outputs.json }}\n    steps:\n      - name: Get open pull requests\n        id: fetch\n        uses: octokit/request-action@v2.x\n        with:\n          route: GET /repos/{repo}/pulls?state=open\n          repo: ${{ github.repository }}\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Create matrix\n        id: save\n        uses: nickofthyme/object-remap@v3\n        with:\n          include.*.number: ${{ toJSON(fromJSON(steps.fetch.outputs.data).*.number) }}\n          include.*.sha: ${{ toJSON(fromJSON(steps.fetch.outputs.data).*.head.sha) }}\n\n  update-check:\n    name: \"Checking PR #${{ matrix.number }}\"\n    runs-on: ubuntu-latest\n    needs: fetch\n    strategy:\n      matrix: ${{ fromJSON(needs.fetch.outputs.matrix) }}\n    steps:\n      - name: Do something cool...\n```\n\n## Limitations\n\nAside from the obvious limitations to assign values in any way you desire, including assigning values to array indices, the following limitations are unavoidable.\n\n### Argument is too long\n\nThere is a limit to the character length of the arguments you can pass to any GitHub action. I'm not sure what the exact limit is and it likely varies by machine but this is unavoidable. The error will look something like...\n\n```\nError: Argument list too long\n```\n\n![image](https://user-images.githubusercontent.com/19007109/132149632-40fff6dd-4de6-46ff-a42c-cb7e5cc1fdfb.png)\n\nThis limit is easily exceeded by the full `output` of verbose api requests. In such a case, you could possibly limit the count received from the api request or use [Object filters](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#object-filters) to pluck and assign only the values you need. For example...\n\n```yml\njobs:\n  fetch:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Fetch GH pull requests\n        id: fetch\n        uses: octokit/request-action@v2.x\n        with:\n          route: GET /repos/{repo}/pulls?state=open\n          repo: ${{ github.repository }}\n        env:\n          GITHUB_TOKEN: \"${{ secrets.GITHUB_TOKEN }}\"\n      - name: Store matrix\n        id: save\n        uses: nickofthyme/object-remap@v3\n        with:\n          include.*.number: ${{ toJSON(fromJSON(steps.fetch.outputs.data).*.number) }}\n          include.*.head_sha: ${{ toJSON(fromJSON(steps.fetch.outputs.data).*.head.sha) }}\n          include.*.base_sha: ${{ toJSON(fromJSON(steps.fetch.outputs.data).*.base.sha) }}\n```\n\n## Troubleshooting\n\nAll defined input options (i.e. `__case`, `__depth` \u0026 `__deep_casing`) will failover to their default value if an invalid option is supplied. If you experience unanticipated outputs based on the inputs you provided see `warnings` in the GitHub action logs to make sure the correct inputs are used. Ignore the warning mentioned in [User-defined inputs](#user-defined-inputs-eg-pathvalue) section.\n\nIn addition, this action will always log the parsed user-defined `Inputs` including `path`, `type` and `value`, as well as the final remapped `Output` to enable easy troubleshooting. These logs would look something like...\n\n```\n--------- Inputs ---------\npath: number\ntype: number\nvalue: 21\n--------------------------\npath: string\ntype: string\nvalue: \"a string\"\n--------------------------\npath: yes\ntype: boolean\nvalue: true\n--------------------------\npath: no\ntype: boolean\nvalue: false\n--------------------------\npath: arr\ntype: array\nvalue: [\"one\",\"two\"]\n--------------------------\npath: obj\ntype: object\nvalue: {\"one\":1}\n--------- Output ---------\nRemapped json:\n{\n  \"number\": 21,\n  \"string\": \"a string\",\n  \"yes\": true,\n  \"no\": false,\n  \"arr\": [\n    \"one\",\n    \"two\"\n  ],\n  \"obj\": {\n    \"one\": 1\n  }\n}\n```\n\n## Contributing\n\nI am happy to make changes based on issue requests. Or feel free to contribute yourself, see [`CONTRIBUTING.md`](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickofthyme%2Fobject-remap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickofthyme%2Fobject-remap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickofthyme%2Fobject-remap/lists"}