{"id":14965357,"url":"https://github.com/scravy/jinsi","last_synced_at":"2026-02-23T22:16:52.484Z","repository":{"id":54420044,"uuid":"316363177","full_name":"scravy/jinsi","owner":"scravy","description":"JSON/YAML homoiconic templating language","archived":false,"fork":false,"pushed_at":"2023-05-13T13:22:31.000Z","size":120,"stargazers_count":18,"open_issues_count":5,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-01-31T07:04:29.781Z","etag":null,"topics":["cloudformation","devops","functional-programming","json","kubernetes","kubernetes-deployment","pypy3","python","python-3","python3","saltstack","template-engine","templates","yaml","yaml-configuration","yaml-files"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/jinsi","language":"Python","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/scravy.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":"2020-11-27T00:24:37.000Z","updated_at":"2024-08-09T09:26:03.000Z","dependencies_parsed_at":"2024-09-02T17:41:18.743Z","dependency_job_id":null,"html_url":"https://github.com/scravy/jinsi","commit_stats":{"total_commits":117,"total_committers":3,"mean_commits":39.0,"dds":0.1709401709401709,"last_synced_commit":"c4db87d61ba7ad77440bdba3b6cae33b39753a6b"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scravy%2Fjinsi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scravy%2Fjinsi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scravy%2Fjinsi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scravy%2Fjinsi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scravy","download_url":"https://codeload.github.com/scravy/jinsi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238128561,"owners_count":19421054,"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":["cloudformation","devops","functional-programming","json","kubernetes","kubernetes-deployment","pypy3","python","python-3","python3","saltstack","template-engine","templates","yaml","yaml-configuration","yaml-files"],"created_at":"2024-09-24T13:34:38.293Z","updated_at":"2025-10-25T11:31:31.501Z","avatar_url":"https://github.com/scravy.png","language":"Python","readme":"# JSON/YAML homoiconic templating language\n\n[![Github Actions](https://github.com/scravy/jinsi/workflows/Python%20application/badge.svg)](https://github.com/scravy/jinsi/actions)\n[![Downloads](https://static.pepy.tech/personalized-badge/jinsi?period=total\u0026units=international_system\u0026left_color=black\u0026right_color=orange\u0026left_text=Downloads)](https://pepy.tech/project/jinsi)\n[![PyPI version](https://badge.fury.io/py/jinsi.svg)](https://pypi.org/project/jinsi/)\n\n```shell script\npython3 -m pip install jinsi\n```\n\nJinsi is a templating engine that uses YAML/JSON syntax, i.e. it is homoiconic. Never mess with indentation again.\n\nMost template engines are a poor choice for templating YAML/JSON, which is why Jinsi is embedded in the document as\nnative YAML/JSON syntax.\n\nExample:\n\n```yaml\n::let:\n  foo: Hello\n  bar: World\nvalue: \u003c\u003cfoo\u003e\u003e \u003c\u003cbar\u003e\u003e\n```\n\nYields:\n\n```\nvalue: Hello World\n```\n\nSince Jinsi is basically independent from the syntax it works natively in JSON (or any other dialect which uses the\nsame data model) too:\n\n```\n{\n  \"::let\": {\n    \"foo\": \"Hello\",\n    \"bar\": \"World\"\n  },\n  \"value\": \"\u003c\u003cfoo\u003e\u003e \u003c\u003cbar\u003e\u003e\"\n}\n```\n\nJinsi was inspired by AWS Cloudformation templates, which are also homoiconic and feature builtin functions\n(with more limited scope though). As I am using it to ease my DevOps woes it supports Cloudformation's\nBang-Syntax (`!Sub`) natively.\n\nJinsi comes as a command line tool, but you can use it as a library for reading/writing YAML/JSON files too.\n\nUsage:\n\n```bash\njinsi template.yaml foo=bar qux=quuz\n```\n\nThe above invocation will set `$foo` to `Jane` and `$qux` to `Jim`:\n\n```\nvalue: Hello \u003c\u003c$foo\u003e\u003e\n```\n\n...would result in `value: Hello Jane`.\n\nI am also using it to template Kubernetes YAML files. Both `kustomize` as well as `helm` (which uses Go\nTemplates 😖) do not cut it for me. My developer life has been happier ever since. I could imagine using it with salt, too\n(Jinja templates + YAML is just a PITA). Here's an example which configures\nan [ingress resource using aws load balancer controller](https://github.com/kubernetes-sigs/aws-load-balancer-controller)\n\n```yaml\n::let:\n  $name: web-application\n  $subdomain: dashboard\n  $domain: example.com\n  $services:\n    - users\n    - messages\n    - backoffice\n\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  name: \u003c\u003c$subdomain\u003e\u003e\n  annotations:\n    kubernetes.io/ingress.class: alb\n    alb.ingress.kubernetes.io/group.name: \u003c\u003c$domain\u003e\u003e\n    alb.ingress.kubernetes.io/scheme: internet-facing\n    alb.ingress.kubernetes.io/listen-ports:\n      ::json_serialize:\n        - HTTPS: 443\n        - HTTP: 80\n    alb.ingress.kubernetes.io/actions.ssl-redirect:\n      ::json_serialize:\n        Type: redirect\n        RedirectConfig:\n          Protocol: HTTPS\n          Port: '443'\n          StatusCode: HTTP_301\nspec:\n  rules:\n    - host: \u003c\u003c$subdomain\u003e\u003e.\u003c\u003c$domain\u003e\u003e\n      http:\n        paths:\n          ::concat:\n            - - path: /*\n                backend:\n                  serviceName: ssl-redirect\n                  servicePort: use-annotation\n            - ::each $services as $service:\n                path: '/\u003c\u003c$service\u003e\u003e/*'\n                backend:\n                  serviceName: \u003c\u003c$service\u003e\u003e-service\n                  servicePort: 80\n            - - path: '/*'\n                backend:\n                  serviceName: \u003c\u003c$name\u003e\u003e\n                  servicePort: 80\n```\n\n## Usage via CLI\n\n```shell script\npython3 -m jinsi -  # read from stdin\n```\n\n```shell script\npython3 -m jinsi -j -  # read from stdin, render as json\n```\n\n```shell script\npython3 -m jinsi file1.yaml file2.yaml\n```\n\n\n## Examples\n\n### Cloudformation Template\n\nYAML input:\n\n```yaml\n::let:\n  user:\n    ::object:\n      - ::titlecase:\n          ::get: $user.username\n      - Type: AWS::IAM::User\n        Properties:\n          UserName:\n            ::get: $user.username\n          Groups:\n            - Administrators\n          LoginProfile:\n            Password:\n              ::get: $user.password\n              ::else: default\n            PasswordResetRequired: Yes\n  users:\n    ::merge:\n      ::each $ as $user:\n        ::call user:\n\nResources:\n  ::call users:\n    - username: jim\n      password: one\n    - username: jack\n      password: two\n    - username: johnny\n```\n\nRendered output:\n\n```yaml\nResources:\n  Jack:\n    Properties:\n      Groups:\n      - Administrators\n      LoginProfile:\n        Password: two\n        PasswordResetRequired: true\n      UserName: jack\n    Type: AWS::IAM::User\n  Jim:\n    Properties:\n      Groups:\n      - Administrators\n      LoginProfile:\n        Password: one\n        PasswordResetRequired: true\n      UserName: jim\n    Type: AWS::IAM::User\n  Johnny:\n    Properties:\n      Groups:\n      - Administrators\n      LoginProfile:\n        Password: default\n        PasswordResetRequired: true\n      UserName: johnny\n    Type: AWS::IAM::User\n```\n\n### Some fancy shit, too 🥸\n\nThis is just an example to show how complex a template can be.\nAlso note: The fibonacci function is defined recursively. This\nwould blow up and values upto 50 could not be computed. Since\nJinsi is purely functional, functions are mappings and can be\ncached. This is why the computation returns quickly (at all).\n\n```shell script\npython3 -m jinsi max=50 -\n```\n\nYAML input:\n\n```yaml\n::let:\n  fib:\n    ::when:\n      ::get: $n == 0 or $n == 1\n    ::then:\n      ::get: $n\n    ::else:\n      ::add:\n        - ::call fib:\n            $n:\n              ::get: $n - 1\n        - ::call fib:\n            $n:\n              ::get: $n - 2\n  fibs:\n    ::range_exclusive:\n      - 0\n      - ::get: $max\n        ::else: 10\n\nresult:\n  ::each fibs as $n:\n    ::call: fib\n```\n\nRendered output:\n\n```yaml\nresult:\n- 0\n- 1\n- 1\n- 2\n- 3\n- 5\n- 8\n- 13\n- 21\n- 34\n- 55\n- 89\n- 144\n- 233\n- 377\n- 610\n- 987\n- 1597\n- 2584\n- 4181\n- 6765\n- 10946\n- 17711\n- 28657\n- 46368\n- 75025\n- 121393\n- 196418\n- 317811\n- 514229\n- 832040\n- 1346269\n- 2178309\n- 3524578\n- 5702887\n- 9227465\n- 14930352\n- 24157817\n- 39088169\n- 63245986\n- 102334155\n- 165580141\n- 267914296\n- 433494437\n- 701408733\n- 1134903170\n- 1836311903\n- 2971215073\n- 4807526976\n- 7778742049\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscravy%2Fjinsi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscravy%2Fjinsi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscravy%2Fjinsi/lists"}