{"id":24983631,"url":"https://github.com/posthtml/sugarml","last_synced_at":"2025-04-11T20:51:20.036Z","repository":{"id":66009398,"uuid":"62177535","full_name":"posthtml/sugarml","owner":"posthtml","description":"SugarML Parser","archived":false,"fork":false,"pushed_at":"2016-11-19T00:41:54.000Z","size":53,"stargazers_count":24,"open_issues_count":0,"forks_count":1,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-10-29T21:06:08.343Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/posthtml.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}},"created_at":"2016-06-28T22:09:57.000Z","updated_at":"2023-06-07T09:24:52.000Z","dependencies_parsed_at":"2023-03-10T02:16:35.414Z","dependency_job_id":null,"html_url":"https://github.com/posthtml/sugarml","commit_stats":{"total_commits":47,"total_committers":4,"mean_commits":11.75,"dds":"0.44680851063829785","last_synced_commit":"f2a43e50a6af1fa9156bb2719df5ff34584da54d"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posthtml%2Fsugarml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posthtml%2Fsugarml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posthtml%2Fsugarml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posthtml%2Fsugarml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/posthtml","download_url":"https://codeload.github.com/posthtml/sugarml/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247838252,"owners_count":21004570,"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":"2025-02-04T09:19:55.852Z","updated_at":"2025-04-11T20:51:20.010Z","avatar_url":"https://github.com/posthtml.png","language":"JavaScript","readme":"[![npm][npm]][npm-url]\n[![deps][deps]][deps-url]\n[![tests][tests]][tests-url]\n[![coverage][cover]][cover-url]\n[![code style][style]][style-url]\n[![chat][chat]][chat-url]\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg width=\"200\" height=\"200\" title=\"SugarML\" src=\"https://d1yn1kh78jj1rr.cloudfront.net/preview/funny-sugar-skull-vector-t-shirt-design_zyKH5bO__M.jpg\"\u003e\n  \u003cimg width=\"220\" height=\"200\" title=\"PostHTML\" hspace=\"20\"     src=\"http://posthtml.github.io/posthtml/logo.svg\"\u003e\n  \u003ch1\u003eSugarML\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003ch2 align=\"center\"\u003eInstall\u003c/h2\u003e\n\n```bash\nnpm i -S posthtml-sugarml\n```\n\n\u003ch2 align=\"center\"\u003eUsage\u003c/h2\u003e\n\n```js\nimport { readFileSync } from 'fs'\n\nimport posthtml from 'posthtml'\nimport sugarml from 'posthtml-sugarml'\n\nconst html = readFileSync('./index.sml', 'utf8')\n\nposthtml()\n  .process(html, { parser: sugarml() })\n  .then((result) =\u003e console.log(result.html))\n```\n\nThis parser is very loose with its rules and standards. It is not responsible for enforcing good style or conventions, it's simply responsible for compiling your code. This means that you can use all sorts of invalid characters in attribute and tag names, and indentation rules are extremely loose.\n\n#### Indentation\n\nThis parser determines how tags are nested based on indentation. For example:\n\n```txt\n.first-level\n  .second-level\n    .third-level Hi!\n  .second-level\n```\n\nThis would be compiled into the following html output:\n\n```html\n\u003cdiv class=\"first-level\"\u003e\n  \u003cdiv class=\"second-level\"\u003e\n    \u003cdiv class=\"third-level\"\u003eHi!\u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"second-level\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n_As long as one line is indented with more characters than the last, it will be nested_. It doesn't matter if the number of characters that you use is consistent, or if they are spaces or tabs, or anything else. It's just the number of space characters used to indent, that's it. So you can get away with very messy code, if you want, but that's what linters are for.\n\n#### Doctypes\n\nThe doctype is a special tag, and is handled specially. If the first word on the first line of your template is `doctype`, it will be parsed as a doctype. Anything after this word will be added to the tag. So for example:\n\n```html\ndoctype html \u003e\u003e\u003e \u003c!DOCTYPE html\u003e\ndoctype HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\" \u003e\u003e\u003e \u003c!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\u003e\n```\n\n#### Tags\n\nA tag is written simply as the name of the tag. Tag names must start with a letter, then after that can contain any character other than `#`, `.`, `(`, `:`, or a space/tab. These character limitation are in place solely because of the language's syntax requirements.\n\nSo, for example, these tag names are valid and will compile correctly (although I would not advise using a tag with characters other than letters and hyphens personally):\n\n```sml\ntag\ntag!\ntag-name\ntag_name\ntag@name\n```\n\nHowever, these tag names will not compile into the results you expect\n\n```txt\ntag.name\ntag:name\ntag(name\ntag name\n```\n\nFortunately, it is not advisable to have custom html tags that look anything like these anyway, so you should be in the clear as long as you are writing reasonable html.\n\n#### Nested Tags\n\nSometimes you don't really want to indent nested tags when they are short enough to be placed on one line. When this happens, you can use a colon instead of a newline and indent to nest. For example:\n\n```html\nul\n  li: a(href='#') link 1\n  li: a(href='#') link 2\n```\n\nYou can nest as many wrapper tags on a single line as you want, as long as they are all separated by a colon immediately following the tag. However If the tag has content, it cannot be nested with a colon. For example:\n\n```\n.wrap: .wrap2: .wrap3 hello! // this works fine\n.wrap hello!: .wrap2         // this doesn't work\n```\n\n#### Shorthands\n\nThere is a shorthand for adding classes and IDs to your tags, which is exactly the same as it is in just about every other whitespace-significant html parser, and the same as CSS. For example:\n\n```html\np#main =\u003e \u003cp id=\"main\"\u003e\u003c/p\u003e\np.main =\u003e \u003cp class=\"main\"\u003e\u003c/p\u003e\np#uid.app.active =\u003e \u003cp id=\"uid\" class=\"app active\"\u003e\u003c/p\u003e\n```\n\nYou can chain as many classes and IDs in this manner as you want. If you do not use an element name, it will assume you want a div. For example:\n\n```html\n#main =\u003e \u003cdiv id=\"main\"\u003e\u003c/div\u003e\n```\n\n#### Attributes\n\nAttributes fall between parentheses directly after a tag's name. They are space-separated and can be either boolean (key, no value), or key/value pairs. For example:\n\n```html\ninput(checked) =\u003e \u003cinput checked\u003e\ninput(type='text') =\u003e \u003cinput type=\"text\"\u003e\ninput(type='checkbox' checked) =\u003e \u003cinput type=\"checkbox\" checked\u003e\n```\n\nYou can quote your attribute values or not, your choice (although we would recommend quoting). However, if the value contains a space, it must be quoted. For example:\n\n```html\ndiv(class=foo) =\u003e \u003cdiv class=\"foo\"\u003e\u003c/div\u003e\ndiv(class=foo bar) =\u003e \u003cdiv class=\"foo\" bar\u003e\u003c/div\u003e\ndiv(class='foo bar') =\u003e \u003cdiv class=\"foo bar\"\u003e\u003c/div\u003e\n```\n\nAttributes can contain any character other than `=` or a space. If you value is quoted, it can contain any value other than a quote (that will end the attribute), and if it's not quoted, it can contain any value other than a quote or space. So even attributes with special characters (found sometimes in certain front-end frameworks like vue and angular) work fine. For example:\n\n```html\ndiv(:bind='focus') \u003e\u003e\u003e \u003cdiv :bind=\"click\"\u003e\u003c/div\u003e\ndiv(*ngFor='foo in bar') \u003e\u003e\u003e \u003cdiv *ngFor=\"foo in bar\"\u003e\u003c/div\u003e\ndiv(@click='handleClick') \u003e\u003e\u003e \u003cdiv @click=\"handleClick\"\u003e\u003c/div\u003e\n```\n\n#### Content\n\nIf you need to mix up text content alongside inline tags and such, you can use the pipe character for this as such:\n\n```\np\n  | Here's some text\n  strong And some bold text\n  | ...and some more text\n```\n\nThis would render as:\n\n```html\n\u003cp\u003eHere's some text \u003cstrong\u003eand some bold text\u003c/strong\u003e ...and some more text\u003c/p\u003e\n```\n\nFor any type of content transforms that are more complex than this, we recommend checking out [posthtml-content](https://github.com/posthtml/posthtml-content).\n\n#### Comments\n\nYou can use buffered `//` and unbuffered `//-` comments. Only buffered comments would be compiled into the html output.\n\n```\n// just some text\np Paragraph after buffered comment\n\n//- will not output within markup\np Paragraph after unbuffered comment\n```\n\nThis would render as:\n\n```html\n\u003c!-- just some text --\u003e\n\u003cp\u003eParagraph after buffered comment\u003c/p\u003e\n\u003cp\u003eParagraph after unbuffered comment\u003c/p\u003e\n```\n\n\u003ch2 align=\"center\"\u003eExample\u003c/h2\u003e\n\n```\ndoctype html\nhtml\n  head\n    title Testing\n  body#index\n    h1 Hello world!\n    p.intro Wow what a great little language! Some features:\n    ul(data-list='yep' @sortable)\n      li: a(href='#') whitespace significant!\n      li: a(href='#') simple classes and ids!\n    footer\n      | Thanks for visiting\n      span see you next time!\n```\n\n```js\nimport { readFileSync } from 'fs'\n\nimport posthtml from 'posthtml'\nimport sugarml from 'posthtml-sugarml'\n\nconst html = readFileSync('./index.sml', 'utf8')\n\nposthtml()\n  .process(html, { parser: sugarml() })\n  .then((result) =\u003e console.log(result.html))\n```\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eTesting\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody id=\"index\"\u003e\n    \u003ch1\u003eHello world!\u003c/h1\u003e\n    \u003cp class=\"intro\"\u003eWow what a great little language! Some features:\u003c/p\u003e\n    \u003cul data-list=\"yep\" @sortable\u003e\n      \u003cli\u003e\u003ca href=\"#\"\u003ewhitespace significant!\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#\"\u003esimple classes and ids!\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cfooter\u003e\n      Thanks for visiting\n      \u003cspan\u003esee you next time!\u003c/span\u003e\n    \u003c/footer\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n\u003ch2 align=\"center\"\u003eMaintainer\u003c/h2\u003e\n\n\u003ctable\u003e\n  \u003ctbody\u003e\n   \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"150 height=\"150\"\n        src=\"https://avatars.githubusercontent.com/u/556932?s=125\"\u003e\n      \u003cbr /\u003e\n      \u003ca href=\"https://github.com/jescalan\"\u003eJeff Escalante\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctbody\u003e\n\u003c/table\u003e\n\n\u003ch2 align=\"center\"\u003eContributors\u003c/h2\u003e\n\n\u003ctable\u003e\n  \u003ctbody\u003e\n   \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"150 height=\"150\" src=\"https://avatars.githubusercontent.com/u/1510217?v=3\u0026s=150\"\u003e\n      \u003cbr /\u003e\n      \u003ca href=\"https://github.com/voischev\"\u003eIvan Voischev\u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cimg width=\"150\" height=\"150\"\n        src=\"https://avatars.githubusercontent.com/u/5419992?v=3\u0026s=150\"\u003e\n      \u003cbr /\u003e\n      \u003ca href=\"https://github.com/michael-ciniawsky\"\u003eMichael Ciniawsky\u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctbody\u003e\n\u003c/table\u003e\n\n[npm]: https://img.shields.io/npm/v/posthtml-sugarml.svg\n[npm-url]: https://npmjs.com/package/posthtml-sugarml\n\n[node]: https://img.shields.io/node/v/posthtml-sugarml.svg\n[node-url]: https://nodejs.org/\n\n[deps]: http://img.shields.io/david/posthtml/sugarml.svg\n[deps-url]: https://david-dm.org/posthtml/sugarml\n\n[style]: https://img.shields.io/badge/code%20style-standard-yellow.svg\n[style-url]: http://standardjs.com/\n\n[tests]: http://img.shields.io/travis/posthtml/sugarml/master.svg\n[tests-url]: https://travis-ci.org/posthtml/sugarml\n\n[cover]: http://img.shields.io/coveralls/posthtml/sugarml.svg\n[cover-url]: https://coveralls.io/github/posthtml/sugarml\n\n[chat]: https://badges.gitter.im/posthtml/posthtml.svg\n[chat-url]: https://gitter.im/posthtml/posthtml?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge\"\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposthtml%2Fsugarml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fposthtml%2Fsugarml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposthtml%2Fsugarml/lists"}