{"id":15821077,"url":"https://github.com/anilsenay/htmlcheck","last_synced_at":"2025-04-01T06:37:01.893Z","repository":{"id":214118328,"uuid":"735695611","full_name":"anilsenay/htmlcheck","owner":"anilsenay","description":"simple, fast and easy HTML validator in Go","archived":false,"fork":false,"pushed_at":"2023-12-26T14:09:16.000Z","size":27,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-12T07:39:44.207Z","etag":null,"topics":["go","go-html","golang","html","html-tags","html-validation","html-validator","validation","validator"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anilsenay.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}},"created_at":"2023-12-25T21:22:33.000Z","updated_at":"2023-12-26T19:16:02.000Z","dependencies_parsed_at":"2023-12-26T02:14:41.419Z","dependency_job_id":"1ee8b2d6-51ea-47f1-97dc-6aa4a6fbe812","html_url":"https://github.com/anilsenay/htmlcheck","commit_stats":{"total_commits":5,"total_committers":1,"mean_commits":5.0,"dds":0.0,"last_synced_commit":"67d7bb11d54d0772a7ed3daea5c03755eda823dd"},"previous_names":["anilsenay/htmlcheck"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anilsenay%2Fhtmlcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anilsenay%2Fhtmlcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anilsenay%2Fhtmlcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anilsenay%2Fhtmlcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anilsenay","download_url":"https://codeload.github.com/anilsenay/htmlcheck/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246598151,"owners_count":20802973,"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":["go","go-html","golang","html","html-tags","html-validation","html-validator","validation","validator"],"created_at":"2024-10-05T07:20:23.527Z","updated_at":"2025-04-01T06:37:01.863Z","avatar_url":"https://github.com/anilsenay.png","language":"Go","readme":"# htmlcheck\n\nsimple, fast and easy HTML validator in Go\n\n---\n\n## About The Project\n\n`htmlcheck` is a lightweight and efficient Golang package designed to simplify the validation of HTML content in your Go applications. Whether you're working with complete HTML documents or HTML snippets, this package provides a straightforward interface to check the validity of your markup.\n\nYou can specify valid HTML tags, their attributes, and permissible attribute values, providing a comprehensive solution for HTML validation.\n\nThis package is a clone of [htmlcheck](https://github.com/mpfund/htmlcheck) package which has not been maintained for a long time\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Examples](#examples)\n- [Documentation](#documentation)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\n```bash\ngo get github.com/anilsenay/htmlcheck\n```\n\n## Usage\n\nExplain how users can import and use your package in their Go projects. Include code snippets to demonstrate the basic usage.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/anilsenay/htmlcheck\"\n)\n\nfunc main() {\n\tvalidator := htmlcheck.Validator{}\n\n\tvalidator.AddValidTag(htmlcheck.ValidTag{\n\t\tName:  \"a\",\n\t\tAttrs: []htmlcheck.Attribute{\n\t\t\t{Name: \"id\"},\n\t\t\t{Name: \"href\", Value: \u0026htmlcheck.AttributeValue{\n\t\t\t\t// valid regex for href attribute value\n\t\t\t\tRegex: \"^(http(s|))://.*\"\n\t\t\t}},\n\t\t\t{Name: \"target\", Value: \u0026htmlcheck.AttributeValue{\n\t\t\t\t// valid values for target attribute value\n\t\t\t\tList: []string{\"_target\", \"_blank\"}\n\t\t\t}},\n\t\t},\n\t\tIsSelfClosing: false,\n\t})\n\n\thtml := \"\u003ca href='http://hello.world'\u003eHello, World!\u003c/a\u003e\"\n\terrors := htmlcheck.Validate(html)\n\tif len(errors) == 0 {\n\t\tfmt.Println(\"HTML is not valid.\")\n\t} else {\n\t\tfmt.Println(\"HTML is valid!\")\n\t}\n}\n```\n\n## Examples\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/anilsenay/htmlcheck\"\n)\n\nfunc main() {\n\tvalidator := htmlcheck.Validator{}\n\n\tvalidLink := htmlcheck.ValidTag{\n\t\tName:  \"a\",\n\t\tAttrs: []htmlcheck.Attribute{\n\t\t\t{Name: \"id\"},\n\t\t\t{Name: \"href\", Value: \u0026htmlcheck.AttributeValue{Regex: \"^(http(s|))://.*\"}}, // valid regex for href attribute value\n\t\t\t{Name: \"target\", Value: \u0026htmlcheck.AttributeValue{List: []string{\"_target\", \"_blank\"}}}, // valid values for target attribute value\n\t\t},\n\t\tIsSelfClosing: false,\n\t}\n\n\tvalidator.AddValidTag(validLink)\n\n\t// first check\n\terr := validator.ValidateHtmlString(\"\u003ca href='http://google.com'\u003em\u003c/a\u003e\").Join()\n\tif err == nil {\n\t\tfmt.Println(\"ok\")\n\t} else {\n\t\tfmt.Println(err)\n\t}\n\n\t// second check\n\t// notice the missing / in the second \u003ca\u003e:\n\terrors := validator.ValidateHtmlString(\"\u003ca href='http://google.com'\u003em\u003ca\u003e\")\n\tif len(errors) == 0 {\n\t\tfmt.Println(\"ok\")\n\t} else {\n\t\tfmt.Println(errors)\n\t}\n}\n```\n\noutput:\n\n```\nok\ntag 'a' is not properly closed\n```\n\n## Documentation\n\n### Error Handling\n\nValidation function returns a slice of errors (`[]error`) as type of `ValidationErrors`.\n\n```go\nerrors := validator.ValidateHtmlString(\"\u003ca href='http://google.com'\u003em\u003ca\u003e\")\nif len(errors) \u003e 0 {\n\tfmt.Println(\"NOT valid\")\n}\n```\n\nYou can join all errors as one by using `Join()` function:\n\n```go\nerr := validator.ValidateHtmlString(\"\u003ca href='http://google.com'\u003em\u003ca\u003e\").Join()\nif err != nil {\n\tfmt.Println(\"NOT valid\")\n}\n```\n\n##### Stop after first error\n\nIt will return after an error occurs\n\n```go\nvalidator := htmlcheck.Validator{\n\tStopAfterFirstError: true,\n}\nerrors := validator.ValidateHtmlString(\"\u003ca href='http://google.com'\u003em\u003ca\u003e\")\nif len(errors) \u003e 0 {\n\terr := errors[0] // its the only error\n}\n```\n\n##### Check error types\n\nYou can check type of errors:\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample\u003c/summary\u003e\n\t\n```go\nvar err error\nfor _, e := range validationErrors {\n  switch v := e.(type) {\n  case htmlcheck.ErrInvAttribute:\n    err = errors.Join(err, fmt.Errorf(\"inv attr: '%s'\", v.AttributeName))\n  case htmlcheck.ErrInvAttributeValue:\n    err = errors.Join(err, fmt.Errorf(\"inv attr val: '%s'\", v.AttributeValue))\n  case htmlcheck.ErrInvClosedBeforeOpened:\n    err = errors.Join(err, fmt.Errorf(\"closed before opened: '%s'\", v.TagName))\n  case htmlcheck.ErrInvDuplicatedAttribute:\n    err = errors.Join(err, fmt.Errorf(\"dup attr: '%s'\", v.AttributeName))\n  case htmlcheck.ErrInvTag:\n    err = errors.Join(err, fmt.Errorf(\"inv tag: '%s'\", v.TagName))\n  case htmlcheck.ErrInvNotProperlyClosed:\n    err = errors.Join(err, fmt.Errorf(\"not properly closed: '%s'\", v.TagName))\n  case htmlcheck.ErrInvEOF:\n    err = errors.Join(err, fmt.Errorf(\"EOF\"))\n  default:\n    err = errors.Join(err, fmt.Errorf(\"Validation error: '%s'\", e.Error()))\n  }\n}\n```\n\u003c/details\u003e\n\n#### Register Callback\n\n```go\nv.RegisterCallback(func(tagName string, attributeName string, value string, reason ErrorReason) error {\n\tif reason == InvTag || reason == InvAttribute {\n\t\treturn fmt.Errorf(\"validation error: tag '%s', attr: %s\", tagName, attributeName)\n\t}\n\treturn nil\n})\n```\n\n### Validator Functions\n\n##### AddValidTag\n\n```go\nvalidator := htmlcheck.Validator{}\nvalidator.AddValidTag(ValidTag{\n\tName:          \"b\",\n\tIsSelfClosing: false,\n})\n```\n\n##### AddValidTags\n\n```go\nvalidator := htmlcheck.Validator{}\nvalidator.AddValidTags([]*htmlcheck.ValidTag{\n\t{ Name: \"div\" },\n\t{ Name: \"p\" },\n})\n```\n\n##### AddGroup / AddGroups\n\nYou can group attributes to use in valid tags by group name\n\n```go\nvalidator := htmlcheck.Validator{}\n// consider it should only accept http/https urls in some attributes in this example\nhttpRegex := \u0026htmlcheck.AttributeValue{Regex: \"^(http(s|))://.*\"}\nvalidator.AddGroup(\u0026htmlcheck.TagGroup{\n\tName:  \"valid-links\",\n\tAttrs: []htmlcheck.Attribute{\n\t\t{Name: \"href\", Value: httpRegex},\n\t\t{Name: \"src\", Value: httpRegex},\n\t},\n})\nvalidator.AddValidTag(htmlcheck.ValidTag{ Name: \"a\", Groups: []string{\"valid-links\"} })\nvalidator.AddValidTag(htmlcheck.ValidTag{ Name: \"img\", Groups: []string{\"valid-links\"} })\n```\n\n### Types\n\n#### ValidTag\n\n| Field            | Type          | Description                                                      |\n| ---------------- | ------------- | ---------------------------------------------------------------- |\n| `Name`           | `string`      | Name of tag such as `div`, `a`, `p`, `span`, etc.                |\n| `Attrs`          | `[]Attribute` | Valid Attribute list for the tag                                 |\n| `AttrRegex`      | `string`      | Attributes that match the regex are valid                        |\n| `AttrStartsWith` | `string`      | Attributes that starts with the given input are valid            |\n| `Groups`         | `[]string`    | Group list                                                       |\n| `IsSelfClosing`  | `bool`        | If true, tag will be valid without closing tag, default: `false` |\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample\u003c/summary\u003e\n\t\n```go\nvalidator.AddValidTags([]*htmlcheck.ValidTag{\n  { Name: \"div\", Attrs: []htmlcheck.Attribute{ {Name: \"id\"} } },\n  { Name: \"p\", AttrStartsWith: \"data-\" },\n  { Name: \"a\", AttrRegex: \"^(data-).+\" },\n})\n```\n\u003c/details\u003e\n\n#### Attribute\n\n| Field   | Type              | Description                                              |\n| ------- | ----------------- | -------------------------------------------------------- |\n| `Name`  | `string`          | Name of attribute such as `href`, `class`, `style`, etc. |\n| `Value` | `*AttributeValue` | Valid values for the attribute                           |\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample\u003c/summary\u003e\n\t\n```go\nvalidLink := htmlcheck.ValidTag{\n  Name:  \"a\",\n  Attrs: []htmlcheck.Attribute{\n    {Name: \"id\"},\n    {Name: \"href\", Value: \u0026htmlcheck.AttributeValue{Regex: \"^(http(s|))://.*\"}}, // valid regex for href attribute value\n    {Name: \"target\", Value: \u0026htmlcheck.AttributeValue{List: []string{\"_target\", \"_blank\"}}}, // valid values for target attribute value\n  },\n}\n```\n\u003c/details\u003e\n\n#### AttributeValue\n\n| Field        | Type       | Description                                                    |\n| ------------ | ---------- | -------------------------------------------------------------- |\n| `List`       | `[]string` | List of valid attribute values (for example valid class names) |\n| `Regex`      | `string`   | Attribute values that match the regex are valid                |\n| `StartsWith` | `string`   | Attributes that starts with the given input are valid          |\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample\u003c/summary\u003e\n\t\n```go\nvalidLink := htmlcheck.ValidTag{\n  Name:  \"a\",\n  Attrs: []htmlcheck.Attribute{\n    {Name: \"id\"},\n    {Name: \"href\", Value: \u0026htmlcheck.AttributeValue{Regex: \"^(http(s|))://.*\"}}, // valid regex for href attribute value\n    {Name: \"target\", Value: \u0026htmlcheck.AttributeValue{List: []string{\"_target\", \"_blank\"}}}, // valid values for target attribute value\n  },\n}\n```\n\u003c/details\u003e\n\n#### TagGroup\n\n| Field   | Type          | Description                        |\n| ------- | ------------- | ---------------------------------- |\n| `Name`  | `string`      | Name of group                      |\n| `Attrs` | `[]Attribute` | Valid Attribute list for the group |\n\n\u003cdetails\u003e\n\t\u003csummary\u003eExample\u003c/summary\u003e\n\t\n```go\n// consider it should only accept http/https urls in some attributes in this example\nhttpRegex := \u0026htmlcheck.AttributeValue{Regex: \"^(http(s|))://.*\"}\nvalidator.AddGroup(\u0026htmlcheck.TagGroup{\n  Name:  \"valid-links\",\n  Attrs: []htmlcheck.Attribute{\n    {Name: \"href\", Value: httpRegex}, \n    {Name: \"src\", Value: httpRegex},\n  },\n})\n```\n\u003c/details\u003e\n\n### Error Types\n\n| Type                        | Description                                                                           |\n| --------------------------- | ------------------------------------------------------------------------------------- |\n| `ErrInvTag`                 | Tag is not valid                                                                      |\n| `ErrInvClosedBeforeOpened`  | Tag closed before opened e.g: `\u003cdiv\u003e\u003c/p\u003e\u003c/div\u003e`                                       |\n| `ErrInvNotProperlyClosed`   | Tag is opened but not closed e.g: `\u003cdiv\u003e\u003cp\u003e\u003c/div\u003e`                                    |\n| `ErrInvAttribute`           | An attribute in tag is not valid                                                      |\n| `ErrInvAttributeValue`      | Value of the attribute is not valid                                                   |\n| `ErrInvDuplicatedAttribute` | Duplicate attribute e.g: `\u003ca href='..' href='..'\u003e\u003c/a\u003e`                                |\n| `ErrInvEOF`                 | This error occurs when parsing is done. It will not be added in the output error list |\n\n## Contributing\n\nAnyone can contribute by opening issue or pull-request\n\n## License\n\nDistributed under the GPL License. See `LICENSE` for more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanilsenay%2Fhtmlcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanilsenay%2Fhtmlcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanilsenay%2Fhtmlcheck/lists"}