pug-tail 0.1.0-alpha.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.

Potentially problematic release.


This version of pug-tail might be problematic. Click here for more details.

Files changed (126) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +318 -0
  4. package/dist/cli/config/loader.d.ts +9 -0
  5. package/dist/cli/config/loader.d.ts.map +1 -0
  6. package/dist/cli/config/loader.js +82 -0
  7. package/dist/cli/config/loader.js.map +1 -0
  8. package/dist/cli/config/matcher.d.ts +3 -0
  9. package/dist/cli/config/matcher.d.ts.map +1 -0
  10. package/dist/cli/config/matcher.js +29 -0
  11. package/dist/cli/config/matcher.js.map +1 -0
  12. package/dist/cli/config/types.d.ts +26 -0
  13. package/dist/cli/config/types.d.ts.map +1 -0
  14. package/dist/cli/config/types.js +2 -0
  15. package/dist/cli/config/types.js.map +1 -0
  16. package/dist/cli/dataLoader.d.ts +8 -0
  17. package/dist/cli/dataLoader.d.ts.map +1 -0
  18. package/dist/cli/dataLoader.js +70 -0
  19. package/dist/cli/dataLoader.js.map +1 -0
  20. package/dist/cli/dependencyTracker.d.ts +19 -0
  21. package/dist/cli/dependencyTracker.d.ts.map +1 -0
  22. package/dist/cli/dependencyTracker.js +149 -0
  23. package/dist/cli/dependencyTracker.js.map +1 -0
  24. package/dist/cli/fileProcessor.d.ts +32 -0
  25. package/dist/cli/fileProcessor.d.ts.map +1 -0
  26. package/dist/cli/fileProcessor.js +218 -0
  27. package/dist/cli/fileProcessor.js.map +1 -0
  28. package/dist/cli/pathResolver.d.ts +12 -0
  29. package/dist/cli/pathResolver.d.ts.map +1 -0
  30. package/dist/cli/pathResolver.js +35 -0
  31. package/dist/cli/pathResolver.js.map +1 -0
  32. package/dist/cli/watcher.d.ts +22 -0
  33. package/dist/cli/watcher.d.ts.map +1 -0
  34. package/dist/cli/watcher.js +186 -0
  35. package/dist/cli/watcher.js.map +1 -0
  36. package/dist/cli.d.ts +3 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +624 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/core/astTransformer.d.ts +32 -0
  41. package/dist/core/astTransformer.d.ts.map +1 -0
  42. package/dist/core/astTransformer.js +532 -0
  43. package/dist/core/astTransformer.js.map +1 -0
  44. package/dist/core/componentRegistry.d.ts +14 -0
  45. package/dist/core/componentRegistry.d.ts.map +1 -0
  46. package/dist/core/componentRegistry.js +32 -0
  47. package/dist/core/componentRegistry.js.map +1 -0
  48. package/dist/core/errorHandler.d.ts +24 -0
  49. package/dist/core/errorHandler.d.ts.map +1 -0
  50. package/dist/core/errorHandler.js +102 -0
  51. package/dist/core/errorHandler.js.map +1 -0
  52. package/dist/core/slotResolver.d.ts +9 -0
  53. package/dist/core/slotResolver.d.ts.map +1 -0
  54. package/dist/core/slotResolver.js +88 -0
  55. package/dist/core/slotResolver.js.map +1 -0
  56. package/dist/index.d.ts +10 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +8 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/transform.d.ts +26 -0
  61. package/dist/transform.d.ts.map +1 -0
  62. package/dist/transform.js +247 -0
  63. package/dist/transform.js.map +1 -0
  64. package/dist/types/index.d.ts +41 -0
  65. package/dist/types/index.d.ts.map +1 -0
  66. package/dist/types/index.js +2 -0
  67. package/dist/types/index.js.map +1 -0
  68. package/dist/utils/astHelpers.d.ts +16 -0
  69. package/dist/utils/astHelpers.d.ts.map +1 -0
  70. package/dist/utils/astHelpers.js +66 -0
  71. package/dist/utils/astHelpers.js.map +1 -0
  72. package/dist/utils/attributeCategorizer.d.ts +6 -0
  73. package/dist/utils/attributeCategorizer.d.ts.map +1 -0
  74. package/dist/utils/attributeCategorizer.js +17 -0
  75. package/dist/utils/attributeCategorizer.js.map +1 -0
  76. package/dist/utils/attributes/addAttributeFallthrough.d.ts +4 -0
  77. package/dist/utils/attributes/addAttributeFallthrough.d.ts.map +1 -0
  78. package/dist/utils/attributes/addAttributeFallthrough.js +22 -0
  79. package/dist/utils/attributes/addAttributeFallthrough.js.map +1 -0
  80. package/dist/utils/attributes/createAttributesCode.d.ts +3 -0
  81. package/dist/utils/attributes/createAttributesCode.d.ts.map +1 -0
  82. package/dist/utils/attributes/createAttributesCode.js +21 -0
  83. package/dist/utils/attributes/createAttributesCode.js.map +1 -0
  84. package/dist/utils/attributes/extractAttributes.d.ts +4 -0
  85. package/dist/utils/attributes/extractAttributes.d.ts.map +1 -0
  86. package/dist/utils/attributes/extractAttributes.js +15 -0
  87. package/dist/utils/attributes/extractAttributes.js.map +1 -0
  88. package/dist/utils/attributes/findRootElements.d.ts +7 -0
  89. package/dist/utils/attributes/findRootElements.d.ts.map +1 -0
  90. package/dist/utils/attributes/findRootElements.js +36 -0
  91. package/dist/utils/attributes/findRootElements.js.map +1 -0
  92. package/dist/utils/attributes/index.d.ts +5 -0
  93. package/dist/utils/attributes/index.d.ts.map +1 -0
  94. package/dist/utils/attributes/index.js +5 -0
  95. package/dist/utils/attributes/index.js.map +1 -0
  96. package/dist/utils/babelHelpers.d.ts +3 -0
  97. package/dist/utils/babelHelpers.d.ts.map +1 -0
  98. package/dist/utils/babelHelpers.js +73 -0
  99. package/dist/utils/babelHelpers.js.map +1 -0
  100. package/dist/utils/componentDetector.d.ts +12 -0
  101. package/dist/utils/componentDetector.d.ts.map +1 -0
  102. package/dist/utils/componentDetector.js +206 -0
  103. package/dist/utils/componentDetector.js.map +1 -0
  104. package/dist/utils/dataFilesDetector.d.ts +4 -0
  105. package/dist/utils/dataFilesDetector.d.ts.map +1 -0
  106. package/dist/utils/dataFilesDetector.js +88 -0
  107. package/dist/utils/dataFilesDetector.js.map +1 -0
  108. package/dist/utils/deepClone.d.ts +5 -0
  109. package/dist/utils/deepClone.d.ts.map +1 -0
  110. package/dist/utils/deepClone.js +10 -0
  111. package/dist/utils/deepClone.js.map +1 -0
  112. package/dist/utils/index.d.ts +7 -0
  113. package/dist/utils/index.d.ts.map +1 -0
  114. package/dist/utils/index.js +7 -0
  115. package/dist/utils/index.js.map +1 -0
  116. package/dist/utils/scopeAnalyzer.d.ts +5 -0
  117. package/dist/utils/scopeAnalyzer.d.ts.map +1 -0
  118. package/dist/utils/scopeAnalyzer.js +267 -0
  119. package/dist/utils/scopeAnalyzer.js.map +1 -0
  120. package/dist/utils/usageDetector.d.ts +8 -0
  121. package/dist/utils/usageDetector.d.ts.map +1 -0
  122. package/dist/utils/usageDetector.js +148 -0
  123. package/dist/utils/usageDetector.js.map +1 -0
  124. package/docs/COMPONENTS.md +708 -0
  125. package/docs/CONFIGURATION.md +708 -0
  126. package/package.json +103 -0
