htl-to-js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 htl-to-js contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,489 @@
1
+ # htl-to-js
2
+
3
+ [![npm version](https://img.shields.io/npm/v/htl-to-js.svg)](https://www.npmjs.com/package/htl-to-js)
4
+ [![license](https://img.shields.io/npm/l/htl-to-js.svg)](./LICENSE)
5
+
6
+ Webpack loader and CLI that transpiles AEM HTL (Sightly) templates into JavaScript functions returning template literals.
7
+
8
+ ```js
9
+ import { createAccordion } from '../../jcr_root/apps/mysite/components/accordion/accordion.html';
10
+ ```
11
+
12
+ ---
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install --save-dev htl-to-js
18
+ ```
19
+
20
+ Requires Node.js >= 18.
21
+
22
+ ---
23
+
24
+ ## Storybook setup (webpack5)
25
+
26
+ Add the loader rule in `.storybook/main.js`. Since Storybook config files are often ESM, use `createRequire` to resolve the loader path:
27
+
28
+ ```js
29
+ import { createRequire } from 'module';
30
+ const require = createRequire(import.meta.url);
31
+
32
+ const config = {
33
+ // ...
34
+ async webpackFinal(config) {
35
+ config.module.rules.push({
36
+ test: /\.html$/,
37
+ include: /jcr_root[\\/]apps/, // only AEM component HTML
38
+ use: require.resolve('htl-to-js/loader'),
39
+ });
40
+ return config;
41
+ }
42
+ };
43
+
44
+ export default config;
45
+ ```
46
+
47
+ If your Storybook config uses CommonJS:
48
+
49
+ ```js
50
+ module.exports = {
51
+ async webpackFinal(config) {
52
+ config.module.rules.push({
53
+ test: /\.html$/,
54
+ include: /jcr_root[\\/]apps/,
55
+ use: require.resolve('htl-to-js/loader'),
56
+ });
57
+ return config;
58
+ }
59
+ };
60
+ ```
61
+
62
+ ---
63
+
64
+ ## HTL directive support
65
+
66
+ | Directive | Behavior |
67
+ |---|---|
68
+ | `data-sly-use.name="..."` | Becomes a function parameter |
69
+ | `data-sly-test="${cond}"` | Conditional rendering via ternary |
70
+ | `data-sly-test.varName="${cond}"` | Conditional + assigns result to variable |
71
+ | `data-sly-repeat.item="${list}"` | Loop: repeats the **whole element** per item |
72
+ | `data-sly-list.item="${list}"` | Loop: outer tag rendered once, **inner content** repeated |
73
+ | `data-sly-element="${expr}"` | Dynamic tag name (falls back to original tag) |
74
+ | `data-sly-unwrap` / `data-sly-unwrap="${cond}"` | Strips wrapper tag (always or conditionally) |
75
+ | `data-sly-set.varName="${expr}"` | Local variable declaration |
76
+ | `data-sly-text="${expr}"` | Replaces element inner content with expression |
77
+ | `data-sly-attribute.name="${expr}"` | Dynamic named attribute (null omits, true → valueless) |
78
+ | `data-sly-attribute="${obj}"` | Object spread as multiple attributes |
79
+ | `data-sly-template.name="${ @ params }"` | Named export function |
80
+ | `data-sly-call="${tmpl @ p=v}"` | Invokes a template function |
81
+ | `data-sly-resource="${expr}"` | Slot via `_includes` map |
82
+ | `data-sly-include="./file.html"` | Delegates to `_includes` map |
83
+ | `<sly>` | Transparent wrapper — only children are rendered |
84
+
85
+ Both `data-sly-repeat` and `data-sly-list` support bare forms (without `.varName`) that default to `item` as the iteration variable. They also provide a `${itemList}` status object with `index`, `count`, `first`, `last`, `odd`, and `even` properties.
86
+
87
+ ### Expression conversions
88
+
89
+ | HTL | Generated JS |
90
+ |---|---|
91
+ | `${expr @ context='html'}` | `${expr}` (context options stripped) |
92
+ | `${'string' @ i18n}` | `${_i18n?.['string'] ?? 'string'}` (dictionary lookup) |
93
+ | `${list.size}` | `${list.length}` |
94
+ | `${obj.jcr:title}` | `${obj?.['jcr:title']}` |
95
+ | `${tags @ join=', '}` | `${(tags).join(', ')}` |
96
+ | `${'pattern {0}/{1}' @ format=[a, b]}` | `${a + '/' + b}` |
97
+ | `${key in obj}` | `${(obj && key in obj)}` (null-safe) |
98
+
99
+ ### HTML escaping
100
+
101
+ Attribute values are automatically escaped via the `_htlAttr` helper:
102
+ - `&` → `&amp;`, `<` → `&lt;`, `>` → `&gt;`, `"` → `&quot;`
103
+ - Object values are serialized with `JSON.stringify`
104
+ - `null`/`undefined` produce an empty string
105
+
106
+ Dynamic named attributes (`data-sly-attribute.name`) use `_htlDynAttr`:
107
+ - `null`/`false` → attribute omitted entirely
108
+ - `true` → valueless boolean attribute (e.g. `disabled`)
109
+ - Other values → `name="escaped-value"`
110
+
111
+ ### AEM implicit objects
112
+
113
+ The following AEM implicit objects are automatically detected and added as optional parameters with safe defaults:
114
+
115
+ | Object | Default |
116
+ |---|---|
117
+ | `wcmmode` | `{ edit: false, disabled: true, preview: false }` |
118
+ | `properties` | `{}` |
119
+ | `pageProperties` | `{}` |
120
+ | `inheritedPageProperties` | `{}` |
121
+ | `component` | `{}` |
122
+ | `currentDesign` | `{}` |
123
+ | `currentStyle` | `{}` |
124
+ | `currentPage` | `{}` |
125
+ | `resource` | `{}` |
126
+ | `model` | `{}` |
127
+ | `_includes` | `{}` |
128
+ | `_i18n` | `{}` |
129
+ | `request` | `{ requestPathInfo: { selectorString: '', suffix: '', resourcePath: '' }, contextPath: '' }` |
130
+
131
+ Variables declared via `data-sly-use.X` are always included as parameters. Any other free variables referenced in directive expressions are also detected and added as parameters with `{}` defaults.
132
+
133
+ ### Automatic attribute stripping
134
+
135
+ The following AEM author-mode and analytics attributes are stripped by default:
136
+
137
+ - `data-cmp-data-layer` — analytics data layer JSON
138
+ - `data-placeholder-text` — author mode placeholder
139
+ - `data-panelcontainer` — author mode panel container
140
+ - `data-component-name` — AEM component tracking
141
+ - `data-region-id` — analytics region tracking
142
+ - `data-emptytext` — author mode empty text
143
+
144
+ > **Note:** `data-cmp-hook-*` attributes are **not** stripped by default because the AEM Core Components site JS uses them at runtime.
145
+
146
+ ### Other features
147
+
148
+ - **Void elements** (`<br>`, `<img>`, `<input>`, etc.) are rendered as self-closing tags
149
+ - **HTL block comments** (`<!--/* ... */-->`) are stripped from output
150
+ - **Regular HTML comments** (`<!-- ... -->`) are preserved
151
+ - **Self-closing `<sly/>`** is expanded automatically
152
+ - **camelCase variable names** are preserved through parse5's lowercasing
153
+ - **Reserved words** (`class`, `for`) are escaped to `_class`, `_for` in generated JS
154
+
155
+ ---
156
+
157
+ ## Generated output
158
+
159
+ Given `accordion.html`:
160
+
161
+ ```html
162
+ <div data-sly-use.accordion="com.example.Accordion"
163
+ class="cmp-accordion ${properties.theme}"
164
+ id="${accordion.id}">
165
+ <div data-sly-repeat.item="${accordion.items}"
166
+ data-sly-test="${accordion.items.size > 0}">
167
+ <span>${item.title}</span>
168
+ </div>
169
+ </div>
170
+ ```
171
+
172
+ The loader generates:
173
+
174
+ ```js
175
+ // AUTO-GENERATED from accordion.html — DO NOT EDIT
176
+
177
+ const _htlAttr = (v) => v == null ? '' : (typeof v === 'object' ? JSON.stringify(v).replace(/"/g, '&quot;') : String(v).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'));
178
+ const _htlDynAttr = (name, val) => { ... };
179
+ const _htlSpreadAttrs = (obj) => { ... };
180
+
181
+ const createAccordion = ({ accordion = {}, properties = {} } = {}) => {
182
+ return /* html */`<div class="cmp-accordion ${_htlAttr(properties?.theme)}" id="${_htlAttr(accordion?.id)}">${(accordion?.items?.length > 0) ? `${((accordion?.items) || []).map((item, _i, _arr) => { if (item == null) return ''; const itemList = { index: _i, count: _i + 1, first: _i === 0, last: _i === _arr.length - 1, odd: (_i + 1) % 2 !== 0, even: (_i + 1) % 2 === 0 }; return `<div><span>${(item?.title) ?? ''}</span></div>`; }).join('')}` : ''}</div>`;
183
+ };
184
+ module.exports = { createAccordion };
185
+ ```
186
+
187
+ ### Named templates (`data-sly-template`)
188
+
189
+ Files that define named templates generate one export per template:
190
+
191
+ ```html
192
+ <!-- template/default.html -->
193
+ <template data-sly-template.default="${ @ model }">
194
+ <a class="template" href="${model.url}">
195
+ <h3>${model.title}</h3>
196
+ </a>
197
+ </template>
198
+ ```
199
+
200
+ Generates:
201
+
202
+ ```js
203
+ const createDefault = ({ model = {} } = {}) => {
204
+ return /* html */`<a class="template" href="${_htlAttr(model?.url)}">
205
+ <h3>${(model?.title) ?? ''}</h3>
206
+ </a>`;
207
+ };
208
+ module.exports = { createDefault };
209
+ ```
210
+
211
+ ---
212
+
213
+ ## `data-sly-resource` (slots)
214
+
215
+ `data-sly-resource` loads a child JCR node at runtime in AEM — there is no equivalent in Storybook. The loader converts it to an `_includes` slot:
216
+
217
+ ```html
218
+ <!-- HTL -->
219
+ <sly data-sly-resource="${'header'}"></sly>
220
+
221
+ <!-- With @path fallback -->
222
+ <sly data-sly-resource="${@ path=model.path}"></sly>
223
+ ```
224
+
225
+ ```js
226
+ // Generated
227
+ ${_includes?.['header']?.() ?? ''}
228
+ ${_includes?.[model?.path]?.() ?? ''}
229
+ ```
230
+
231
+ Pass content via `_includes` in your story args:
232
+
233
+ ```js
234
+ export const Default = {
235
+ args: {
236
+ _includes: {
237
+ header: () => '<nav>Navigation</nav>',
238
+ }
239
+ }
240
+ }
241
+ ```
242
+
243
+ ---
244
+
245
+ ## `data-sly-call`
246
+
247
+ Calls a named template passing parameters. The binding declared via `data-sly-use` becomes a function parameter — pass the imported template module as its value.
248
+
249
+ ```html
250
+ <!-- HTL -->
251
+ <sly data-sly-use.template="default.html"
252
+ data-sly-call="${template.default @ model=item}"></sly>
253
+ ```
254
+
255
+ Generated:
256
+
257
+ ```js
258
+ ${require('./default.html').createDefault?.({ model: item, _includes }) ?? ''}
259
+ ```
260
+
261
+ When the host element is not `<sly>`, the call output is wrapped in that element:
262
+
263
+ ```html
264
+ <div class="wrapper" data-sly-call="${myFn @ text='Hi'}"></div>
265
+ ```
266
+
267
+ ```js
268
+ <div class="wrapper">${myFn?.({ text: 'Hi', _includes }) ?? ''}</div>
269
+ ```
270
+
271
+ In the story, pass the imported template function:
272
+
273
+ ```js
274
+ import { createDefault } from '../default.html';
275
+
276
+ export const Default = {
277
+ args: {
278
+ template: { default: createDefault },
279
+ item: { title: 'Card Title', url: '/path' },
280
+ }
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## `data-sly-include`
287
+
288
+ Includes another HTL file at runtime. The loader generates a slot in the `_includes` map.
289
+
290
+ ```html
291
+ <!-- Literal path -->
292
+ <sly data-sly-include="./header.html"></sly>
293
+
294
+ <!-- Dynamic path -->
295
+ <sly data-sly-include="${model.templatePath}"></sly>
296
+ ```
297
+
298
+ Generated:
299
+
300
+ ```js
301
+ // Literal path
302
+ ${_includes['./header.html']?.() ?? ''}
303
+
304
+ // Dynamic path
305
+ ${_includes[model?.templatePath]?.() ?? ''}
306
+ ```
307
+
308
+ In the story:
309
+
310
+ ```js
311
+ import { createHeader } from '../header.html';
312
+
313
+ export const Default = {
314
+ args: {
315
+ _includes: {
316
+ './header.html': createHeader,
317
+ './footer.html': () => '<footer>Footer content</footer>',
318
+ }
319
+ }
320
+ }
321
+ ```
322
+
323
+ ---
324
+
325
+ ## i18n (internationalization)
326
+
327
+ HTL expressions with `@ i18n` are converted into runtime dictionary lookups. Pass a JSON dictionary via the `_i18n` parameter to translate strings:
328
+
329
+ ```html
330
+ <!-- HTL -->
331
+ <span>${'Read more' @ i18n}</span>
332
+ <a title="${'Go home' @ i18n}" href="/">...</a>
333
+ ```
334
+
335
+ Generated:
336
+
337
+ ```js
338
+ <span>${_i18n?.['Read more'] ?? 'Read more'}</span>
339
+ <a title="${_htlAttr(_i18n?.['Go home'] ?? 'Go home')}" href="/">...</a>
340
+ ```
341
+
342
+ In the story, pass the dictionary as `_i18n`:
343
+
344
+ ```js
345
+ import dict from './i18n/es.json';
346
+
347
+ export const Spanish = {
348
+ args: {
349
+ _i18n: dict,
350
+ }
351
+ }
352
+ ```
353
+
354
+ Example `i18n/es.json`:
355
+
356
+ ```json
357
+ {
358
+ "Read more": "Leer más",
359
+ "Go home": "Ir al inicio",
360
+ "Title": "Título"
361
+ }
362
+ ```
363
+
364
+ When no dictionary is passed (or when a key is missing), the original string is used as fallback.
365
+
366
+ ---
367
+
368
+ ## `data-sly-repeat` vs `data-sly-list`
369
+
370
+ Both iterate over a list, but they differ in what gets repeated:
371
+
372
+ | | `data-sly-repeat` | `data-sly-list` |
373
+ |---|---|---|
374
+ | **Repeats** | The entire host element | Only inner content |
375
+ | **Outer tag** | Rendered once per item | Rendered once total |
376
+
377
+ ```html
378
+ <!-- repeat: <li> repeated per item -->
379
+ <li data-sly-repeat.item="${items}">${item}</li>
380
+
381
+ <!-- list: <ul> once, <li> repeated per item -->
382
+ <ul data-sly-list.item="${items}"><li>${item}</li></ul>
383
+ ```
384
+
385
+ Both support:
386
+ - Null items are automatically skipped
387
+ - A `${itemList}` status object with `index`, `count`, `first`, `last`, `odd`, `even`
388
+ - Combined `data-sly-test.var` + `data-sly-repeat` on the same element (test var is hoisted before the loop in a scoped IIFE)
389
+
390
+ ---
391
+
392
+ ## Options
393
+
394
+ Both the `transpile()` function and the webpack loader accept the following options:
395
+
396
+ ### `omitAttrs`
397
+
398
+ Array of regular expressions matching attribute names to exclude from output.
399
+
400
+ **Override in webpack loader:**
401
+
402
+ ```js
403
+ config.module.rules.push({
404
+ test: /\.html$/,
405
+ include: /jcr_root[\\/]apps/,
406
+ use: {
407
+ loader: require.resolve('htl-to-js/loader'),
408
+ options: {
409
+ omitAttrs: [
410
+ /^data-cmp-data-layer$/,
411
+ /^data-my-custom-attr/,
412
+ ]
413
+ }
414
+ }
415
+ });
416
+ ```
417
+
418
+ Pass `omitAttrs: []` to disable filtering entirely.
419
+
420
+ ### `modelTransforms`
421
+
422
+ Object mapping use-class patterns to property injections. Enables build-time property merging based on the `data-sly-use` class name.
423
+
424
+ ---
425
+
426
+ ## Programmatic API
427
+
428
+ ```ts
429
+ import { transpile } from 'htl-to-js';
430
+ import fs from 'fs';
431
+
432
+ const source = fs.readFileSync('accordion.html', 'utf8');
433
+ const jsModule = transpile(source, {
434
+ filename: 'accordion.html',
435
+ omitAttrs: [],
436
+ });
437
+
438
+ console.log(jsModule);
439
+ ```
440
+
441
+ ---
442
+
443
+ ## CLI
444
+
445
+ Generate `.template.js` files alongside their `.html` source:
446
+
447
+ ```bash
448
+ npx htl-gen "src/**/*.html"
449
+ ```
450
+
451
+ Watch mode:
452
+
453
+ ```bash
454
+ npx htl-gen --watch "components/**/*.html"
455
+ ```
456
+
457
+ Output files are placed next to the source:
458
+ ```
459
+ accordion.html → accordion.template.js
460
+ card/default.html → card/default.template.js
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Known limitations
466
+
467
+ - **`data-sly-include` with args** — passing parameters to included files (`@ wcmmode=wcmmode`) is not supported; only the path is used.
468
+ - **`data-sly-call` across files** — the called template must be imported and passed explicitly via args; cross-file resolution at build time is not supported unless the file is declared via `data-sly-use`.
469
+ - **Java expressions** in `data-sly-use` — the class path is ignored; the binding name becomes a function parameter.
470
+ - **`data-sly-use` with `@` defaults** — the default values are extracted as destructuring defaults, but complex expressions are not supported.
471
+
472
+ ---
473
+
474
+ ## Development
475
+
476
+ Written in TypeScript. Source in `src/`, compiled to `dist/`.
477
+
478
+ ```bash
479
+ npm run build # compile TypeScript
480
+ npm test # run 111 Jest tests
481
+ npm run test:watch # watch mode
482
+ npm run test:coverage # with coverage
483
+ ```
484
+
485
+ ---
486
+
487
+ ## License
488
+
489
+ [MIT](./LICENSE)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const index_1 = require("./transpiler/index");
8
+ const glob_1 = require("glob");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const args = process.argv.slice(2);
12
+ if (!args.length || args.includes('--help') || args.includes('-h')) {
13
+ console.log(`
14
+ htl-gen — transpile HTL templates to JS template string functions
15
+
16
+ Usage:
17
+ htl-gen <glob> Transpile matching files once
18
+ htl-gen --watch <glob> Watch and re-transpile on changes
19
+
20
+ Examples:
21
+ htl-gen "components/**/*.html"
22
+ htl-gen accordion.html
23
+ htl-gen --watch "src/**/*.html"
24
+ `);
25
+ process.exit(0);
26
+ }
27
+ const watchMode = args.includes('--watch') || args.includes('-w');
28
+ const patternArg = args.find(a => !a.startsWith('-'));
29
+ if (!patternArg) {
30
+ console.error('Error: no glob pattern provided.');
31
+ process.exit(1);
32
+ }
33
+ const pattern = patternArg;
34
+ function processFile(file) {
35
+ try {
36
+ const source = node_fs_1.default.readFileSync(file, 'utf8');
37
+ const output = (0, index_1.transpile)(source, { filename: file });
38
+ const outFile = file.replace(/\.html$/, '.template.js');
39
+ node_fs_1.default.writeFileSync(outFile, output, 'utf8');
40
+ console.log(`✓ ${node_path_1.default.relative(process.cwd(), file)} → ${node_path_1.default.basename(outFile)}`);
41
+ }
42
+ catch (err) {
43
+ console.error(`✗ ${node_path_1.default.relative(process.cwd(), file)}: ${err.message}`);
44
+ }
45
+ }
46
+ async function main() {
47
+ const files = await (0, glob_1.glob)(pattern, { absolute: true });
48
+ if (!files.length) {
49
+ console.warn(`No files matched: ${pattern}`);
50
+ process.exit(0);
51
+ }
52
+ for (const file of files)
53
+ processFile(file);
54
+ if (watchMode) {
55
+ console.log(`\nWatching ${files.length} file(s) for changes…\n`);
56
+ for (const file of files) {
57
+ node_fs_1.default.watch(file, () => {
58
+ console.log(`↻ ${node_path_1.default.relative(process.cwd(), file)} changed`);
59
+ processFile(file);
60
+ });
61
+ }
62
+ }
63
+ }
64
+ main(); // NOSONAR
65
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { transpile } from './transpiler/index';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transpile = void 0;
4
+ var index_1 = require("./transpiler/index");
5
+ Object.defineProperty(exports, "transpile", { enumerable: true, get: function () { return index_1.transpile; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAAtC,kGAAA,SAAS,OAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Webpack loader for HTL templates.
3
+ *
4
+ * Configuration (webpack.config.js or .storybook/main.js):
5
+ *
6
+ * module: {
7
+ * rules: [{
8
+ * test: /\.html$/,
9
+ * include: /jcr_root[\\/]apps/,
10
+ * use: 'htl-to-js/loader',
11
+ * }]
12
+ * }
13
+ *
14
+ * Then in your Storybook stories:
15
+ *
16
+ * import { createAccordion } from '../path/to/accordion.html';
17
+ */
18
+ declare function htlLoader(this: any, source: string): string;
19
+ export = htlLoader;
package/dist/loader.js ADDED
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ const index_1 = require("./transpiler/index");
3
+ /**
4
+ * Webpack loader for HTL templates.
5
+ *
6
+ * Configuration (webpack.config.js or .storybook/main.js):
7
+ *
8
+ * module: {
9
+ * rules: [{
10
+ * test: /\.html$/,
11
+ * include: /jcr_root[\\/]apps/,
12
+ * use: 'htl-to-js/loader',
13
+ * }]
14
+ * }
15
+ *
16
+ * Then in your Storybook stories:
17
+ *
18
+ * import { createAccordion } from '../path/to/accordion.html';
19
+ */
20
+ function htlLoader(source) {
21
+ this.cacheable(true);
22
+ const options = this.getOptions ? this.getOptions() : {};
23
+ try {
24
+ return (0, index_1.transpile)(source, { filename: this.resourcePath, ...options });
25
+ }
26
+ catch (err) {
27
+ this.emitError(new Error(`[htl-to-js] ${this.resourcePath}: ${err.message}`));
28
+ return 'module.exports = {};';
29
+ }
30
+ }
31
+ module.exports = htlLoader;
32
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":";AAAA,8CAA+C;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,SAAS,CAAY,MAAc;IAC1C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAErB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzD,IAAI,CAAC;QACH,OAAO,IAAA,iBAAS,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,YAAY,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC9E,OAAO,sBAAsB,CAAC;IAChC,CAAC;AACH,CAAC;AAED,iBAAS,SAAS,CAAC"}