{"id":41904979,"url":"https://github.com/umono-cms/compono","last_synced_at":"2026-01-28T16:12:43.591Z","repository":{"id":313272618,"uuid":"995919118","full_name":"umono-cms/compono","owner":"umono-cms","description":"Component-based Markdown DSL","archived":false,"fork":false,"pushed_at":"2026-01-24T18:01:26.000Z","size":180,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-26T05:12:11.717Z","etag":null,"topics":["domain-specific-language","markdown","reusable-components"],"latest_commit_sha":null,"homepage":"","language":"Go","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/umono-cms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-04T07:40:19.000Z","updated_at":"2026-01-24T17:59:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"6c28a250-c5be-4ed9-acfd-fce475b25a00","html_url":"https://github.com/umono-cms/compono","commit_stats":null,"previous_names":["umono-cms/compono"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/umono-cms/compono","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umono-cms%2Fcompono","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umono-cms%2Fcompono/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umono-cms%2Fcompono/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umono-cms%2Fcompono/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/umono-cms","download_url":"https://codeload.github.com/umono-cms/compono/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/umono-cms%2Fcompono/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846870,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T15:15:36.453Z","status":"ssl_error","status_checked_at":"2026-01-28T15:15:13.020Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["domain-specific-language","markdown","reusable-components"],"created_at":"2026-01-25T15:15:19.610Z","updated_at":"2026-01-28T16:12:43.583Z","avatar_url":"https://github.com/umono-cms.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Compono\n\nCompono is a component-based domain-specific language that can compile HTML. It extends Markdown syntax with reusable components, making it ideal for content-heavy applications.\n\nOriginally developed for [Umono CMS](https://github.com/umono-cms/umono), Compono can be used in any Go project that needs a flexible templating solution.\n\n## Installation\n\n```bash\ngo get github.com/umono-cms/compono\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"bytes\"\n    \"fmt\"\n    \"github.com/umono-cms/compono\"\n)\n\nfunc main() {\n    c := compono.New()\n\n    source := []byte(`{{ SAY_HELLO name=\"World\" }}\n\n~ SAY_HELLO name=\"Guest\"\n# Hello, {{ name }}!\n`)\n\n    var buf bytes.Buffer\n    if err := c.Convert(source, \u0026buf); err != nil {\n        panic(err)\n    }\n\n    fmt.Println(buf.String())\n    // Output: \u003ch1\u003eHello, World!\u003c/h1\u003e\n}\n```\n\n## Syntax\n\n### Markdown Support\n\nCompono supports common Markdown elements:\n\n```\n# Heading 1\n## Heading 2\n### Heading 3\n\nThis is a paragraph with **bold** and *italic* text.\n\n`inline code`\n\n[Link text](https://example.com)\n```\n\nCode blocks are also supported:\n\n~~~\n```go\nfmt.Println(\"Hello\")\n```\n~~~\n\n### Components\n\nComponents are the core feature of Compono. They allow you to create reusable content blocks.\n\n#### Defining a Local Component\n\nLocal components are defined in the same scope where they're used:\n\n```\n{{ GREETING }}\n\n~ GREETING\nWelcome to our website!\n```\n\nThe `~ COMPONENT_NAME` syntax marks the beginning of a local component definition. Everything after it becomes the component's content. A component definition ends when another component definition starts or at EOF.\n\n#### Components with Parameters\n\nComponents can accept parameters with default values:\n\n```\n{{ USER_CARD name=\"Anonymous\" role=\"Guest\" }}\n\n~ USER_CARD name=\"\" role=\"\"\n## {{ name }}\n*{{ role }}*\n```\n\nParameter types supported:\n- Strings: `name=\"John\"`\n- Numbers: `age=25`\n- Booleans: `active=true`\n\n#### Block vs Inline Components\n\nComponents containing multiple paragraphs or block elements are **block components**:\n\n```\n{{ ARTICLE }}\n\n~ ARTICLE\n# Title\nFirst paragraph.\n\nSecond paragraph.\n```\n\nComponents with single-line content can be used **inline**:\n\n```\nWelcome, {{ USERNAME }}!\n\n~ USERNAME\nJohn\n```\n\n### Global Components\n\nGlobal components can be registered once and used across multiple conversions:\n\n```go\nc := compono.New()\n\n// Register a global component\nc.RegisterGlobalComponent(\"FOOTER\", []byte(`© 2026 My Company`))\n\n// Use it in any conversion\nc.Convert([]byte(`\n# Page Title\nContent here...\n{{ FOOTER }}\n`), \u0026buf)\n```\n\nGlobal components can also have parameters:\n\n```go\nc.RegisterGlobalComponent(\"BLOG_PAGE\", []byte(`title=\"\" content=\"\"\n## {{ title }}\n{{ content }}`))\n```\n\n## Built-in Components\n\n### LINK\n\nCreates an anchor element with optional target blank:\n\n```\n{{ LINK text=\"Visit us\" url=\"https://example.com\" new-tab=true }}\n```\n\nOutput:\n```html\n\u003ca href=\"https://example.com\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eVisit us\u003c/a\u003e\n```\n\n## Error Handling\n\nCompono provides clear error messages rendered as custom HTML elements:\n\n- **Unknown component**: When calling a component that doesn't exist\n- **Invalid component usage**: When using a block component inline\n- **Unknown parameter**: When referencing an undefined parameter\n- **Infinite loop detection**: When components call each other recursively\n\n## API Reference\n\n### Core Methods\n\n```go\n// Create a new Compono instance\nc := compono.New()\n\n// Convert source to HTML\nerr := c.Convert(source []byte, writer io.Writer)\n\n// Register a global component\nerr := c.RegisterGlobalComponent(name string, source []byte)\n\n// Unregister a global component\nerr := c.UnregisterGlobalComponent(name string)\n\n// Convert and preview a global component\nerr := c.ConvertGlobalComponent(name string, source []byte, writer io.Writer)\n```\n\n## Component Naming Convention\n\nComponent names must be in `SCREAMING_SNAKE_CASE`:\n\n- ✓ `HEADER`\n- ✓ `USER_PROFILE`\n- ✓ `NAV_MENU_ITEM`\n- ✗ `header`\n- ✗ `userProfile`\n\n## Parameter Naming Convention\n\nParameter names must be in `kebab-case`:\n\n- ✓ `name`\n- ✓ `user-name`\n- ✓ `is-active`\n- ✗ `userName`\n- ✗ `user_name`\n\n## Component Override Behavior\n\nWhen multiple components share the same name, Compono follows a clear override hierarchy:\n\n```\nLocal Component \u003e Global Component \u003e Built-in Component\n```\n\n**Local always wins:**\n\n```\n{{ LINK }}\n\n~ LINK\nI override the built-in LINK component!\n```\n\nThis outputs `\u003cp\u003eI override the built-in LINK component!\u003c/p\u003e` instead of an anchor tag.\n\n**Global overrides built-in:**\n\n```go\nc.RegisterGlobalComponent(\"LINK\", []byte(`Custom link behavior`))\n```\n\nNow all `{{ LINK }}` calls will use your global definition instead of the built-in one.\n\nThis allows you to customize or extend built-in components without modifying the library.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumono-cms%2Fcompono","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fumono-cms%2Fcompono","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fumono-cms%2Fcompono/lists"}