@@ -0,0 +1,708 @@
1
+ # Component DSL Reference
2
+
3
+ This document provides a comprehensive reference for pug-tail's component DSL.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Component Definition](#component-definition)
8
+ - [Component Calls](#component-calls)
9
+ - [Named Slots](#named-slots)
10
+ - [Props and Attrs](#props-and-attrs)
11
+ - [Attribute Fallthrough](#attribute-fallthrough)
12
+ - [Scope Isolation](#scope-isolation)
13
+ - [Advanced Patterns](#advanced-patterns)
14
+ - [Integration with Pug Features](#integration-with-pug-features)
15
+
16
+ ## Component Definition
17
+
18
+ ### Basic Syntax
19
+
20
+ ```pug
21
+ component ComponentName()
22
+ // component body
23
+ ```
24
+
25
+ **Rules**:
26
+ - Component names must start with an uppercase letter
27
+ - Components are defined using the `component` keyword
28
+ - Component body can contain any valid Pug markup
29
+ - Components are block-scoped (defined where declared)
30
+
31
+ ### Example
32
+
33
+ ```pug
34
+ component Card()
35
+ .card
36
+ .card-header
37
+ h2 Default Title
38
+ .card-body
39
+ p Default content
40
+ ```
41
+
42
+ ## Component Calls
43
+
44
+ ### Basic Syntax
45
+
46
+ ```pug
47
+ ComponentName()
48
+ ```
49
+
50
+ **Rules**:
51
+ - Component calls look like function calls with uppercase names
52
+ - Arguments are passed as Pug attributes
53
+ - Child content is provided via slots
54
+
55
+ ### With Arguments
56
+
57
+ ```pug
58
+ component Button()
59
+ - const { label, type = "button" } = $props
60
+ button(type=type)= label
61
+
62
+ Button(label="Click me", type="submit")
63
+ Button(label="Cancel") // Uses default type="button"
64
+ ```
65
+
66
+ ### With Slots
67
+
68
+ ```pug
69
+ component Card()
70
+ .card
71
+ slot(header)
72
+ slot(body)
73
+
74
+ Card()
75
+ slot(header)
76
+ h1 Title
77
+ slot(body)
78
+ p Content
79
+ ```
80
+
81
+ ## Named Slots
82
+
83
+ ### Defining Slots
84
+
85
+ ```pug
86
+ component Layout()
87
+ header
88
+ slot(header)
89
+ p Default header
90
+
91
+ main
92
+ slot(main)
93
+ p Default main content
94
+
95
+ footer
96
+ slot(footer)
97
+ p Default footer
98
+ ```
99
+
100
+ **Features**:
101
+ - `slot(name)` defines a named slot
102
+ - Content inside slot tag is the default (used if no content provided)
103
+ - Slots can be nested
104
+
105
+ ### Using Slots
106
+
107
+ ```pug
108
+ Layout()
109
+ slot(header)
110
+ h1 My Site
111
+
112
+ slot(main)
113
+ article
114
+ p Main content
115
+
116
+ slot(footer)
117
+ p Copyright 2026
118
+ ```
119
+
120
+ **Rules**:
121
+ - Slot names must match between definition and usage
122
+ - Slots can be provided in any order
123
+ - Unmatched slots use default content
124
+ - Extra slots (not defined) are ignored
125
+
126
+ ### Nested Components and Slots
127
+
128
+ ```pug
129
+ component Page()
130
+ Layout()
131
+ slot(header)
132
+ slot(pageHeader) // Expose slot to parent
133
+ slot(main)
134
+ slot(pageMain)
135
+
136
+ Page()
137
+ slot(pageHeader)
138
+ h1 Welcome
139
+ slot(pageMain)
140
+ p Content
141
+ ```
142
+
143
+ ## Props and Attrs
144
+
145
+ ### $props - Component Properties
146
+
147
+ Props are explicitly declared properties that the component expects.
148
+
149
+ ```pug
150
+ component Button()
151
+ - const { label, type = "button", disabled = false } = $props
152
+ button(type=type disabled=disabled)= label
153
+
154
+ Button(label="Submit", type="submit")
155
+ ```
156
+
157
+ **Features**:
158
+ - Use JavaScript destructuring syntax
159
+ - Support default values
160
+ - Support renaming: `{ class: className }`
161
+ - Type-safe (values are passed as-is)
162
+
163
+ ### $attrs - Additional Attributes
164
+
165
+ Attrs are all other attributes not declared in `$props`.
166
+
167
+ ```pug
168
+ component Card()
169
+ - const { title } = $props
170
+ - const { class: className = "card" } = $attrs
171
+
172
+ .card(class=className)
173
+ h2= title
174
+
175
+ Card(title="Hello", class="custom-card", data-id="123")
176
+ // title → $props
177
+ // class, data-id → $attrs
178
+ ```
179
+
180
+ **Automatic Categorization**:
181
+
182
+ pug-tail automatically splits component arguments:
183
+ 1. Analyzes `$props` destructuring
184
+ 2. Puts declared properties in `$props`
185
+ 3. Puts everything else in `$attrs`
186
+
187
+ ### Legacy attributes
188
+
189
+ The traditional `attributes` object still works:
190
+
191
+ ```pug
192
+ component Card()
193
+ - const { title, ...attrs } = attributes
194
+ .card&attributes(attrs)
195
+ h2= title
196
+
197
+ Card(title="Hello", class="custom")
198
+ ```
199
+
200
+ **Recommendation**: Use `$props`/`$attrs` for new code. It's more explicit and follows Vue/React conventions.
201
+
202
+ ## Attribute Fallthrough
203
+
204
+ ### Automatic Fallthrough
205
+
206
+ By default, `$attrs` are automatically applied to the root element:
207
+
208
+ ```pug
209
+ component Card()
210
+ .card
211
+ h2 Title
212
+
213
+ Card(class="my-card", id="card-1", data-test="value")
214
+ ```
215
+
216
+ **Output**:
217
+ ```html
218
+ <div class="card my-card" id="card-1" data-test="value">
219
+ <h2>Title</h2>
220
+ </div>
221
+ ```
222
+
223
+ **Rules**:
224
+ - Applies only to single root element
225
+ - Classes are merged (not replaced)
226
+ - Other attributes override component's attributes
227
+
228
+ ### Disabling Automatic Fallthrough
229
+
230
+ Use `&attributes()` explicitly to control where attrs are applied:
231
+
232
+ ```pug
233
+ component Input()
234
+ .wrapper
235
+ label Label
236
+ input.field&attributes(attributes)
237
+
238
+ Input(type="text", class="primary")
239
+ ```
240
+
241
+ **Output**:
242
+ ```html
243
+ <div class="wrapper">
244
+ <label>Label</label>
245
+ <input class="field primary" type="text"/>
246
+ </div>
247
+ ```
248
+
249
+ The explicit `&attributes(attributes)` disables automatic fallthrough to `.wrapper`.
250
+
251
+ ### Using $attrs Explicitly
252
+
253
+ ```pug
254
+ component Card()
255
+ - const { title } = $props
256
+
257
+ .card&attributes($attrs)
258
+ h2= title
259
+
260
+ Card(title="Test", class="my-card")
261
+ ```
262
+
263
+ Using `&attributes($attrs)` also disables automatic fallthrough.
264
+
265
+ ### Multiple Root Elements
266
+
267
+ Automatic fallthrough is disabled with multiple root elements:
268
+
269
+ ```pug
270
+ component Split()
271
+ .left
272
+ slot(left)
273
+ .right
274
+ slot(right)
275
+
276
+ Split(class="container")
277
+ // class="container" is NOT applied (multiple roots)
278
+ ```
279
+
280
+ **Workaround**:
281
+ ```pug
282
+ component Split()
283
+ - const { class: className } = $attrs
284
+ .split(class=className)
285
+ .left
286
+ slot(left)
287
+ .right
288
+ slot(right)
289
+ ```
290
+
291
+ ## Scope Isolation
292
+
293
+ ### Strict Mode (Default)
294
+
295
+ Components cannot access external variables:
296
+
297
+ ```pug
298
+ - const message = 'Hello'
299
+
300
+ component Card()
301
+ p= message // ❌ Error: references external variable "message"
302
+
303
+ Card()
304
+ ```
305
+
306
+ **Fix**: Pass via props:
307
+ ```pug
308
+ - const message = 'Hello'
309
+
310
+ component Card()
311
+ - const { text } = $props
312
+ p= text
313
+
314
+ Card(text=message) // ✅ OK
315
+ ```
316
+
317
+ ### Allowed Identifiers
318
+
319
+ These are always accessible:
320
+
321
+ **JavaScript globals**:
322
+ - `console`, `Math`, `Date`, `JSON`, `Object`, `Array`
323
+ - `String`, `Number`, `Boolean`, `RegExp`, `Error`
324
+ - `Promise`, `Set`, `Map`, `WeakSet`, `WeakMap`
325
+ - `parseInt`, `parseFloat`, `isNaN`, `isFinite`
326
+ - `encodeURI`, `decodeURI`, `encodeURIComponent`, `decodeURIComponent`
327
+
328
+ **Pug built-ins**:
329
+ - `attributes`, `block`
330
+
331
+ **pug-tail keywords**:
332
+ - `$props`, `$attrs`
333
+
334
+ ### Configuration
335
+
336
+ Control validation mode in config file:
337
+
338
+ ```javascript
339
+ // pugtail.config.js
340
+ export default {
341
+ validation: {
342
+ scopeIsolation: 'error', // 'error' | 'warn' | 'off'
343
+ allowedGlobals: ['myHelper', 'APP_VERSION']
344
+ }
345
+ }
346
+ ```
347
+
348
+ **Modes**:
349
+ - `'error'` (default): Compilation fails on external references
350
+ - `'warn'`: Logs warnings but compiles successfully
351
+ - `'off'`: Disables validation (legacy compatibility)
352
+
353
+ ### Custom Allowed Globals
354
+
355
+ Add project-specific globals:
356
+
357
+ ```javascript
358
+ // pugtail.config.js
359
+ export default {
360
+ validation: {
361
+ scopeIsolation: 'error',
362
+ allowedGlobals: [
363
+ 'formatDate', // Custom helper
364
+ 'APP_CONFIG', // Global config
365
+ '_', // Lodash
366
+ ]
367
+ }
368
+ }
369
+ ```
370
+
371
+ ## Advanced Patterns
372
+
373
+ ### Conditional Slots
374
+
375
+ ```pug
376
+ component Card()
377
+ .card
378
+ if hasHeader
379
+ .card-header
380
+ slot(header)
381
+ .card-body
382
+ slot(body)
383
+
384
+ - const hasHeader = true
385
+ Card()
386
+ slot(header)
387
+ h1 Title
388
+ slot(body)
389
+ p Content
390
+ ```
391
+
392
+ ### Iterating with Slots
393
+
394
+ ```pug
395
+ component List()
396
+ ul
397
+ each item in items
398
+ li= item
399
+
400
+ - const items = ['A', 'B', 'C']
401
+ List()
402
+ ```
403
+
404
+ ### Dynamic Attributes
405
+
406
+ ```pug
407
+ component Button()
408
+ - const { variant = 'primary' } = $props
409
+ - const classes = `btn btn-${variant}`
410
+ button(class=classes)
411
+ slot(default)
412
+ | Click me
413
+
414
+ Button(variant="secondary")
415
+ slot(default)
416
+ | Custom label
417
+ ```
418
+
419
+ ### Computed Properties
420
+
421
+ ```pug
422
+ component Price()
423
+ - const { amount, currency = 'USD' } = $props
424
+ - const formatted = new Intl.NumberFormat('en', { style: 'currency', currency }).format(amount)
425
+ span.price= formatted
426
+
427
+ Price(amount=99.99, currency="EUR")
428
+ ```
429
+
430
+ ### Wrapper Components
431
+
432
+ ```pug
433
+ component Container()
434
+ - const { maxWidth = '1200px' } = $props
435
+ - const { class: className } = $attrs
436
+ .container(class=className style=`max-width: ${maxWidth}`)
437
+ slot(default)
438
+
439
+ Container(maxWidth="800px", class="my-container")
440
+ p Content
441
+ ```
442
+
443
+ ## Integration with Pug Features
444
+
445
+ ### With Includes
446
+
447
+ ```pug
448
+ // components/Button.pug
449
+ component Button()
450
+ - const { label } = $props
451
+ button= label
452
+
453
+ // pages/index.pug
454
+ include ../components/Button.pug
455
+
456
+ Button(label="Click")
457
+ ```
458
+
459
+ ### With Extends
460
+
461
+ ```pug
462
+ // layouts/base.pug
463
+ component Layout()
464
+ html
465
+ head
466
+ block head
467
+ body
468
+ slot(content)
469
+
470
+ // pages/home.pug
471
+ include ../layouts/base.pug
472
+
473
+ extends ../layouts/base.pug
474
+
475
+ block head
476
+ title Home
477
+
478
+ Layout()
479
+ slot(content)
480
+ h1 Home Page
481
+ ```
482
+
483
+ ### With Mixins
484
+
485
+ ```pug
486
+ mixin icon(name)
487
+ i(class=`icon-${name}`)
488
+
489
+ component Button()
490
+ - const { icon } = $props
491
+ button
492
+ +icon(icon)
493
+ slot(default)
494
+
495
+ Button(icon="star")
496
+ slot(default)
497
+ | Favorite
498
+ ```
499
+
500
+ ### With Filters
501
+
502
+ ```pug
503
+ component Code()
504
+ pre
505
+ code
506
+ slot(default)
507
+
508
+ Code()
509
+ slot(default)
510
+ :markdown-it
511
+ # Markdown content
512
+ This is **bold**
513
+ ```
514
+
515
+ ## Best Practices
516
+
517
+ ### 1. Keep Components Focused
518
+
519
+ Each component should have a single, clear responsibility:
520
+
521
+ ```pug
522
+ // ✅ Good - Focused component
523
+ component Button()
524
+ button
525
+ slot(default)
526
+
527
+ // ❌ Avoid - Too much responsibility
528
+ component ButtonWithModalAndTooltip()
529
+ // ...
530
+ ```
531
+
532
+ ### 2. Use Props for Data, Attrs for Styling
533
+
534
+ ```pug
535
+ component Card()
536
+ - const { title, description } = $props // Data
537
+ - const { class: className } = $attrs // Styling
538
+
539
+ .card(class=className)
540
+ h2= title
541
+ p= description
542
+ ```
543
+
544
+ ### 3. Provide Sensible Defaults
545
+
546
+ ```pug
547
+ component Button()
548
+ - const { type = "button", disabled = false } = $props
549
+ button(type=type disabled=disabled)
550
+ slot(default)
551
+ | Button
552
+ ```
553
+
554
+ ### 4. Document Complex Components
555
+
556
+ ```pug
557
+ //- Button component
558
+ //- @param {string} label - Button text
559
+ //- @param {string} type - Button type (button|submit|reset)
560
+ //- @param {boolean} disabled - Disabled state
561
+ //- @param {string} class - Additional CSS classes
562
+ component Button()
563
+ // ...
564
+ ```
565
+
566
+ ### 5. Use Descriptive Slot Names
567
+
568
+ ```pug
569
+ // ✅ Clear intent
570
+ component Card()
571
+ slot(header)
572
+ slot(body)
573
+ slot(footer)
574
+
575
+ // ❌ Unclear
576
+ component Card()
577
+ slot(a)
578
+ slot(b)
579
+ slot(c)
580
+ ```
581
+
582
+ ### 6. Avoid Deep Nesting
583
+
584
+ Limit component nesting depth for maintainability:
585
+
586
+ ```pug
587
+ // ✅ Reasonable depth
588
+ Layout()
589
+ slot(main)
590
+ Card()
591
+ slot(body)
592
+ p Content
593
+
594
+ // ❌ Too deep (hard to follow)
595
+ A()
596
+ B()
597
+ C()
598
+ D()
599
+ E()
600
+ F()
601
+ ```
602
+
603
+ ## Common Patterns
604
+
605
+ ### Card with Optional Header/Footer
606
+
607
+ ```pug
608
+ component Card()
609
+ - const { title } = $props
610
+ .card
611
+ if title
612
+ .card-header
613
+ h2= title
614
+ .card-body
615
+ slot(body)
616
+ .card-footer
617
+ slot(footer)
618
+
619
+ // With all parts
620
+ Card(title="Title")
621
+ slot(body)
622
+ p Content
623
+ slot(footer)
624
+ button OK
625
+
626
+ // Body only
627
+ Card()
628
+ slot(body)
629
+ p Content
630
+ ```
631
+
632
+ ### Modal Dialog
633
+
634
+ ```pug
635
+ component Modal()
636
+ - const { isOpen = false } = $props
637
+ if isOpen
638
+ .modal-overlay
639
+ .modal
640
+ .modal-header
641
+ slot(header)
642
+ button.close ×
643
+ .modal-body
644
+ slot(body)
645
+ .modal-footer
646
+ slot(footer)
647
+
648
+ Modal(isOpen=true)
649
+ slot(header)
650
+ h2 Confirm
651
+ slot(body)
652
+ p Are you sure?
653
+ slot(footer)
654
+ button Cancel
655
+ button OK
656
+ ```
657
+
658
+ ### Navigation Menu
659
+
660
+ ```pug
661
+ component Nav()
662
+ - const { items = [] } = $props
663
+ nav
664
+ ul
665
+ each item in items
666
+ li
667
+ a(href=item.url)= item.label
668
+
669
+ Nav(items=[{label: 'Home', url: '/'}, {label: 'About', url: '/about'}])
670
+ ```
671
+
672
+ ## Troubleshooting
673
+
674
+ ### Common Errors
675
+
676
+ **Error**: `Component "X" not found`
677
+ - **Cause**: Component not defined before use
678
+ - **Fix**: Define component before calling it
679
+
680
+ **Error**: `Component "X" references external variable "Y"`
681
+ - **Cause**: Scope isolation violation
682
+ - **Fix**: Pass variable via props or add to allowedGlobals
683
+
684
+ **Error**: `Unexpected token in $props destructuring`
685
+ - **Cause**: Invalid JavaScript syntax
686
+ - **Fix**: Check destructuring syntax
687
+
688
+ ### Debugging
689
+
690
+ Enable debug mode to see transformation details:
691
+
692
+ ```javascript
693
+ // pugtail.config.js
694
+ export default {
695
+ debug: true
696
+ }
697
+ ```
698
+
699
+ ### Getting Help
700
+
701
+ - Check [Configuration Guide](./CONFIGURATION.md) for settings
702
+ - Review [Architecture](./ARCHITECTURE.md) for internals
703
+ - See [Contributing](./CONTRIBUTING.md) for development setup
704
+ - Open an issue on GitHub with a minimal reproduction
705
+
706
+ ---
707
+
708
+ For more information, see the main [README](../README.md).