{"id":21216682,"url":"https://github.com/chharvey/template-processor","last_synced_at":"2025-07-26T12:02:09.667Z","repository":{"id":48030561,"uuid":"147437807","full_name":"chharvey/template-processor","owner":"chharvey","description":"A lightweight class for generating markup from a template and some data.","archived":false,"fork":false,"pushed_at":"2022-12-02T10:53:51.000Z","size":308,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-09T07:04:23.416Z","etag":null,"topics":["dom","html","template"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/template-processor","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/chharvey.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}},"created_at":"2018-09-05T00:42:36.000Z","updated_at":"2021-01-25T20:32:01.000Z","dependencies_parsed_at":"2023-01-22T14:00:16.984Z","dependency_job_id":null,"html_url":"https://github.com/chharvey/template-processor","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chharvey%2Ftemplate-processor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chharvey%2Ftemplate-processor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chharvey%2Ftemplate-processor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chharvey%2Ftemplate-processor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chharvey","download_url":"https://codeload.github.com/chharvey/template-processor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243667965,"owners_count":20328036,"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":["dom","html","template"],"created_at":"2024-11-20T21:55:09.511Z","updated_at":"2025-03-15T00:41:38.874Z","avatar_url":"https://github.com/chharvey.png","language":"TypeScript","readme":"# template-processor\nA lightweight class for generating markup from a template and some data.\n\n\n## Install\n```bash\nnpm install template-processor\n```\n\n\n## Example\n\nGiven the following document,\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ctemplate\u003e\n\t\u003ca href=\"{{ url }}\"\u003e{{ text }}\u003c/a\u003e\n\u003c/template\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThe code below (JavaScript or Typescript) will append the following markup to the body.\n\n```html\n\u003ca href=\"https://www.example.com/\" rel=\"external\"\u003eAN EXAMPLE\u003c/a\u003e\n```\n\nAPI:\n\n1. Import the `Processor` class.\n2. The constructor’s `instructions` argument must be a function returning `void`.\n3. The constructor’s `instructions_async` argument, if provided, must be an asynchronous function returning a `Promise\u003cvoid\u003e`.\n\t(If providing `instructions_async`, the `instructions` argument is still required. It could be an empty function or a fallback to the async.)\n4. The `process` method returns a `DocumentFragment`.\n5. The asynchronous `processAsync` method returns a `Promise\u003cDocumentFragment\u003e`.\n\n### JavaScript\n\n1. Import the module.\n\t```js\n\tconst { Processor } = require('template-processor')\n\t```\n\n2. Get your own template \u0026 write your own instructions.\n\t```js\n\tconst template = document.querySelector('template')\n\tconst instructions = (frag, data, opts) =\u003e {\n\t\tfrag.querySelector('a').href        = data.url\n\t\tfrag.querySelector('a').textContent = (opts.uppercase) ? data.text.toUpperCase() : data.text\n\t\tif (data.url.slice(0,4) === 'http') {\n\t\t\tfrag.querySelector('a').setAttribute('rel', 'external')\n\t\t}\n\t}\n\t```\n\tIf your instructions uses I/O, you can write an asynchronous function.\n\tNote that this function must not take promises as arguments.\n\t```js\n\tconst instructionsAsync = async (frag, data, opts) =\u003e {\n\t\tawait doSomeAsyncStuff();\n\t}\n\t```\n\n3. Construct a new processor with the stuff you wrote\n\t(optionally provide the async instructions).\n\t```js\n\tlet my_processor = new Processor(template, instructions)\n\tmy_processor = new Processor(template, instructions, instructionsAsync)\n\t```\n\n4. Process some data (synchronously or asynchronously).\n\t```js\n\tconst snippet = my_processor.process({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t}, { uppercase: true })\n\tdocument.body.append(snippet)\n\n\tmy_processor.processAsync({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t}, { uppercase: true }).then((snippet) =\u003e {\n\t\tdocument.body.append(snippet)\n\t})\n\t```\n\tYou can also pass in promises for the data and options.\n\tHere’s where the promises will be awaited.\n\t```js\n\tmy_processor.processAsync(Promise.resolve({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t}), Promise.resolve({ uppercase: true })).then((snippet) =\u003e {\n\t\tdocument.body.append(snippet)\n\t})\n\t```\n\n### TypeScript\n\n1. Import the module.\n\t```ts\n\timport { Processor } from 'template-processor'\n\t```\n\n2. Get your own template \u0026 write your own instructions.\n\t```ts\n\ttype DataType = { url: string; text: string; }\n\ttype OptsType = { uppercase?: boolean; }\n\n\tconst template: HTMLTemplateElement = document.querySelector('template') !\n\tconst instructions = (frag: DocumentFragment, data: DataType, opts: OptsType): void =\u003e {\n\t\tfrag.querySelector('a').href        = data.url\n\t\tfrag.querySelector('a').textContent = (opts.uppercase) ? data.text.toUpperCase() : data.text\n\t\tif (data.url.slice(0,4) === 'http') {\n\t\t\tfrag.querySelector('a').setAttribute('rel', 'external')\n\t\t}\n\t}\n\t```\n\tIf your instructions uses I/O, you can write an asynchronous function.\n\tNote that this function must not take promises as arguments.\n\t```ts\n\tconst instructionsAsync = async (frag: DocumentFragment, data: DataType, opts: OptsType): Promise\u003cvoid\u003e =\u003e {\n\t\tawait doSomeAsyncStuff();\n\t}\n\t```\n\n3. Construct a new processor with the stuff you wrote\n\t(optionally provide the async instructions).\n\t```ts\n\tlet my_processor: Processor\u003cDataType, OptsType\u003e = new Processor(template, instructions)\n\tmy_processor = new Processor(template, instructions, instructionsAsync)\n\t```\n\n4. Process some data (synchronously or asynchronously).\n\t```ts\n\tconst snippet: DocumentFragment = my_processor.process({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t}, { uppercase: true })\n\tdocument.body.append(snippet)\n\n\tmy_processor.processAsync({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t}, { uppercase: true }).then((snippet) =\u003e {\n\t\tdocument.body.append(snippet)\n\t})\n\t```\n\tYou can also pass in promises for the data and options.\n\tHere’s where the promises will be awaited.\n\t```ts\n\tconst data: Promise\u003cDataType\u003e = Promise.resolve({\n\t\turl: 'https://www.example.com/',\n\t\ttext: 'an example',\n\t})\n\tconst opts: Promise\u003cOptsType\u003e = Promise.resolve({ uppercase: true })\n\tmy_processor.processAsync(data, opts).then((snippet) =\u003e {\n\t\tdocument.body.append(snippet)\n\t})\n\t```\n\n\n## Why?\n\nThe point is to have one template and one instruction, but tons of data.\n\n```js\nlet dataset = [\n\t{ \"name\": \"twitter\" , \"url\": \"//twitter.com/god\"    , \"text\": \"Follow God on Twitter\"        },\n\t{ \"name\": \"google\"  , \"url\": \"//plus.google.com/god\", \"text\": \"Follow God on Google+\"        },\n\t{ \"name\": \"facebook\", \"url\": \"//facebook.com/god\"   , \"text\": \"Like God on Facebook\"         },\n\t{ \"name\": \"linkedin\", \"url\": \"//linkedin.com/god\"   , \"text\": \"Connect with God on LinkedIn\" },\n\t{ \"name\": \"youtube\" , \"url\": \"//youtube.com/god\"    , \"text\": \"Watch God on YouTube\"         },\n\t// even more and more\n]\n// or it could be a promise:\ndataset = Promise.resolve([\n\t{ \"name\": \"twitter\" , \"url\": \"//twitter.com/god\"    , \"text\": \"Follow God on Twitter\"        },\n\t// even more and more\n])\n\nconst document = createDocument`\n\u003chtml\u003e\n\u003cbody\u003e\n\u003ch1\u003eSocial Media Links\u003c/h1\u003e\n\u003cul class=\"c-LinkList\"\u003e\n\t\u003ctemplate\u003e\n\t\t\u003cli class=\"c-LinkList__Item\"\u003e\n\t\t\t\u003ca class=\"c-LinkList__Link\" href=\"{{ url }}\"\u003e\n\t\t\t\t\u003ci class=\"{{ name }}\"\u003e\u003c/i\u003e\n\t\t\t\t\u003cslot name=\"text\"\u003e{{ text }}\u003c/slot\u003e\n\t\t\t\u003c/a\u003e\n\t\t\u003c/li\u003e\n\t\u003c/template\u003e\n\u003c/ul\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n`\n```\n\nSynchronously:\n```js\nconst processor = new Processor(document.querySelector('ul \u003e template'), (frag, data, opts) =\u003e {\n\tfrag.querySelector('a.c-LinkList__Link').href        = data.url\n\tfrag.querySelector('i'                 ).className   = `icon icon-${data.name}`\n\tfrag.querySelector('slot[name=\"text\"]' ).textContent = data.text\n})\n\ndocument.querySelector('ul').append(...dataset.map((data) =\u003e processor.process(data)))\n```\n\nAsynchronously:\n```js\nconst processor = new Processor(document.querySelector('ul \u003e template'), () =\u003e {}, async (frag, data, opts) =\u003e {\n\tawait doSomeAsyncStuff();\n\tfrag.querySelector('a.c-LinkList__Link').href        = data.url\n\tfrag.querySelector('i'                 ).className   = `icon icon-${data.name}`\n\tfrag.querySelector('slot[name=\"text\"]' ).textContent = data.text\n})\n\n// with promises:\ndataset.then((datapoints) =\u003e\n\tPromise.all(datapoints.map((data) =\u003e processor.processAsync(data)))\n).then((frags) =\u003e\n\tdocument.querySelector('ul').append(...frags)\n)\n\n// with await:\ndocument.querySelector('ul').append(\n\t...await Promise.all((await dataset).map((data) =\u003e processor.processAsync(data)))\n)\n```\n\nStarting in v1.2, we can do the above much more efficiently with two new static methods:\n`Processor.populateList` and `Processor.populateListAsync`.\nThey check for a `\u003ctemplate\u003e` inside the list and ensure it has the correct markup structure.\n\nSynchronously:\n```js\nProcessor.populateList(document.querySelector('ul'), (frag, data, opts) =\u003e {\n\tfrag.querySelector('a.c-LinkList__Link').href        = data.url\n\tfrag.querySelector('i'                 ).className   = `icon icon-${data.name}`\n\tfrag.querySelector('slot[name=\"text\"]' ).textContent = data.text\n}, dataset)\n```\n\nAsynchronously:\n```js\nProcessor.populateListAsync(document.querySelector('ul'), async (frag, data, opts) =\u003e {\n\tawait doSomeAsyncStuff();\n\tfrag.querySelector('a.c-LinkList__Link').href        = data.url\n\tfrag.querySelector('i'                 ).className   = `icon icon-${data.name}`\n\tfrag.querySelector('slot[name=\"text\"]' ).textContent = data.text\n}, Promise.resolve(dataset))\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchharvey%2Ftemplate-processor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchharvey%2Ftemplate-processor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchharvey%2Ftemplate-processor/lists"}