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.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +318 -0
- package/dist/cli/config/loader.d.ts +9 -0
- package/dist/cli/config/loader.d.ts.map +1 -0
- package/dist/cli/config/loader.js +82 -0
- package/dist/cli/config/loader.js.map +1 -0
- package/dist/cli/config/matcher.d.ts +3 -0
- package/dist/cli/config/matcher.d.ts.map +1 -0
- package/dist/cli/config/matcher.js +29 -0
- package/dist/cli/config/matcher.js.map +1 -0
- package/dist/cli/config/types.d.ts +26 -0
- package/dist/cli/config/types.d.ts.map +1 -0
- package/dist/cli/config/types.js +2 -0
- package/dist/cli/config/types.js.map +1 -0
- package/dist/cli/dataLoader.d.ts +8 -0
- package/dist/cli/dataLoader.d.ts.map +1 -0
- package/dist/cli/dataLoader.js +70 -0
- package/dist/cli/dataLoader.js.map +1 -0
- package/dist/cli/dependencyTracker.d.ts +19 -0
- package/dist/cli/dependencyTracker.d.ts.map +1 -0
- package/dist/cli/dependencyTracker.js +149 -0
- package/dist/cli/dependencyTracker.js.map +1 -0
- package/dist/cli/fileProcessor.d.ts +32 -0
- package/dist/cli/fileProcessor.d.ts.map +1 -0
- package/dist/cli/fileProcessor.js +218 -0
- package/dist/cli/fileProcessor.js.map +1 -0
- package/dist/cli/pathResolver.d.ts +12 -0
- package/dist/cli/pathResolver.d.ts.map +1 -0
- package/dist/cli/pathResolver.js +35 -0
- package/dist/cli/pathResolver.js.map +1 -0
- package/dist/cli/watcher.d.ts +22 -0
- package/dist/cli/watcher.d.ts.map +1 -0
- package/dist/cli/watcher.js +186 -0
- package/dist/cli/watcher.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +624 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/astTransformer.d.ts +32 -0
- package/dist/core/astTransformer.d.ts.map +1 -0
- package/dist/core/astTransformer.js +532 -0
- package/dist/core/astTransformer.js.map +1 -0
- package/dist/core/componentRegistry.d.ts +14 -0
- package/dist/core/componentRegistry.d.ts.map +1 -0
- package/dist/core/componentRegistry.js +32 -0
- package/dist/core/componentRegistry.js.map +1 -0
- package/dist/core/errorHandler.d.ts +24 -0
- package/dist/core/errorHandler.d.ts.map +1 -0
- package/dist/core/errorHandler.js +102 -0
- package/dist/core/errorHandler.js.map +1 -0
- package/dist/core/slotResolver.d.ts +9 -0
- package/dist/core/slotResolver.d.ts.map +1 -0
- package/dist/core/slotResolver.js +88 -0
- package/dist/core/slotResolver.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/transform.d.ts +26 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +247 -0
- package/dist/transform.js.map +1 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/astHelpers.d.ts +16 -0
- package/dist/utils/astHelpers.d.ts.map +1 -0
- package/dist/utils/astHelpers.js +66 -0
- package/dist/utils/astHelpers.js.map +1 -0
- package/dist/utils/attributeCategorizer.d.ts +6 -0
- package/dist/utils/attributeCategorizer.d.ts.map +1 -0
- package/dist/utils/attributeCategorizer.js +17 -0
- package/dist/utils/attributeCategorizer.js.map +1 -0
- package/dist/utils/attributes/addAttributeFallthrough.d.ts +4 -0
- package/dist/utils/attributes/addAttributeFallthrough.d.ts.map +1 -0
- package/dist/utils/attributes/addAttributeFallthrough.js +22 -0
- package/dist/utils/attributes/addAttributeFallthrough.js.map +1 -0
- package/dist/utils/attributes/createAttributesCode.d.ts +3 -0
- package/dist/utils/attributes/createAttributesCode.d.ts.map +1 -0
- package/dist/utils/attributes/createAttributesCode.js +21 -0
- package/dist/utils/attributes/createAttributesCode.js.map +1 -0
- package/dist/utils/attributes/extractAttributes.d.ts +4 -0
- package/dist/utils/attributes/extractAttributes.d.ts.map +1 -0
- package/dist/utils/attributes/extractAttributes.js +15 -0
- package/dist/utils/attributes/extractAttributes.js.map +1 -0
- package/dist/utils/attributes/findRootElements.d.ts +7 -0
- package/dist/utils/attributes/findRootElements.d.ts.map +1 -0
- package/dist/utils/attributes/findRootElements.js +36 -0
- package/dist/utils/attributes/findRootElements.js.map +1 -0
- package/dist/utils/attributes/index.d.ts +5 -0
- package/dist/utils/attributes/index.d.ts.map +1 -0
- package/dist/utils/attributes/index.js +5 -0
- package/dist/utils/attributes/index.js.map +1 -0
- package/dist/utils/babelHelpers.d.ts +3 -0
- package/dist/utils/babelHelpers.d.ts.map +1 -0
- package/dist/utils/babelHelpers.js +73 -0
- package/dist/utils/babelHelpers.js.map +1 -0
- package/dist/utils/componentDetector.d.ts +12 -0
- package/dist/utils/componentDetector.d.ts.map +1 -0
- package/dist/utils/componentDetector.js +206 -0
- package/dist/utils/componentDetector.js.map +1 -0
- package/dist/utils/dataFilesDetector.d.ts +4 -0
- package/dist/utils/dataFilesDetector.d.ts.map +1 -0
- package/dist/utils/dataFilesDetector.js +88 -0
- package/dist/utils/dataFilesDetector.js.map +1 -0
- package/dist/utils/deepClone.d.ts +5 -0
- package/dist/utils/deepClone.d.ts.map +1 -0
- package/dist/utils/deepClone.js +10 -0
- package/dist/utils/deepClone.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/scopeAnalyzer.d.ts +5 -0
- package/dist/utils/scopeAnalyzer.d.ts.map +1 -0
- package/dist/utils/scopeAnalyzer.js +267 -0
- package/dist/utils/scopeAnalyzer.js.map +1 -0
- package/dist/utils/usageDetector.d.ts +8 -0
- package/dist/utils/usageDetector.d.ts.map +1 -0
- package/dist/utils/usageDetector.js +148 -0
- package/dist/utils/usageDetector.js.map +1 -0
- package/docs/COMPONENTS.md +708 -0
- package/docs/CONFIGURATION.md +708 -0
- package/package.json +103 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0-alpha.0] - 2026-01-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- Component system with multiple named slots (Vue/Svelte-like syntax)
|
|
14
|
+
- Props/attrs separation (Vue 3-style)
|
|
15
|
+
- Zero runtime cost - fully expanded at build time
|
|
16
|
+
- Works with standard Pug features (includes, extends, mixins, etc.)
|
|
17
|
+
- Programmatic API (`transform()` function)
|
|
18
|
+
- CLI tool with watch mode support
|
|
19
|
+
- Data file loading system (`$dataFiles` directive)
|
|
20
|
+
- Scope isolation validation
|
|
21
|
+
- TypeScript type definitions
|
|
22
|
+
- Comprehensive test suite
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
- **Component Definition**: Define reusable components with `component` keyword
|
|
27
|
+
- **Named Slots**: Multiple named slots with default content support
|
|
28
|
+
- **Props/Attrs Separation**: Clear separation of props and attrs (Vue 3-style with `$props`/`$attrs`)
|
|
29
|
+
- **Attrs Inheritance**: Automatic attribute passthrough with `&attributes()`
|
|
30
|
+
- **Control Flow**: Pug control structures (if/unless/each/while/case) work seamlessly in components
|
|
31
|
+
- **Dynamic Data**: Pass external data (from CLI, config, or frontmatter) as component attributes
|
|
32
|
+
- **Nested Components**: Components can use other components
|
|
33
|
+
- **Scope Isolation**: Component scope validation with configurable modes (error/warn/off)
|
|
34
|
+
- **Watch Mode**: CLI supports file watching for development
|
|
35
|
+
- **Error Handling**: Detailed error messages with file locations
|
|
36
|
+
|
|
37
|
+
[0.1.0-alpha.0]: https://github.com/megurock/pug-tail/releases/tag/v0.1.0-alpha.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eiji Meguro
|
|
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,318 @@
|
|
|
1
|
+
# pug-tail
|
|
2
|
+
|
|
3
|
+
A build tool that brings Vue/Svelte-like component syntax to Pug.
|
|
4
|
+
|
|
5
|
+
<img src="./images/pug-tail-logo.png" alt="pug-tail logo"/>
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/pug-tail)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
[日本語 (Japanese)](README-ja.md)
|
|
11
|
+
|
|
12
|
+
### 🤖 Note on AI-Assisted Development
|
|
13
|
+
|
|
14
|
+
> [!NOTE]
|
|
15
|
+
> This is an **experimental project** developed heavily with the assistance of Large Language Models (LLMs).
|
|
16
|
+
>
|
|
17
|
+
> While functional, the codebase may contain unconventional solutions or require further refinement. Feedback and contributions are highly welcome.
|
|
18
|
+
|
|
19
|
+
## ✨ Features
|
|
20
|
+
|
|
21
|
+
- 🎯 **Multiple Named Slots** - Intuitive component syntax like Vue and Svelte.
|
|
22
|
+
- 📦 **Props/Attrs Separation** - Clear separation of props and attributes, inspired by Vue 3.
|
|
23
|
+
- ⚡ **Zero Runtime Cost** - Fully expanded at build time, generating a pure Pug AST.
|
|
24
|
+
- 🔄 **Control Flow Support** - Use `if`/`unless`/`each`/`while`/`case` within components.
|
|
25
|
+
- 🔧 **Pug Integration** - Works with other Pug features like `include`, `extends`, and `mixin`.
|
|
26
|
+
- 🚫 **No Runtime Extensions** - No modifications to Pug's runtime.
|
|
27
|
+
- ⚙️ **Powerful CLI** - Supports watch mode, configuration files, and data file loading.
|
|
28
|
+
- 📝 **Built with TypeScript** - Type-safe implementation and a great developer experience.
|
|
29
|
+
|
|
30
|
+
## 🌐 Live Demo
|
|
31
|
+
|
|
32
|
+
Explore pug-tail features in action:
|
|
33
|
+
|
|
34
|
+
- **[Main Demo](https://megurock.github.io/pug-tail/)** - Interactive examples and feature showcase
|
|
35
|
+
- **[CLI Guide](https://megurock.github.io/pug-tail/cli-guide.html)** - Complete CLI documentation
|
|
36
|
+
- **[Slots & Props](https://megurock.github.io/pug-tail/about.html)** - Advanced usage examples
|
|
37
|
+
|
|
38
|
+
## 🤔 Why pug-tail?
|
|
39
|
+
|
|
40
|
+
Pug's mixins can only accept a single content block, and named blocks are limited to `extends`. pug-tail solves this limitation at the AST level, enabling a component system with multiple named slots.
|
|
41
|
+
|
|
42
|
+
### Before (Pug's mixin limitation)
|
|
43
|
+
|
|
44
|
+
```pug
|
|
45
|
+
mixin Card()
|
|
46
|
+
.card
|
|
47
|
+
.card-header
|
|
48
|
+
block
|
|
49
|
+
.card-body
|
|
50
|
+
// Multiple blocks are not possible
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### After (pug-tail)
|
|
54
|
+
|
|
55
|
+
```pug
|
|
56
|
+
component Card()
|
|
57
|
+
.card
|
|
58
|
+
.card-header
|
|
59
|
+
slot(header)
|
|
60
|
+
p Default Header
|
|
61
|
+
.card-body
|
|
62
|
+
slot(body)
|
|
63
|
+
p Default Body
|
|
64
|
+
.card-footer
|
|
65
|
+
slot(footer)
|
|
66
|
+
p Default Footer
|
|
67
|
+
|
|
68
|
+
// Usage
|
|
69
|
+
Card()
|
|
70
|
+
slot(header)
|
|
71
|
+
h1 Title
|
|
72
|
+
slot(body)
|
|
73
|
+
p Content
|
|
74
|
+
slot(footer)
|
|
75
|
+
button OK
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 📦 Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install pug-tail
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
or
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
yarn add pug-tail
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 🚀 Quick Start
|
|
91
|
+
|
|
92
|
+
### Using the CLI
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Basic usage
|
|
96
|
+
npx pug-tail src/index.pug -o dist/index.html
|
|
97
|
+
|
|
98
|
+
# Convert a directory
|
|
99
|
+
npx pug-tail src -o dist
|
|
100
|
+
|
|
101
|
+
# Development with watch mode
|
|
102
|
+
npx pug-tail src -o dist -w
|
|
103
|
+
|
|
104
|
+
# Use with a data file
|
|
105
|
+
npx pug-tail src/index.pug -o dist/index.html --obj data.json
|
|
106
|
+
|
|
107
|
+
# Use a configuration file
|
|
108
|
+
npx pug-tail -c pugtail.config.js
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Key CLI Options**:
|
|
112
|
+
- `-o, --out <dir>` - Output directory or file
|
|
113
|
+
- `-w, --watch` - Watch mode (monitors file changes)
|
|
114
|
+
- `-c, --config <path>` - Path to the configuration file
|
|
115
|
+
- `--obj <path>` - Path to a data file (JSON/YAML)
|
|
116
|
+
- `--pretty` - Formats the HTML output
|
|
117
|
+
- `--basedir <path>` - Base directory for absolute includes
|
|
118
|
+
- `-d, --debug` - Enable debug output (shows details like component registration, slot detection, etc.)
|
|
119
|
+
|
|
120
|
+
#### Per-Page Data Files
|
|
121
|
+
|
|
122
|
+
You can load page-specific external data files using the `$dataFiles` directive within your entry Pug file.
|
|
123
|
+
|
|
124
|
+
```pug
|
|
125
|
+
// pages/index.pug
|
|
126
|
+
- const $dataFiles = ['/data/navigation.json', '/data/footer.json']
|
|
127
|
+
|
|
128
|
+
// Data from these files will be available
|
|
129
|
+
header
|
|
130
|
+
each item in navigation
|
|
131
|
+
a(href=item.url)= item.label
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Important Constraints**:
|
|
135
|
+
- Only available in entry files (top-level files being compiled).
|
|
136
|
+
- Cannot be used within included component files.
|
|
137
|
+
- Absolute paths (starting with `/`) are resolved relative to `basedir`.
|
|
138
|
+
- Relative paths are resolved relative to the entry file.
|
|
139
|
+
|
|
140
|
+
See the [Configuration Guide](./docs/CONFIGURATION.md) for more details.
|
|
141
|
+
|
|
142
|
+
### Programmatic API
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { transform } from 'pug-tail'
|
|
146
|
+
|
|
147
|
+
const source = `
|
|
148
|
+
component Card()
|
|
149
|
+
.card
|
|
150
|
+
slot(header)
|
|
151
|
+
slot(body)
|
|
152
|
+
|
|
153
|
+
Card()
|
|
154
|
+
slot(header)
|
|
155
|
+
h1 Hello
|
|
156
|
+
slot(body)
|
|
157
|
+
p World
|
|
158
|
+
`
|
|
159
|
+
|
|
160
|
+
const result = transform(source, { output: 'html' })
|
|
161
|
+
console.log(result.html)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## 📖 Component DSL
|
|
165
|
+
|
|
166
|
+
### Basic Usage
|
|
167
|
+
|
|
168
|
+
```pug
|
|
169
|
+
// Component Definition
|
|
170
|
+
component Card()
|
|
171
|
+
.card
|
|
172
|
+
.card-header
|
|
173
|
+
slot(header)
|
|
174
|
+
p Default Header
|
|
175
|
+
.card-body
|
|
176
|
+
slot(body)
|
|
177
|
+
p Default Body
|
|
178
|
+
|
|
179
|
+
// Component Invocation
|
|
180
|
+
Card()
|
|
181
|
+
slot(header)
|
|
182
|
+
h1 Title
|
|
183
|
+
slot(body)
|
|
184
|
+
p Content
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This DSL is expanded into pure Pug at build time to generate the final HTML.
|
|
188
|
+
|
|
189
|
+
### Key Features
|
|
190
|
+
|
|
191
|
+
#### Multiple Named Slots
|
|
192
|
+
|
|
193
|
+
Define multiple named slots, just like in Vue or Svelte.
|
|
194
|
+
|
|
195
|
+
```pug
|
|
196
|
+
component Layout()
|
|
197
|
+
header
|
|
198
|
+
slot(header)
|
|
199
|
+
main
|
|
200
|
+
slot(main)
|
|
201
|
+
footer
|
|
202
|
+
slot(footer)
|
|
203
|
+
|
|
204
|
+
Layout()
|
|
205
|
+
slot(header)
|
|
206
|
+
h1 My Site
|
|
207
|
+
slot(main)
|
|
208
|
+
p Content
|
|
209
|
+
slot(footer)
|
|
210
|
+
p © 2026
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Props/Attrs Separation
|
|
214
|
+
|
|
215
|
+
Clear separation of props and attributes with `$props` and `$attrs`, inspired by Vue 3.
|
|
216
|
+
|
|
217
|
+
```pug
|
|
218
|
+
component Button()
|
|
219
|
+
- const { label, type = "button" } = $props
|
|
220
|
+
- const { class: className = "btn" } = $attrs
|
|
221
|
+
button(type=type class=className)= label
|
|
222
|
+
|
|
223
|
+
Button(label="Submit", type="submit", class="btn-primary")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
- Properties not declared in `$props` are automatically categorized into `$attrs`.
|
|
227
|
+
- Default values and renaming are also supported.
|
|
228
|
+
|
|
229
|
+
#### Automatic Attribute Fallthrough
|
|
230
|
+
|
|
231
|
+
Attributes passed to a component are automatically applied to the root element.
|
|
232
|
+
|
|
233
|
+
```pug
|
|
234
|
+
component Card()
|
|
235
|
+
.card
|
|
236
|
+
h2 Title
|
|
237
|
+
|
|
238
|
+
Card(class="my-card", id="card-1")
|
|
239
|
+
// → <div class="card my-card" id="card-1">...</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Manual control is also possible.
|
|
243
|
+
|
|
244
|
+
```pug
|
|
245
|
+
component Input()
|
|
246
|
+
.wrapper
|
|
247
|
+
input&attributes(attributes)
|
|
248
|
+
|
|
249
|
+
Input(type="text", class="primary")
|
|
250
|
+
// Attributes are applied to the input
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Scope Isolation
|
|
254
|
+
|
|
255
|
+
Components have an isolated scope, preventing direct access to external variables.
|
|
256
|
+
|
|
257
|
+
```pug
|
|
258
|
+
// ❌ Error
|
|
259
|
+
- const message = 'Hello'
|
|
260
|
+
component Card()
|
|
261
|
+
p= message
|
|
262
|
+
|
|
263
|
+
// ✅ Correct way: Pass via props
|
|
264
|
+
- const message = 'Hello'
|
|
265
|
+
component Card()
|
|
266
|
+
- const { text } = $props
|
|
267
|
+
p= text
|
|
268
|
+
Card(text=message)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Detailed Documentation
|
|
272
|
+
|
|
273
|
+
The complete Component DSL documentation is here:
|
|
274
|
+
|
|
275
|
+
- [Component DSL Reference](./docs/COMPONENTS.md) - Complete reference guide
|
|
276
|
+
- [Configuration Guide](./docs/CONFIGURATION.md) - Configuration options
|
|
277
|
+
|
|
278
|
+
## 📚 Documentation
|
|
279
|
+
|
|
280
|
+
- [Configuration Guide](./docs/CONFIGURATION.md) - CLI options, configuration files, and data loading
|
|
281
|
+
- [Component DSL Reference](./docs/COMPONENTS.md) - Complete component syntax reference
|
|
282
|
+
- [Architecture](./docs/ARCHITECTURE.md) - Internal design and processing flow
|
|
283
|
+
- [Contributing](./docs/CONTRIBUTING.md) - Development setup and guidelines
|
|
284
|
+
|
|
285
|
+
## 🔧 Development
|
|
286
|
+
|
|
287
|
+
### Setup
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Install dependencies
|
|
291
|
+
npm install
|
|
292
|
+
|
|
293
|
+
# Build
|
|
294
|
+
npm run build
|
|
295
|
+
|
|
296
|
+
# Test
|
|
297
|
+
npm test
|
|
298
|
+
|
|
299
|
+
# Lint & Format
|
|
300
|
+
npm run check
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Contributing
|
|
304
|
+
|
|
305
|
+
Interested in contributing? Please see the [Contribution Guide](./docs/CONTRIBUTING.md).
|
|
306
|
+
|
|
307
|
+
## 📄 License
|
|
308
|
+
|
|
309
|
+
MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
310
|
+
|
|
311
|
+
## 🙏 Acknowledgements
|
|
312
|
+
|
|
313
|
+
- [Pug](https://pugjs.org/) - The amazing template engine
|
|
314
|
+
- Inspired by the component system of [Vue.js](https://vuejs.org/)
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
**Status**: Alpha Release (v0.1.0-alpha.0) - 286 tests passing ✅
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PugTailConfig } from './types.js';
|
|
2
|
+
export declare function findConfigFile(startDir?: string): string | null;
|
|
3
|
+
export declare function loadConfigFile(configPath: string): Promise<PugTailConfig>;
|
|
4
|
+
export declare function loadConfig(configPath?: string): Promise<{
|
|
5
|
+
config: PugTailConfig;
|
|
6
|
+
configDir: string | null;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function mergeConfig(config: PugTailConfig, cliOptions: Partial<PugTailConfig>): PugTailConfig;
|
|
9
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/cli/config/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAqB/C,wBAAgB,cAAc,CAC5B,QAAQ,GAAE,MAAsB,GAC/B,MAAM,GAAG,IAAI,CAyBf;AAQD,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAqBxB;AAQD,wBAAsB,UAAU,CAC9B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAmB9D;AAUD,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,GACjC,aAAa,CAuBf"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
const CONFIG_FILE_NAMES = [
|
|
5
|
+
'pugtail.config.js',
|
|
6
|
+
'pugtail.config.mjs',
|
|
7
|
+
'pugtail.config.json',
|
|
8
|
+
'.pugtailrc.js',
|
|
9
|
+
'.pugtailrc.mjs',
|
|
10
|
+
'.pugtailrc.json',
|
|
11
|
+
'.pugtailrc',
|
|
12
|
+
];
|
|
13
|
+
export function findConfigFile(startDir = process.cwd()) {
|
|
14
|
+
let currentDir = resolve(startDir);
|
|
15
|
+
const root = dirname(currentDir);
|
|
16
|
+
while (currentDir !== root) {
|
|
17
|
+
for (const filename of CONFIG_FILE_NAMES) {
|
|
18
|
+
const configPath = join(currentDir, filename);
|
|
19
|
+
if (existsSync(configPath)) {
|
|
20
|
+
return configPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (existsSync(join(currentDir, 'package.json')) ||
|
|
24
|
+
existsSync(join(currentDir, '.git'))) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
currentDir = dirname(currentDir);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
export async function loadConfigFile(configPath) {
|
|
32
|
+
const ext = configPath.split('.').pop();
|
|
33
|
+
try {
|
|
34
|
+
if (ext === 'json' || configPath.endsWith('.pugtailrc')) {
|
|
35
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
36
|
+
return JSON.parse(content);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const fileUrl = pathToFileURL(configPath).href;
|
|
40
|
+
const module = await import(fileUrl);
|
|
41
|
+
return (module.default || module);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new Error(`Failed to load config file "${configPath}": ${error instanceof Error ? error.message : String(error)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function loadConfig(configPath) {
|
|
49
|
+
if (configPath) {
|
|
50
|
+
if (!existsSync(configPath)) {
|
|
51
|
+
throw new Error(`Config file not found: ${configPath}`);
|
|
52
|
+
}
|
|
53
|
+
const config = await loadConfigFile(configPath);
|
|
54
|
+
return { config, configDir: dirname(resolve(configPath)) };
|
|
55
|
+
}
|
|
56
|
+
const foundConfig = findConfigFile();
|
|
57
|
+
if (foundConfig) {
|
|
58
|
+
const config = await loadConfigFile(foundConfig);
|
|
59
|
+
return { config, configDir: dirname(resolve(foundConfig)) };
|
|
60
|
+
}
|
|
61
|
+
return { config: {}, configDir: null };
|
|
62
|
+
}
|
|
63
|
+
export function mergeConfig(config, cliOptions) {
|
|
64
|
+
return {
|
|
65
|
+
...config,
|
|
66
|
+
...cliOptions,
|
|
67
|
+
files: {
|
|
68
|
+
...config.files,
|
|
69
|
+
...cliOptions.files,
|
|
70
|
+
input: cliOptions.files?.input || config.files?.input,
|
|
71
|
+
output: cliOptions.files?.output || config.files?.output,
|
|
72
|
+
render: cliOptions.files?.render === undefined && cliOptions.files?.input
|
|
73
|
+
? undefined
|
|
74
|
+
: cliOptions.files?.render || config.files?.render,
|
|
75
|
+
},
|
|
76
|
+
watch: {
|
|
77
|
+
...config.watch,
|
|
78
|
+
...cliOptions.watch,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/cli/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../../../src/cli/config/matcher.ts"],"names":[],"mappings":"AA4BA,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAwBT;AAQD,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAOnD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
import { minimatch } from 'minimatch';
|
|
3
|
+
export function shouldIncludeFile(filePath, patterns, basePath) {
|
|
4
|
+
const relativePath = relative(basePath, filePath);
|
|
5
|
+
let included = patterns.length === 0;
|
|
6
|
+
for (const pattern of patterns) {
|
|
7
|
+
if (pattern.startsWith('!')) {
|
|
8
|
+
const negatedPattern = pattern.slice(1);
|
|
9
|
+
if (minimatch(relativePath, negatedPattern, { dot: true })) {
|
|
10
|
+
included = false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
if (minimatch(relativePath, pattern, { dot: true })) {
|
|
15
|
+
included = true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return included;
|
|
20
|
+
}
|
|
21
|
+
export function getDefaultOutputPatterns() {
|
|
22
|
+
return [
|
|
23
|
+
'**/*.pug',
|
|
24
|
+
'!**/_*.pug',
|
|
25
|
+
'!**/*.component.pug',
|
|
26
|
+
'!**/components/**/*.pug',
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../../src/cli/config/matcher.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAuBrC,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,QAAkB,EAClB,QAAgB;IAGhB,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAGjD,IAAI,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAA;IAGpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAE5B,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACvC,IAAI,SAAS,CAAC,YAAY,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC3D,QAAQ,GAAG,KAAK,CAAA;YAClB,CAAC;QACH,CAAC;aAAM,CAAC;YAEN,IAAI,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;gBACpD,QAAQ,GAAG,IAAI,CAAA;YACjB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAQD,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,UAAU;QACV,YAAY;QACZ,qBAAqB;QACrB,yBAAyB;KAC1B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface PugTailConfig {
|
|
2
|
+
files?: {
|
|
3
|
+
input?: string | string[];
|
|
4
|
+
output?: string;
|
|
5
|
+
root?: string;
|
|
6
|
+
render?: string[];
|
|
7
|
+
};
|
|
8
|
+
extension?: string;
|
|
9
|
+
basedir?: string;
|
|
10
|
+
doctype?: string;
|
|
11
|
+
pretty?: boolean;
|
|
12
|
+
format?: 'html' | 'ast' | 'pug-code';
|
|
13
|
+
data?: string | Record<string, unknown>;
|
|
14
|
+
dataKey?: string;
|
|
15
|
+
watch?: {
|
|
16
|
+
enabled?: boolean;
|
|
17
|
+
debounce?: number;
|
|
18
|
+
};
|
|
19
|
+
silent?: boolean;
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
validation?: {
|
|
22
|
+
scopeIsolation?: 'error' | 'warn' | 'off';
|
|
23
|
+
allowedGlobals?: string[];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cli/config/types.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAE5B,KAAK,CAAC,EAAE;QAEN,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;QAGzB,MAAM,CAAC,EAAE,MAAM,CAAA;QAaf,IAAI,CAAC,EAAE,MAAM,CAAA;QAqBb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;KAClB,CAAA;IAGD,SAAS,CAAC,EAAE,MAAM,CAAA;IAGlB,OAAO,CAAC,EAAE,MAAM,CAAA;IAGhB,OAAO,CAAC,EAAE,MAAM,CAAA;IAGhB,MAAM,CAAC,EAAE,OAAO,CAAA;IAGhB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,CAAA;IAGpC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAGvC,OAAO,CAAC,EAAE,MAAM,CAAA;IAGhB,KAAK,CAAC,EAAE;QAEN,OAAO,CAAC,EAAE,OAAO,CAAA;QAEjB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IAGD,MAAM,CAAC,EAAE,OAAO,CAAA;IAGhB,KAAK,CAAC,EAAE,OAAO,CAAA;IAGf,UAAU,CAAC,EAAE;QAEX,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;QAEzC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;KAC1B,CAAA;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cli/config/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function loadData(input: string, basedir?: string): Record<string, unknown>;
|
|
2
|
+
export declare function mergeData(...sources: Array<Record<string, unknown> | undefined>): Record<string, unknown>;
|
|
3
|
+
declare class DataLoader {
|
|
4
|
+
loadDataFiles(filePaths: string[], basePath?: string, basedir?: string): Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export declare const dataLoader: DataLoader;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=dataLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataLoader.d.ts","sourceRoot":"","sources":["../../src/cli/dataLoader.ts"],"names":[],"mappings":"AAoCA,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiCzB;AAmBD,wBAAgB,SAAS,CACvB,GAAG,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAKD,cAAM,UAAU;IASd,aAAa,CACX,SAAS,EAAE,MAAM,EAAE,EACnB,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAgD3B;AAED,eAAO,MAAM,UAAU,YAAmB,CAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
3
|
+
export function loadData(input, basedir) {
|
|
4
|
+
const basePath = basedir || process.cwd();
|
|
5
|
+
const filePath = resolve(basePath, input);
|
|
6
|
+
try {
|
|
7
|
+
const fileContent = readFileSync(filePath, 'utf-8');
|
|
8
|
+
try {
|
|
9
|
+
return JSON.parse(fileContent);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
throw new Error(`Failed to parse file "${input}" as JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch (fileError) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(input);
|
|
18
|
+
}
|
|
19
|
+
catch (parseError) {
|
|
20
|
+
throw new Error(`Failed to load data from "${input}". ` +
|
|
21
|
+
`It must be either a valid JSON file path or a JSON string. ` +
|
|
22
|
+
`File error: ${fileError instanceof Error ? fileError.message : String(fileError)}. ` +
|
|
23
|
+
`Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function mergeData(...sources) {
|
|
28
|
+
const result = {};
|
|
29
|
+
for (const source of sources) {
|
|
30
|
+
if (source) {
|
|
31
|
+
Object.assign(result, source);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
class DataLoader {
|
|
37
|
+
loadDataFiles(filePaths, basePath, basedir) {
|
|
38
|
+
const mergedData = {};
|
|
39
|
+
for (const filePath of filePaths) {
|
|
40
|
+
try {
|
|
41
|
+
let resolvedPath;
|
|
42
|
+
const isPugStyleAbsolute = filePath.startsWith('/') &&
|
|
43
|
+
!filePath.startsWith('/Users/') &&
|
|
44
|
+
!filePath.startsWith('/home/') &&
|
|
45
|
+
!/^[A-Z]:\\/.test(filePath);
|
|
46
|
+
if (isPugStyleAbsolute) {
|
|
47
|
+
const normalizedPath = filePath.slice(1);
|
|
48
|
+
const resolveBase = basedir || basePath || process.cwd();
|
|
49
|
+
resolvedPath = resolve(resolveBase, normalizedPath);
|
|
50
|
+
}
|
|
51
|
+
else if (isAbsolute(filePath)) {
|
|
52
|
+
resolvedPath = filePath;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const resolveBase = basePath || basedir || process.cwd();
|
|
56
|
+
resolvedPath = resolve(resolveBase, filePath);
|
|
57
|
+
}
|
|
58
|
+
const fileContent = readFileSync(resolvedPath, 'utf-8');
|
|
59
|
+
const data = JSON.parse(fileContent);
|
|
60
|
+
Object.assign(mergedData, data);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.warn(`Warning: Failed to load data file "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return mergedData;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export const dataLoader = new DataLoader();
|
|
70
|
+
//# sourceMappingURL=dataLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataLoader.js","sourceRoot":"","sources":["../../src/cli/dataLoader.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA6B/C,MAAM,UAAU,QAAQ,CACtB,KAAa,EACb,OAAgB;IAIhB,MAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IAEzC,IAAI,CAAC;QAEH,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAGnD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,yBAAyB,KAAK,cAC5B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CACH,CAAA;QACH,CAAC;IACH,CAAC;IAAC,OAAO,SAAS,EAAE,CAAC;QAEnB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC1B,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACb,6BAA6B,KAAK,KAAK;gBACrC,6DAA6D;gBAC7D,eAAe,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI;gBACrF,gBAAgB,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAC1F,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAmBD,MAAM,UAAU,SAAS,CACvB,GAAG,OAAmD;IAEtD,MAAM,MAAM,GAA4B,EAAE,CAAA;IAE1C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAKD,MAAM,UAAU;IASd,aAAa,CACX,SAAmB,EACnB,QAAiB,EACjB,OAAgB;QAEhB,MAAM,UAAU,GAA4B,EAAE,CAAA;QAE9C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,IAAI,YAAoB,CAAA;gBAKxB,MAAM,kBAAkB,GACtB,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;oBACxB,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;oBAC/B,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAC9B,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;gBAE7B,IAAI,kBAAkB,EAAE,CAAC;oBAGvB,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;oBACxC,MAAM,WAAW,GAAG,OAAO,IAAI,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;oBACxD,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;gBACrD,CAAC;qBAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAGhC,YAAY,GAAG,QAAQ,CAAA;gBACzB,CAAC;qBAAM,CAAC;oBAGN,MAAM,WAAW,GAAG,QAAQ,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;oBACxD,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;gBAC/C,CAAC;gBAGD,MAAM,WAAW,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;gBACvD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;gBACpC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;YACjC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CACV,sCAAsC,QAAQ,MAC5C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CACH,CAAA;YACH,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FileDependencies {
|
|
2
|
+
dependencies: Set<string>;
|
|
3
|
+
dependents: Set<string>;
|
|
4
|
+
}
|
|
5
|
+
export declare class DependencyTracker {
|
|
6
|
+
private dependencyMap;
|
|
7
|
+
private basedir?;
|
|
8
|
+
constructor(basedir?: string);
|
|
9
|
+
analyzeDependencies(filePath: string): Set<string>;
|
|
10
|
+
getDependents(filePath: string): Set<string>;
|
|
11
|
+
removeFile(filePath: string): void;
|
|
12
|
+
hasCircularDependency(filePath: string): boolean;
|
|
13
|
+
private resolveDependencyPath;
|
|
14
|
+
private addPugExtension;
|
|
15
|
+
private updateDependencyGraph;
|
|
16
|
+
private clearFileDependencies;
|
|
17
|
+
private isDebug;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=dependencyTracker.d.ts.map
|