@canonical/webarchitect 0.9.0-experimental.12
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/README.md +251 -0
- package/dist/esm/ajv.js +46 -0
- package/dist/esm/ajv.js.map +1 -0
- package/dist/esm/cli.js +277 -0
- package/dist/esm/cli.js.map +1 -0
- package/dist/esm/constants.js +3 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/executeValidationRules.js +26 -0
- package/dist/esm/executeValidationRules.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/ajv.js +59 -0
- package/dist/esm/lib/ajv.js.map +1 -0
- package/dist/esm/lib/describeSchema.js +53 -0
- package/dist/esm/lib/describeSchema.js.map +1 -0
- package/dist/esm/lib/discoverAllRulesets.js +13 -0
- package/dist/esm/lib/discoverAllRulesets.js.map +1 -0
- package/dist/esm/lib/discoverRulesetsInDir.js +35 -0
- package/dist/esm/lib/discoverRulesetsInDir.js.map +1 -0
- package/dist/esm/lib/executeValidationRules.js +41 -0
- package/dist/esm/lib/executeValidationRules.js.map +1 -0
- package/dist/esm/lib/index.js +15 -0
- package/dist/esm/lib/index.js.map +1 -0
- package/dist/esm/lib/listDirectory.js +27 -0
- package/dist/esm/lib/listDirectory.js.map +1 -0
- package/dist/esm/lib/loadFullSchema.js +32 -0
- package/dist/esm/lib/loadFullSchema.js.map +1 -0
- package/dist/esm/lib/resolveSchema.js +113 -0
- package/dist/esm/lib/resolveSchema.js.map +1 -0
- package/dist/esm/lib/validateDirectoryRule.js +138 -0
- package/dist/esm/lib/validateDirectoryRule.js.map +1 -0
- package/dist/esm/lib/validateFileRule.js +92 -0
- package/dist/esm/lib/validateFileRule.js.map +1 -0
- package/dist/esm/lib/validateRule.js +32 -0
- package/dist/esm/lib/validateRule.js.map +1 -0
- package/dist/esm/listDirectory.js +12 -0
- package/dist/esm/listDirectory.js.map +1 -0
- package/dist/esm/loadFullSchema.js +15 -0
- package/dist/esm/loadFullSchema.js.map +1 -0
- package/dist/esm/resolveSchema.js +67 -0
- package/dist/esm/resolveSchema.js.map +1 -0
- package/dist/esm/schema.json +61 -0
- package/dist/esm/schemas/draft-2020-12.json +57 -0
- package/dist/esm/schemas/meta/applicator.json +44 -0
- package/dist/esm/schemas/meta/content.json +12 -0
- package/dist/esm/schemas/meta/core.json +47 -0
- package/dist/esm/schemas/meta/format-annotation.json +10 -0
- package/dist/esm/schemas/meta/meta-data.json +32 -0
- package/dist/esm/schemas/meta/unevaluated.json +11 -0
- package/dist/esm/schemas/meta/validation.json +94 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/validate.js +26 -0
- package/dist/esm/validate.js.map +1 -0
- package/dist/esm/validateDirectoryRule.js +120 -0
- package/dist/esm/validateDirectoryRule.js.map +1 -0
- package/dist/esm/validateFileRule.js +119 -0
- package/dist/esm/validateFileRule.js.map +1 -0
- package/dist/esm/validateProject.js +31 -0
- package/dist/esm/validateProject.js.map +1 -0
- package/dist/types/ajv.d.ts +4 -0
- package/dist/types/ajv.d.ts.map +1 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/constants.d.ts +2 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/executeValidationRules.d.ts +3 -0
- package/dist/types/executeValidationRules.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/lib/ajv.d.ts +4 -0
- package/dist/types/lib/ajv.d.ts.map +1 -0
- package/dist/types/lib/describeSchema.d.ts +22 -0
- package/dist/types/lib/describeSchema.d.ts.map +1 -0
- package/dist/types/lib/discoverAllRulesets.d.ts +9 -0
- package/dist/types/lib/discoverAllRulesets.d.ts.map +1 -0
- package/dist/types/lib/discoverRulesetsInDir.d.ts +6 -0
- package/dist/types/lib/discoverRulesetsInDir.d.ts.map +1 -0
- package/dist/types/lib/executeValidationRules.d.ts +22 -0
- package/dist/types/lib/executeValidationRules.d.ts.map +1 -0
- package/dist/types/lib/index.d.ts +15 -0
- package/dist/types/lib/index.d.ts.map +1 -0
- package/dist/types/lib/listDirectory.d.ts +20 -0
- package/dist/types/lib/listDirectory.d.ts.map +1 -0
- package/dist/types/lib/loadFullSchema.d.ts +20 -0
- package/dist/types/lib/loadFullSchema.d.ts.map +1 -0
- package/dist/types/lib/resolveSchema.d.ts +29 -0
- package/dist/types/lib/resolveSchema.d.ts.map +1 -0
- package/dist/types/lib/validateDirectoryRule.d.ts +26 -0
- package/dist/types/lib/validateDirectoryRule.d.ts.map +1 -0
- package/dist/types/lib/validateFileRule.d.ts +29 -0
- package/dist/types/lib/validateFileRule.d.ts.map +1 -0
- package/dist/types/lib/validateRule.d.ts +21 -0
- package/dist/types/lib/validateRule.d.ts.map +1 -0
- package/dist/types/listDirectory.d.ts +5 -0
- package/dist/types/listDirectory.d.ts.map +1 -0
- package/dist/types/loadFullSchema.d.ts +3 -0
- package/dist/types/loadFullSchema.d.ts.map +1 -0
- package/dist/types/resolveSchema.d.ts +3 -0
- package/dist/types/resolveSchema.d.ts.map +1 -0
- package/dist/types/types.d.ts +42 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/validate.d.ts +23 -0
- package/dist/types/validate.d.ts.map +1 -0
- package/dist/types/validateDirectoryRule.d.ts +3 -0
- package/dist/types/validateDirectoryRule.d.ts.map +1 -0
- package/dist/types/validateFileRule.d.ts +3 -0
- package/dist/types/validateFileRule.d.ts.map +1 -0
- package/dist/types/validateProject.d.ts +8 -0
- package/dist/types/validateProject.d.ts.map +1 -0
- package/package.json +48 -0
- package/rulesets/base.ruleset.json +4 -0
- package/rulesets/package-react.ruleset.json +25 -0
- package/rulesets/package.ruleset.json +97 -0
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Webarchitect
|
|
2
|
+
|
|
3
|
+
A powerful command-line tool for validating project architecture and configuration consistency across development teams and organizations.
|
|
4
|
+
|
|
5
|
+
## What is this tool for?
|
|
6
|
+
|
|
7
|
+
Webarchitect helps development teams maintain consistent project structures and configuration standards. Think of it as a quality gate that ensures every project in your organization follows the same architectural patterns, uses the same build tools, and maintains the same configuration standards.
|
|
8
|
+
|
|
9
|
+
### The Problem It Solves
|
|
10
|
+
|
|
11
|
+
In large organizations with multiple development teams, projects tend to drift from established standards over time. One team might use different TypeScript configurations, another might have inconsistent package.json structures, and a third might be missing essential development scripts. This inconsistency creates several problems: developers waste time figuring out how each project works, code quality varies between teams, and maintaining projects becomes more difficult as each one follows slightly different patterns.
|
|
12
|
+
|
|
13
|
+
Webarchitect addresses this challenge by providing automated validation of project architecture. Instead of relying on documentation that might become outdated or manual code reviews that might miss configuration details, you can define your organization's standards as executable rulesets and validate projects automatically.
|
|
14
|
+
|
|
15
|
+
### How It Works
|
|
16
|
+
|
|
17
|
+
The tool operates on the concept of "rulesets" - JSON Schema-based definitions that describe what files should exist in a project and what those files should contain. For example, a ruleset might specify that every package must have a `package.json` file with specific required fields, a `biome.json` file that extends your organization's linting configuration, and a TypeScript configuration that follows your team's standards.
|
|
18
|
+
|
|
19
|
+
When you run webarchitect against a project, it loads the specified ruleset, checks whether the required files exist, and validates that their contents match the expected structure and values. This approach gives you confidence that projects follow your established patterns without requiring manual inspection.
|
|
20
|
+
|
|
21
|
+
## How to install and run?
|
|
22
|
+
|
|
23
|
+
### Installation
|
|
24
|
+
|
|
25
|
+
First, install webarchitect as a dependency in your project or globally:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Using npm
|
|
29
|
+
npm install --save-dev @canonical/webarchitect
|
|
30
|
+
|
|
31
|
+
# Using bun
|
|
32
|
+
bun add --dev @canonical/webarchitect
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For global installation:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Using npm
|
|
39
|
+
npm install -g @canonical/webarchitect
|
|
40
|
+
|
|
41
|
+
# Using bun
|
|
42
|
+
bun add -g @canonical/webarchitect
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Basic Usage
|
|
46
|
+
|
|
47
|
+
The most straightforward way to get started is by validating your project against the `base-package` ruleset, which enforces common standards for package structure and configuration:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Using node
|
|
51
|
+
npx webarchitect base-package
|
|
52
|
+
|
|
53
|
+
# Using bun
|
|
54
|
+
bun run webarchitect base-package
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This command will check your current directory against the base package requirements, validating that your project has the expected configuration files and that they contain the required fields and values.
|
|
58
|
+
|
|
59
|
+
### Understanding the Output
|
|
60
|
+
|
|
61
|
+
When you run webarchitect, you'll see a clear summary of which validations passed and which failed. Failed validations include detailed explanations of what was expected versus what was found, making it easy to understand how to fix any issues.
|
|
62
|
+
|
|
63
|
+
For more detailed information about what's being validated, add the verbose flag:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx webarchitect base-package --verbose
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The verbose output shows you exactly which files are being checked, what rules are being applied, and what content was found in each file.
|
|
70
|
+
|
|
71
|
+
## What are the available rulesets?
|
|
72
|
+
|
|
73
|
+
Webarchitect comes with several built-in rulesets that cover common project patterns. You can find all available rulesets in the [rulesets folder](./rulesets) of this repository.
|
|
74
|
+
|
|
75
|
+
### Built-in Rulesets
|
|
76
|
+
|
|
77
|
+
- `base`: The foundational ruleset that contains minimal requirements for any project. This is currently empty and should not be used. In the future, this ruleset will include license file validation and will serve as a building block for more specific rulesets.
|
|
78
|
+
|
|
79
|
+
- `base-package`: Extends the base ruleset with comprehensive package requirements. This ruleset validates that your package.json contains required fields like name, version, type, and scripts, ensures consistent module structure with specific entry points, validates biome.json configuration for code formatting and linting, and enforces the use of ES modules and TypeScript.
|
|
80
|
+
|
|
81
|
+
- `package-react`: - Extends base-package with React-specific requirements. This ruleset includes all the base package validations plus verification that React 19 or higher is specified as a dependency, ensuring your React projects use compatible versions.
|
|
82
|
+
|
|
83
|
+
### Ruleset Inheritance
|
|
84
|
+
|
|
85
|
+
Rulesets can extend other rulesets, creating a hierarchy of validation requirements. For example, package-react extends base-package, which extends base. This means when you validate against package-react, you're actually running all three sets of rules. This inheritance model allows you to build complex validation requirements while keeping individual rulesets focused and maintainable.
|
|
86
|
+
|
|
87
|
+
### Creating Custom Rulesets
|
|
88
|
+
|
|
89
|
+
Webarchitect uses standard JSON Schema as its validation engine, but applies it in a specialized way. Instead of directly validating data against schemas, webarchitect creates a meta-usage of JSON Schema where the schemas themselves describe validation rules for project files.
|
|
90
|
+
|
|
91
|
+
Understanding this architecture requires grasping the concept of the "mother schema" - a master JSON Schema definition that validates the structure of webarchitect rulesets themselves. This mother schema defines what properties a valid ruleset can have, how file and directory rules should be structured, and what inheritance patterns are allowed. When you create a custom ruleset, webarchitect first validates your ruleset definition against this mother schema before using your rules to validate project files.
|
|
92
|
+
|
|
93
|
+
You can create custom rulesets by following the JSON Schema format used by the built-in examples. The [JSON Schema documentation](https://json-schema.org/learn/) provides comprehensive guidance on writing schema definitions. Custom rulesets can extend existing ones or define completely new validation requirements for your specific organizational needs.
|
|
94
|
+
|
|
95
|
+
This approach gives you the full power of JSON Schema's validation capabilities while maintaining a consistent structure for how validation rules are defined and applied across different projects and teams.
|
|
96
|
+
|
|
97
|
+
## CLI API
|
|
98
|
+
|
|
99
|
+
Webarchitect provides a simple but powerful command-line interface designed to integrate easily into development workflows and CI/CD pipelines. The tool must be run from the top-level directory of your package - the same directory that contains your package.json file - to properly validate your project structure.
|
|
100
|
+
|
|
101
|
+
### Basic Command Structure
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
webarchitect <ruleset> [options]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Available Options
|
|
108
|
+
|
|
109
|
+
- `--verbose`: Shows detailed information about each validation, including what files are being checked, what rules are being applied, and the actual content found. Essential for debugging validation failures or understanding exactly what the tool is checking.
|
|
110
|
+
-`--json`: Outputs results in JSON format instead of human-readable text. Required for integrating webarchitect into automated systems, CI/CD pipelines, or other tools that need to programmatically process validation results.
|
|
111
|
+
-`--help`: Displays comprehensive usage information, available options, and examples. Use this command to see the most current information about the tool's capabilities.
|
|
112
|
+
|
|
113
|
+
### Ruleset Resolution Mechanism
|
|
114
|
+
|
|
115
|
+
The `<ruleset>` parameter follows a specific resolution order that determines where webarchitect looks for ruleset definitions:
|
|
116
|
+
|
|
117
|
+
1. **Local Files First** - Webarchitect first checks the current directory for a file matching your ruleset name. If you specify `my-rules`, it looks for `my-rules.json` in the current directory. This allows you to override built-in rulesets or use project-specific validation rules.
|
|
118
|
+
|
|
119
|
+
2. **Bundled Rulesets Second** - If no local file is found, webarchitect searches its internal collection of built-in rulesets. These include `base`, `base-package`, and `package-react`. Built-in rulesets are distributed with the tool and provide standard validation patterns for common project types.
|
|
120
|
+
|
|
121
|
+
3. **Remote URLs** - You can also specify a complete URL (starting with `http://` or `https://`) to fetch rulesets from remote locations. Remote rulesets must end with `.json` and be accessible via standard HTTP requests. This enables sharing rulesets across organizations or using centrally managed validation rules.
|
|
122
|
+
|
|
123
|
+
This resolution mechanism allows teams to start with built-in rulesets, customize them locally as needed, and eventually move to centralized remote rulesets as their validation requirements mature and become standardized across larger organizations.
|
|
124
|
+
|
|
125
|
+
### Exit Codes
|
|
126
|
+
|
|
127
|
+
Webarchitect follows standard Unix conventions for exit codes. It returns 0 when all validations pass and 1 when any validation fails. This makes it easy to integrate into scripts and CI/CD pipelines where you want builds to fail if architectural standards aren't met.
|
|
128
|
+
|
|
129
|
+
## Programmatic API
|
|
130
|
+
|
|
131
|
+
While the command-line interface covers most use cases, webarchitect also provides a programmatic API for integration into build tools, custom scripts, or other Node.js applications.
|
|
132
|
+
|
|
133
|
+
### Basic Usage Example
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { validate } from '@canonical/webarchitect';
|
|
137
|
+
import type { ValidationResult } from '@canonical/webarchitect';
|
|
138
|
+
|
|
139
|
+
// Validate the current directory against a ruleset
|
|
140
|
+
async function checkProjectCompliance(): Promise<void> {
|
|
141
|
+
try {
|
|
142
|
+
// The validate function takes a project path and ruleset identifier
|
|
143
|
+
const results: ValidationResult[] = await validate(process.cwd(), 'base-package');
|
|
144
|
+
|
|
145
|
+
// Process the results
|
|
146
|
+
for (const result of results) {
|
|
147
|
+
if (result.passed) {
|
|
148
|
+
console.log(`✓ ${result.rule}: passed`);
|
|
149
|
+
} else {
|
|
150
|
+
console.log(`✗ ${result.rule}: ${result.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check if any validations failed
|
|
155
|
+
const hasFailures: boolean = results.some(result => !result.passed);
|
|
156
|
+
if (hasFailures) {
|
|
157
|
+
throw new Error('Project does not meet architectural standards');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log('All validations passed!');
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Validation failed:', (error as Error).message);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
checkProjectCompliance();
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Advanced Usage with Custom Error Handling
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { validate } from '@canonical/webarchitect';
|
|
174
|
+
import type { ValidationResult } from '@canonical/webarchitect';
|
|
175
|
+
|
|
176
|
+
interface ValidationReport {
|
|
177
|
+
summary: {
|
|
178
|
+
total: number;
|
|
179
|
+
passed: number;
|
|
180
|
+
failed: number;
|
|
181
|
+
success: boolean;
|
|
182
|
+
};
|
|
183
|
+
details: {
|
|
184
|
+
passed: Array<{ rule: string; target?: string }>;
|
|
185
|
+
failed: Array<{ rule: string; message?: string; target?: string }>;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function validateWithDetailedReporting(
|
|
190
|
+
projectPath: string,
|
|
191
|
+
rulesetName: string
|
|
192
|
+
): Promise<ValidationReport> {
|
|
193
|
+
try {
|
|
194
|
+
const results: ValidationResult[] = await validate(projectPath, rulesetName);
|
|
195
|
+
|
|
196
|
+
// Separate passed and failed results
|
|
197
|
+
const passed = results.filter(r => r.passed);
|
|
198
|
+
const failed = results.filter(r => !r.passed);
|
|
199
|
+
|
|
200
|
+
// Generate a detailed report
|
|
201
|
+
const report: ValidationReport = {
|
|
202
|
+
summary: {
|
|
203
|
+
total: results.length,
|
|
204
|
+
passed: passed.length,
|
|
205
|
+
failed: failed.length,
|
|
206
|
+
success: failed.length === 0
|
|
207
|
+
},
|
|
208
|
+
details: {
|
|
209
|
+
passed: passed.map(r => ({ rule: r.rule, target: r.context?.target })),
|
|
210
|
+
failed: failed.map(r => ({
|
|
211
|
+
rule: r.rule,
|
|
212
|
+
message: r.message,
|
|
213
|
+
target: r.context?.target
|
|
214
|
+
}))
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
return report;
|
|
219
|
+
} catch (error) {
|
|
220
|
+
throw new Error(`Failed to validate project: ${(error as Error).message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Usage in a build script
|
|
225
|
+
validateWithDetailedReporting('./my-project', 'base-package')
|
|
226
|
+
.then((report: ValidationReport) => {
|
|
227
|
+
if (report.summary.success) {
|
|
228
|
+
console.log('✅ Project validation successful');
|
|
229
|
+
} else {
|
|
230
|
+
console.log('❌ Project validation failed');
|
|
231
|
+
console.log(`Failed rules: ${report.details.failed.length}`);
|
|
232
|
+
report.details.failed.forEach(failure => {
|
|
233
|
+
console.log(` - ${failure.rule}: ${failure.message}`);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
.catch((error: Error) => {
|
|
238
|
+
console.error('Validation error:', error.message);
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Integration with Build Tools
|
|
243
|
+
|
|
244
|
+
The programmatic API makes it easy to integrate webarchitect into existing build processes. You can add validation steps to webpack configurations, gulp tasks, or any other build system that supports Node.js plugins.
|
|
245
|
+
|
|
246
|
+
## Known caveats?
|
|
247
|
+
|
|
248
|
+
- **Plain Text File Validation** - Webarchitect only validates JSON files. While it can verify that plain text files like LICENSE or README.md exist, it cannot validate their contents. This limitation affects license text verification, documentation standards, and configuration files that use non-JSON formats.
|
|
249
|
+
- **IDE Integration** - No real-time validation feedback is available yet in code editors. Developers must run webarchitect manually or through build scripts to see validation results. Real-time diagnostics would require Language Server Protocol implementation or editor-specific plugins.
|
|
250
|
+
- **Svelte support** - No svelte-specific ruleset has been developed yet.
|
|
251
|
+
- **Error Code Granularity** - All validation failures return the same exit code (1) regardless of failure type. Missing files, invalid JSON syntax, and schema validation failures are not distinguished programmatically. This limits automated error handling and reporting capabilities.
|
package/dist/esm/ajv.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import ajvPackage from "ajv";
|
|
2
|
+
import draft202012 from "./schemas/draft-2020-12.json" with { type: "json" };
|
|
3
|
+
import metaApplicator from "./schemas/meta/applicator.json" with {
|
|
4
|
+
type: "json"
|
|
5
|
+
};
|
|
6
|
+
import metaContent from "./schemas/meta/content.json" with { type: "json" };
|
|
7
|
+
import metaCore from "./schemas/meta/core.json" with { type: "json" };
|
|
8
|
+
import metaFormatAnnotation from "./schemas/meta/format-annotation.json" with {
|
|
9
|
+
type: "json"
|
|
10
|
+
};
|
|
11
|
+
import metaMetaData from "./schemas/meta/meta-data.json" with { type: "json" };
|
|
12
|
+
import metaUnevaluated from "./schemas/meta/unevaluated.json" with {
|
|
13
|
+
type: "json"
|
|
14
|
+
};
|
|
15
|
+
import metaValidation from "./schemas/meta/validation.json" with {
|
|
16
|
+
type: "json"
|
|
17
|
+
};
|
|
18
|
+
const Ajv = ajvPackage.default;
|
|
19
|
+
// Create AJV instance with configuration optimized for our use case
|
|
20
|
+
const ajv = new Ajv({
|
|
21
|
+
strict: false, // Allow unknown keywords without throwing errors
|
|
22
|
+
allErrors: true, // Collect all validation errors, not just the first one
|
|
23
|
+
validateSchema: false, // Temporarily disable automatic schema validation during setup
|
|
24
|
+
});
|
|
25
|
+
// Step 1: Register all the foundational meta-schemas first
|
|
26
|
+
// These are the building blocks that the main Draft 2020-12 schema depends on
|
|
27
|
+
ajv.addSchema(metaCore, "https://json-schema.org/draft/2020-12/meta/core");
|
|
28
|
+
ajv.addSchema(metaApplicator, "https://json-schema.org/draft/2020-12/meta/applicator");
|
|
29
|
+
ajv.addSchema(metaUnevaluated, "https://json-schema.org/draft/2020-12/meta/unevaluated");
|
|
30
|
+
ajv.addSchema(metaValidation, "https://json-schema.org/draft/2020-12/meta/validation");
|
|
31
|
+
ajv.addSchema(metaMetaData, "https://json-schema.org/draft/2020-12/meta/meta-data");
|
|
32
|
+
ajv.addSchema(metaFormatAnnotation, "https://json-schema.org/draft/2020-12/meta/format-annotation");
|
|
33
|
+
ajv.addSchema(metaContent, "https://json-schema.org/draft/2020-12/meta/content");
|
|
34
|
+
// Step 2: Now register the main Draft 2020-12 schema
|
|
35
|
+
// This schema composes all the meta-schemas above into the complete specification
|
|
36
|
+
ajv.addSchema(draft202012, "https://json-schema.org/draft/2020-12/schema");
|
|
37
|
+
ajv.addSchema(draft202012, "http://json-schema.org/draft/2020-12/schema");
|
|
38
|
+
// Step 3: Re-enable schema validation now that all pieces are in place
|
|
39
|
+
ajv.opts.validateSchema = true;
|
|
40
|
+
// Step 4: Add format validation support manually to avoid type issues
|
|
41
|
+
// Instead of using ajv-formats, we'll add the most common formats we need
|
|
42
|
+
ajv.addFormat("email", /^[^\s@]+@[^\s@]+\.[^\s@]+$/);
|
|
43
|
+
ajv.addFormat("uri", /^https?:\/\/[^\s]+$/);
|
|
44
|
+
ajv.addFormat("uri-reference", /^[^\s]*$/);
|
|
45
|
+
export default ajv;
|
|
46
|
+
//# sourceMappingURL=ajv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ajv.js","sourceRoot":"","sources":["../../src/ajv.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,KAAK,CAAC;AAC7B,OAAO,WAAW,MAAM,8BAA8B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC7E,OAAO,cAAc,MAAM,gCAAgC,CAAC;IAC1D,IAAI,EAAE,MAAM;CACb,CAAC;AACF,OAAO,WAAW,MAAM,6BAA6B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5E,OAAO,QAAQ,MAAM,0BAA0B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACtE,OAAO,oBAAoB,MAAM,uCAAuC,CAAC;IACvE,IAAI,EAAE,MAAM;CACb,CAAC;AACF,OAAO,YAAY,MAAM,+BAA+B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/E,OAAO,eAAe,MAAM,iCAAiC,CAAC;IAC5D,IAAI,EAAE,MAAM;CACb,CAAC;AACF,OAAO,cAAc,MAAM,gCAAgC,CAAC;IAC1D,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC;AAE/B,oEAAoE;AACpE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;IAClB,MAAM,EAAE,KAAK,EAAE,iDAAiD;IAChE,SAAS,EAAE,IAAI,EAAE,wDAAwD;IACzE,cAAc,EAAE,KAAK,EAAE,+DAA+D;CACvF,CAAC,CAAC;AAEH,2DAA2D;AAC3D,8EAA8E;AAC9E,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,iDAAiD,CAAC,CAAC;AAC3E,GAAG,CAAC,SAAS,CACX,cAAc,EACd,uDAAuD,CACxD,CAAC;AACF,GAAG,CAAC,SAAS,CACX,eAAe,EACf,wDAAwD,CACzD,CAAC;AACF,GAAG,CAAC,SAAS,CACX,cAAc,EACd,uDAAuD,CACxD,CAAC;AACF,GAAG,CAAC,SAAS,CACX,YAAY,EACZ,sDAAsD,CACvD,CAAC;AACF,GAAG,CAAC,SAAS,CACX,oBAAoB,EACpB,8DAA8D,CAC/D,CAAC;AACF,GAAG,CAAC,SAAS,CACX,WAAW,EACX,oDAAoD,CACrD,CAAC;AAEF,qDAAqD;AACrD,kFAAkF;AAClF,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,8CAA8C,CAAC,CAAC;AAC3E,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE,6CAA6C,CAAC,CAAC;AAE1E,uEAAuE;AACvE,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;AAE/B,sEAAsE;AACtE,0EAA0E;AAC1E,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,4BAA4B,CAAC,CAAC;AACrD,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;AAC5C,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAE3C,eAAe,GAAG,CAAC"}
|
package/dist/esm/cli.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { discoverAllRulesets } from "./lib/index.js";
|
|
5
|
+
import validate from "./validate.js";
|
|
6
|
+
const program = new Command();
|
|
7
|
+
/**
|
|
8
|
+
* Formats AJV validation errors into human-readable messages.
|
|
9
|
+
* Groups errors by their property path and removes duplicate messages.
|
|
10
|
+
*
|
|
11
|
+
* @param errorsJson - JSON string containing an array of AJV ErrorObject instances
|
|
12
|
+
* @returns Array of formatted error messages, one per property path
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const errors = '[{"instancePath": "/name", "message": "must be string"}]';
|
|
17
|
+
* const formatted = formatAjvErrors(errors);
|
|
18
|
+
* // Returns: ["name: must be string"]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
function formatAjvErrors(errorsJson) {
|
|
22
|
+
try {
|
|
23
|
+
const errors = JSON.parse(errorsJson);
|
|
24
|
+
const errorsByPath = new Map();
|
|
25
|
+
for (const error of errors) {
|
|
26
|
+
const path = error.instancePath || "root";
|
|
27
|
+
const message = error.message || "validation failed";
|
|
28
|
+
if (!errorsByPath.has(path)) {
|
|
29
|
+
errorsByPath.set(path, new Set());
|
|
30
|
+
}
|
|
31
|
+
// Use optional chaining for safety
|
|
32
|
+
errorsByPath.get(path)?.add(message);
|
|
33
|
+
}
|
|
34
|
+
return Array.from(errorsByPath.entries()).map(([path, messages]) => {
|
|
35
|
+
const property = path === "root" ? "file" : path.replace("/", "");
|
|
36
|
+
const messageList = Array.from(messages).join(", ");
|
|
37
|
+
return `${property}: ${messageList}`;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Fallback if JSON parsing fails
|
|
42
|
+
return [errorsJson];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Formats validation results for terminal output with color coding.
|
|
47
|
+
* Displays failed validations first, followed by passed validations,
|
|
48
|
+
* and ends with a summary. In verbose mode, shows additional context
|
|
49
|
+
* including file contents and validation rules.
|
|
50
|
+
*
|
|
51
|
+
* @param results - Array of validation results to format
|
|
52
|
+
* @param verbose - Whether to show detailed information including file contents and rules
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const results = [
|
|
57
|
+
* { rule: "package.json", passed: true },
|
|
58
|
+
* { rule: "biome.json", passed: false, message: "File not found" }
|
|
59
|
+
* ];
|
|
60
|
+
* formatTerminalOutput(results, true);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function formatTerminalOutput(results, verbose = false) {
|
|
64
|
+
console.log(); // Empty line for spacing
|
|
65
|
+
const passedResults = results.filter((r) => r.passed);
|
|
66
|
+
const failedResults = results.filter((r) => !r.passed);
|
|
67
|
+
if (failedResults.length > 0) {
|
|
68
|
+
console.log(chalk.red.bold("✗ FAILED VALIDATIONS"));
|
|
69
|
+
console.log(chalk.gray("─".repeat(50)));
|
|
70
|
+
for (const result of failedResults) {
|
|
71
|
+
console.log(chalk.red(`✗ ${result.rule}`));
|
|
72
|
+
if (verbose && result.context) {
|
|
73
|
+
console.log(chalk.gray(` Target: ${result.context.target}`));
|
|
74
|
+
if (result.context.description) {
|
|
75
|
+
console.log(chalk.gray(` Rule: ${result.context.description}`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (result.message) {
|
|
79
|
+
// Check if message contains JSON (AJV errors)
|
|
80
|
+
if (result.message.includes("Validation failed: [")) {
|
|
81
|
+
const jsonStart = result.message.indexOf("[");
|
|
82
|
+
const prefix = result.message.substring(0, jsonStart).trim();
|
|
83
|
+
const jsonPart = result.message.substring(jsonStart);
|
|
84
|
+
if (prefix) {
|
|
85
|
+
console.log(chalk.gray(` ${prefix}`));
|
|
86
|
+
}
|
|
87
|
+
const formattedErrors = formatAjvErrors(jsonPart);
|
|
88
|
+
for (const error of formattedErrors) {
|
|
89
|
+
console.log(chalk.gray(` • ${error}`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log(chalk.gray(` ${result.message}`));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (verbose &&
|
|
97
|
+
result.context?.value &&
|
|
98
|
+
result.context.value !== "[File not found]") {
|
|
99
|
+
// Use regular string instead of template literal where no interpolation needed
|
|
100
|
+
console.log(chalk.gray(" Found:"));
|
|
101
|
+
if (typeof result.context.value === "object") {
|
|
102
|
+
const preview = JSON.stringify(result.context.value, null, 2)
|
|
103
|
+
.split("\n")
|
|
104
|
+
.slice(0, 10) // Show first 10 lines
|
|
105
|
+
.map((line) => ` ${line}`)
|
|
106
|
+
.join("\n");
|
|
107
|
+
console.log(chalk.gray(preview));
|
|
108
|
+
if (JSON.stringify(result.context.value).split("\n").length > 10) {
|
|
109
|
+
console.log(chalk.gray(" ... (truncated)"));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.log(chalk.gray(` ${result.context.value}`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
console.log(); // Empty line between failures
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (passedResults.length > 0) {
|
|
120
|
+
console.log(chalk.green.bold("✓ PASSED VALIDATIONS"));
|
|
121
|
+
console.log(chalk.gray("─".repeat(50)));
|
|
122
|
+
for (const result of passedResults) {
|
|
123
|
+
console.log(chalk.green(`✓ ${result.rule}`));
|
|
124
|
+
if (verbose && result.context) {
|
|
125
|
+
console.log(chalk.gray(` Target: ${result.context.target}`));
|
|
126
|
+
if (result.context.description) {
|
|
127
|
+
console.log(chalk.gray(` Rule: ${result.context.description}`));
|
|
128
|
+
}
|
|
129
|
+
if (result.context.value && typeof result.context.value === "object") {
|
|
130
|
+
// Use regular string instead of template literal
|
|
131
|
+
console.log(chalk.gray(" Validated content:"));
|
|
132
|
+
const preview = JSON.stringify(result.context.value, null, 2)
|
|
133
|
+
.split("\n")
|
|
134
|
+
.slice(0, 5) // Show fewer lines for passed validations
|
|
135
|
+
.map((line) => ` ${line}`)
|
|
136
|
+
.join("\n");
|
|
137
|
+
console.log(chalk.gray(preview));
|
|
138
|
+
if (JSON.stringify(result.context.value).split("\n").length > 5) {
|
|
139
|
+
console.log(chalk.gray(" ... (content validated successfully)"));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
console.log();
|
|
145
|
+
}
|
|
146
|
+
// Summary
|
|
147
|
+
const total = results.length;
|
|
148
|
+
const failed = failedResults.length;
|
|
149
|
+
const passed = passedResults.length;
|
|
150
|
+
if (failed > 0) {
|
|
151
|
+
console.log(chalk.red.bold(`Summary: ${failed}/${total} validations failed (${passed} passed)`));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log(chalk.green.bold(`Summary: All ${total} validations passed`));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Formats validation results as JSON for programmatic consumption.
|
|
159
|
+
* Outputs a structured object with summary statistics and detailed results.
|
|
160
|
+
*
|
|
161
|
+
* @param results - Array of validation results to format
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const results = [
|
|
166
|
+
* { rule: "package.json", passed: true },
|
|
167
|
+
* { rule: "biome.json", passed: false, message: "File not found" }
|
|
168
|
+
* ];
|
|
169
|
+
* formatJsonOutput(results);
|
|
170
|
+
* // Outputs: {
|
|
171
|
+
* // "summary": { "total": 2, "passed": 1, "failed": 1 },
|
|
172
|
+
* // "results": [...]
|
|
173
|
+
* // }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
function formatJsonOutput(results) {
|
|
177
|
+
const output = {
|
|
178
|
+
summary: {
|
|
179
|
+
total: results.length,
|
|
180
|
+
passed: results.filter((r) => r.passed).length,
|
|
181
|
+
failed: results.filter((r) => !r.passed).length,
|
|
182
|
+
},
|
|
183
|
+
results: results.map((result) => ({
|
|
184
|
+
rule: result.rule,
|
|
185
|
+
passed: result.passed,
|
|
186
|
+
...(result.message && { message: result.message }),
|
|
187
|
+
})),
|
|
188
|
+
};
|
|
189
|
+
console.log(JSON.stringify(output, null, 2));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Displays available rulesets in a tree-like format.
|
|
193
|
+
* Groups rulesets by their location (bundled vs current directory).
|
|
194
|
+
*/
|
|
195
|
+
async function displayRulesetTree() {
|
|
196
|
+
const { bundled, local } = await discoverAllRulesets();
|
|
197
|
+
if (bundled.length === 0 && local.length === 0) {
|
|
198
|
+
console.log(chalk.yellow("No rulesets found"));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log(chalk.bold("\nAvailable Webarchitect Rulesets:"));
|
|
202
|
+
console.log(chalk.gray("─".repeat(50)));
|
|
203
|
+
// Display bundled rulesets
|
|
204
|
+
if (bundled.length > 0) {
|
|
205
|
+
console.log(chalk.cyan("Bundled Rulesets:"));
|
|
206
|
+
console.log(chalk.gray(`└── ${bundled[0].path.replace(/\/[^/]+$/, "")}/`));
|
|
207
|
+
for (let i = 0; i < bundled.length; i++) {
|
|
208
|
+
const isLast = i === bundled.length - 1;
|
|
209
|
+
const prefix = isLast ? "└──" : "├──";
|
|
210
|
+
const filename = `${bundled[i].name}.ruleset.json`;
|
|
211
|
+
console.log(` ${prefix} ${chalk.bold(bundled[i].name)} ${chalk.gray(`(${filename})`)}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Display current directory rulesets
|
|
215
|
+
if (bundled.length > 0)
|
|
216
|
+
console.log(); // Add spacing between sections
|
|
217
|
+
console.log(chalk.green("Current Directory:"));
|
|
218
|
+
console.log(chalk.gray(`└── ${process.cwd()}/`));
|
|
219
|
+
if (local.length > 0) {
|
|
220
|
+
for (let i = 0; i < local.length; i++) {
|
|
221
|
+
const isLast = i === local.length - 1;
|
|
222
|
+
const prefix = isLast ? "└──" : "├──";
|
|
223
|
+
const filename = `${local[i].name}.ruleset.json`;
|
|
224
|
+
console.log(` ${prefix} ${chalk.bold(local[i].name)} ${chalk.gray(`(${filename})`)}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.log(chalk.gray(` └── (no rulesets found at this path)`));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
program
|
|
232
|
+
.name("webarchitect")
|
|
233
|
+
.argument("[ruleset]", "ruleset identifier, local path, or URL")
|
|
234
|
+
.option("-v, --verbose", "show all validation results")
|
|
235
|
+
.option("--json", "output results in JSON format")
|
|
236
|
+
.option("--list", "list all available rulesets")
|
|
237
|
+
.action(async (schemaArg, options) => {
|
|
238
|
+
// Handle --list option
|
|
239
|
+
if (options.list) {
|
|
240
|
+
await displayRulesetTree();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
// Require ruleset argument if not listing
|
|
244
|
+
if (!schemaArg) {
|
|
245
|
+
console.error(chalk.red("Error: Missing required argument 'ruleset'"));
|
|
246
|
+
console.error(chalk.gray("Use 'webarchitect --list' to see available rulesets"));
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const results = await validate(process.cwd(), schemaArg);
|
|
251
|
+
if (options.json) {
|
|
252
|
+
formatJsonOutput(results);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
formatTerminalOutput(results, options.verbose);
|
|
256
|
+
// Exit with error code if any validations failed
|
|
257
|
+
const hasFailures = results.some((r) => !r.passed);
|
|
258
|
+
if (hasFailures) {
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (e) {
|
|
264
|
+
if (options.json) {
|
|
265
|
+
console.log(JSON.stringify({
|
|
266
|
+
error: e.message,
|
|
267
|
+
success: false,
|
|
268
|
+
}, null, 2));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
console.error(chalk.red(`Error: ${e.message}`));
|
|
272
|
+
}
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
program.parse();
|
|
277
|
+
//# 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
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import validateDirectoryRule from "./validateDirectoryRule.js";
|
|
2
|
+
import validateFileRule from "./validateFileRule.js";
|
|
3
|
+
export default async function executeValidationRules(projectPath, schema) {
|
|
4
|
+
const results = [];
|
|
5
|
+
// Iterate through each rule in the schema
|
|
6
|
+
for (const [ruleName, rule] of Object.entries(schema)) {
|
|
7
|
+
// Skip meta-properties that aren't validation rules
|
|
8
|
+
if (ruleName === "$schema" || ruleName === "name" || ruleName === "extends")
|
|
9
|
+
continue;
|
|
10
|
+
// Type guard to ensure rule is an object with 'file' or 'directory'
|
|
11
|
+
if (typeof rule === "object" && rule !== null) {
|
|
12
|
+
if ("file" in rule) {
|
|
13
|
+
// Pass the rule name context to file validation
|
|
14
|
+
const fileResults = await validateFileRule(projectPath, rule.file, ruleName);
|
|
15
|
+
results.push(...fileResults);
|
|
16
|
+
}
|
|
17
|
+
else if ("directory" in rule) {
|
|
18
|
+
// Pass the rule name context to directory validation
|
|
19
|
+
const dirResults = await validateDirectoryRule(projectPath, rule.directory, ruleName);
|
|
20
|
+
results.push(...dirResults);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=executeValidationRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executeValidationRules.js","sourceRoot":"","sources":["../../src/executeValidationRules.ts"],"names":[],"mappings":"AACA,OAAO,qBAAqB,MAAM,4BAA4B,CAAC;AAC/D,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;AAErD,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,sBAAsB,CAClD,WAAmB,EACnB,MAAc;IAEd,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,0CAA0C;IAC1C,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,oDAAoD;QACpD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,SAAS;YACzE,SAAS;QAEX,oEAAoE;QACpE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAC9C,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,gDAAgD;gBAChD,MAAM,WAAW,GAAG,MAAM,gBAAgB,CACxC,WAAW,EACX,IAAI,CAAC,IAAI,EACT,QAAQ,CACT,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;YAC/B,CAAC;iBAAM,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;gBAC/B,qDAAqD;gBACrD,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAC5C,WAAW,EACX,IAAI,CAAC,SAAS,EACd,QAAQ,CACT,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|