@spwig/theme-validator 1.0.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.
Files changed (36) hide show
  1. package/README.md +367 -0
  2. package/dist/index.d.ts +12 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +11 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/schemas/component_manifest_schema.json +221 -0
  7. package/dist/schemas/theme_manifest_schema.json +267 -0
  8. package/dist/types/manifest.d.ts +183 -0
  9. package/dist/types/manifest.d.ts.map +1 -0
  10. package/dist/types/manifest.js +5 -0
  11. package/dist/types/manifest.js.map +1 -0
  12. package/dist/types/validation-result.d.ts +48 -0
  13. package/dist/types/validation-result.d.ts.map +1 -0
  14. package/dist/types/validation-result.js +26 -0
  15. package/dist/types/validation-result.js.map +1 -0
  16. package/dist/validators/component-validator.d.ts +50 -0
  17. package/dist/validators/component-validator.d.ts.map +1 -0
  18. package/dist/validators/component-validator.js +235 -0
  19. package/dist/validators/component-validator.js.map +1 -0
  20. package/dist/validators/design-tokens-validator.d.ts +46 -0
  21. package/dist/validators/design-tokens-validator.d.ts.map +1 -0
  22. package/dist/validators/design-tokens-validator.js +202 -0
  23. package/dist/validators/design-tokens-validator.js.map +1 -0
  24. package/dist/validators/manifest-validator.d.ts +69 -0
  25. package/dist/validators/manifest-validator.d.ts.map +1 -0
  26. package/dist/validators/manifest-validator.js +206 -0
  27. package/dist/validators/manifest-validator.js.map +1 -0
  28. package/dist/validators/template-validator.d.ts +34 -0
  29. package/dist/validators/template-validator.d.ts.map +1 -0
  30. package/dist/validators/template-validator.js +170 -0
  31. package/dist/validators/template-validator.js.map +1 -0
  32. package/dist/validators/theme-validator.d.ts +44 -0
  33. package/dist/validators/theme-validator.d.ts.map +1 -0
  34. package/dist/validators/theme-validator.js +237 -0
  35. package/dist/validators/theme-validator.js.map +1 -0
  36. package/package.json +50 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Manifest Validator
3
+ * Validates JSON manifests against schemas using Ajv
4
+ */
5
+ import Ajv from 'ajv';
6
+ import addErrors from 'ajv-errors';
7
+ import fs from 'fs-extra';
8
+ import path from 'path';
9
+ import { createError, } from '../types/validation-result.js';
10
+ export class ManifestValidator {
11
+ ajv;
12
+ errors = [];
13
+ warnings = [];
14
+ constructor() {
15
+ this.ajv = new Ajv({
16
+ allErrors: true,
17
+ verbose: true,
18
+ strict: false,
19
+ });
20
+ addErrors(this.ajv);
21
+ }
22
+ /**
23
+ * Load a JSON schema from file
24
+ */
25
+ async loadSchema(schemaPath) {
26
+ try {
27
+ const schemaContent = await fs.readFile(schemaPath, 'utf-8');
28
+ return JSON.parse(schemaContent);
29
+ }
30
+ catch (error) {
31
+ if (error instanceof Error) {
32
+ throw new Error(`Failed to load schema from ${schemaPath}: ${error.message}`);
33
+ }
34
+ throw error;
35
+ }
36
+ }
37
+ /**
38
+ * Load a JSON file
39
+ */
40
+ async loadJSON(filePath) {
41
+ try {
42
+ const content = await fs.readFile(filePath, 'utf-8');
43
+ return JSON.parse(content);
44
+ }
45
+ catch (error) {
46
+ if (error instanceof SyntaxError) {
47
+ this.errors.push(createError('json_parse_error', `Invalid JSON in ${path.basename(filePath)}: ${error.message}`, {
48
+ path: filePath,
49
+ }));
50
+ }
51
+ else if (error instanceof Error) {
52
+ this.errors.push(createError('file_error', `Failed to read ${path.basename(filePath)}: ${error.message}`, {
53
+ path: filePath,
54
+ }));
55
+ }
56
+ throw error;
57
+ }
58
+ }
59
+ /**
60
+ * Validate manifest against schema
61
+ */
62
+ validateAgainstSchema(manifest, schema, manifestType = 'manifest') {
63
+ const validate = this.ajv.compile(schema);
64
+ const valid = validate(manifest);
65
+ if (!valid && validate.errors) {
66
+ for (const error of validate.errors) {
67
+ this.errors.push(this.convertAjvError(error, manifestType));
68
+ }
69
+ }
70
+ return valid;
71
+ }
72
+ /**
73
+ * Convert Ajv error to ValidationError
74
+ */
75
+ convertAjvError(error, manifestType) {
76
+ const dataPath = error.instancePath || error.schemaPath;
77
+ let message = error.message || 'Validation error';
78
+ // Make error message more readable
79
+ if (error.keyword === 'required') {
80
+ const missingProp = error.params.missingProperty;
81
+ message = `Missing required property: ${missingProp}`;
82
+ }
83
+ else if (error.keyword === 'pattern') {
84
+ message = `${dataPath} ${message}`;
85
+ }
86
+ else if (error.keyword === 'enum') {
87
+ const allowedValues = error.params.allowedValues;
88
+ message = `${dataPath} must be one of: ${allowedValues.join(', ')}`;
89
+ }
90
+ else if (dataPath) {
91
+ message = `${dataPath}: ${message}`;
92
+ }
93
+ return createError('schema_validation', message, {
94
+ path: dataPath,
95
+ });
96
+ }
97
+ /**
98
+ * Reset errors and warnings
99
+ */
100
+ reset() {
101
+ this.errors = [];
102
+ this.warnings = [];
103
+ }
104
+ /**
105
+ * Get current errors
106
+ */
107
+ getErrors() {
108
+ return this.errors;
109
+ }
110
+ /**
111
+ * Get current warnings
112
+ */
113
+ getWarnings() {
114
+ return this.warnings;
115
+ }
116
+ /**
117
+ * Add an error
118
+ */
119
+ addError(error) {
120
+ this.errors.push(error);
121
+ }
122
+ /**
123
+ * Add a warning
124
+ */
125
+ addWarning(warning) {
126
+ this.warnings.push(warning);
127
+ }
128
+ /**
129
+ * Check if file exists
130
+ */
131
+ async fileExists(filePath) {
132
+ try {
133
+ const stats = await fs.stat(filePath);
134
+ return stats.isFile();
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ }
140
+ /**
141
+ * Check if directory exists
142
+ */
143
+ async directoryExists(dirPath) {
144
+ try {
145
+ const stats = await fs.stat(dirPath);
146
+ return stats.isDirectory();
147
+ }
148
+ catch {
149
+ return false;
150
+ }
151
+ }
152
+ /**
153
+ * Compare semantic versions
154
+ * @returns -1 if v1 < v2, 0 if equal, 1 if v1 > v2
155
+ */
156
+ compareVersions(v1, v2) {
157
+ const parts1 = v1.split('.').map(Number);
158
+ const parts2 = v2.split('.').map(Number);
159
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
160
+ const p1 = parts1[i] || 0;
161
+ const p2 = parts2[i] || 0;
162
+ if (p1 < p2)
163
+ return -1;
164
+ if (p1 > p2)
165
+ return 1;
166
+ }
167
+ return 0;
168
+ }
169
+ /**
170
+ * Validate file is not empty
171
+ */
172
+ async validateFileNotEmpty(filePath, fileType) {
173
+ try {
174
+ const stats = await fs.stat(filePath);
175
+ if (stats.size === 0) {
176
+ this.addError(createError('empty_file', `${fileType} file is empty`, {
177
+ path: filePath,
178
+ }));
179
+ return false;
180
+ }
181
+ return true;
182
+ }
183
+ catch (error) {
184
+ this.addError(createError('file_error', `Failed to check ${fileType} file size`, {
185
+ path: filePath,
186
+ }));
187
+ return false;
188
+ }
189
+ }
190
+ /**
191
+ * Validate file is valid UTF-8
192
+ */
193
+ async validateUTF8(filePath, fileType) {
194
+ try {
195
+ await fs.readFile(filePath, 'utf-8');
196
+ return true;
197
+ }
198
+ catch (error) {
199
+ this.addError(createError('encoding_error', `${fileType} file is not valid UTF-8`, {
200
+ path: filePath,
201
+ }));
202
+ return false;
203
+ }
204
+ }
205
+ }
206
+ //# sourceMappingURL=manifest-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest-validator.js","sourceRoot":"","sources":["../../src/validators/manifest-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Template Validator
3
+ * Validates Django/Jinja2 template files
4
+ */
5
+ import { ValidationResult } from '../types/validation-result.js';
6
+ export declare class TemplateValidator {
7
+ private errors;
8
+ private warnings;
9
+ /**
10
+ * Validate a template file
11
+ */
12
+ validate(templatePath: string): Promise<ValidationResult>;
13
+ /**
14
+ * Check file exists
15
+ */
16
+ private fileExists;
17
+ /**
18
+ * Read template content
19
+ */
20
+ private readTemplate;
21
+ /**
22
+ * Check basic template syntax
23
+ */
24
+ private checkTemplateSyntax;
25
+ /**
26
+ * Check for common template issues
27
+ */
28
+ private checkCommonIssues;
29
+ /**
30
+ * Build validation result
31
+ */
32
+ private buildResult;
33
+ }
34
+ //# sourceMappingURL=template-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-validator.d.ts","sourceRoot":"","sources":["../../src/validators/template-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,gBAAgB,EAKjB,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAA2B;IAE3C;;OAEG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2B/D;;OAEG;YACW,UAAU;IASxB;;OAEG;YACW,YAAY;IA0B1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwE3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6CzB;;OAEG;IACH,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Template Validator
3
+ * Validates Django/Jinja2 template files
4
+ */
5
+ import fs from 'fs-extra';
6
+ import { createError, createWarning, } from '../types/validation-result.js';
7
+ export class TemplateValidator {
8
+ errors = [];
9
+ warnings = [];
10
+ /**
11
+ * Validate a template file
12
+ */
13
+ async validate(templatePath) {
14
+ this.errors = [];
15
+ this.warnings = [];
16
+ // Check file exists
17
+ if (!(await this.fileExists(templatePath))) {
18
+ this.errors.push(createError('file_not_found', `Template file does not exist: ${templatePath}`));
19
+ return this.buildResult();
20
+ }
21
+ // Check file is not empty
22
+ const content = await this.readTemplate(templatePath);
23
+ if (!content) {
24
+ return this.buildResult();
25
+ }
26
+ // Basic template syntax checks
27
+ this.checkTemplateSyntax(content, templatePath);
28
+ // Check for common issues
29
+ this.checkCommonIssues(content, templatePath);
30
+ return this.buildResult();
31
+ }
32
+ /**
33
+ * Check file exists
34
+ */
35
+ async fileExists(filePath) {
36
+ try {
37
+ const stats = await fs.stat(filePath);
38
+ return stats.isFile();
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Read template content
46
+ */
47
+ async readTemplate(templatePath) {
48
+ try {
49
+ const content = await fs.readFile(templatePath, 'utf-8');
50
+ if (content.trim().length === 0) {
51
+ this.errors.push(createError('empty_template', 'Template file is empty', {
52
+ path: templatePath,
53
+ }));
54
+ return null;
55
+ }
56
+ return content;
57
+ }
58
+ catch (error) {
59
+ if (error instanceof Error) {
60
+ this.errors.push(createError('read_error', `Failed to read template: ${error.message}`, {
61
+ path: templatePath,
62
+ }));
63
+ }
64
+ return null;
65
+ }
66
+ }
67
+ /**
68
+ * Check basic template syntax
69
+ */
70
+ checkTemplateSyntax(content, templatePath) {
71
+ const lines = content.split('\n');
72
+ // Check for unclosed tags
73
+ let blockStack = [];
74
+ const blockTags = ['if', 'for', 'block', 'with', 'autoescape', 'spaceless', 'verbatim'];
75
+ lines.forEach((line, index) => {
76
+ const lineNumber = index + 1;
77
+ // Find opening tags
78
+ const openMatches = line.matchAll(/{%\s*(\w+)/g);
79
+ for (const match of openMatches) {
80
+ const tag = match[1];
81
+ if (blockTags.includes(tag)) {
82
+ blockStack.push({ tag, line: lineNumber });
83
+ }
84
+ }
85
+ // Find closing tags
86
+ const closeMatches = line.matchAll(/{%\s*end(\w+)/g);
87
+ for (const match of closeMatches) {
88
+ const tag = match[1];
89
+ if (blockStack.length === 0) {
90
+ this.errors.push(createError('template_syntax', `Unexpected closing tag: {% end${tag} %}`, {
91
+ path: templatePath,
92
+ line: lineNumber,
93
+ }));
94
+ }
95
+ else {
96
+ const lastBlock = blockStack.pop();
97
+ if (lastBlock && lastBlock.tag !== tag) {
98
+ this.errors.push(createError('template_syntax', `Mismatched closing tag: expected {% end${lastBlock.tag} %}, found {% end${tag} %}`, {
99
+ path: templatePath,
100
+ line: lineNumber,
101
+ }));
102
+ }
103
+ }
104
+ }
105
+ });
106
+ // Check for unclosed blocks
107
+ if (blockStack.length > 0) {
108
+ for (const block of blockStack) {
109
+ this.errors.push(createError('template_syntax', `Unclosed block: {% ${block.tag} %}`, {
110
+ path: templatePath,
111
+ line: block.line,
112
+ }));
113
+ }
114
+ }
115
+ // Check for basic variable syntax errors
116
+ const variablePattern = /{{\s*[\w._[\]]+\s*}}/g;
117
+ const invalidVariables = content.match(/{{[^}]*$/gm);
118
+ if (invalidVariables) {
119
+ this.errors.push(createError('template_syntax', 'Unclosed variable tag: {{', {
120
+ path: templatePath,
121
+ }));
122
+ }
123
+ }
124
+ /**
125
+ * Check for common template issues
126
+ */
127
+ checkCommonIssues(content, templatePath) {
128
+ // Warn about hardcoded URLs
129
+ if (content.includes('http://') || content.includes('https://')) {
130
+ const httpMatches = content.match(/https?:\/\/[^\s"'<>]+/g);
131
+ if (httpMatches && httpMatches.length > 0) {
132
+ this.warnings.push(createWarning('hardcoded_url', `Found ${httpMatches.length} hardcoded URL(s) in template`, {
133
+ path: templatePath,
134
+ suggestion: 'Use relative URLs or Django template tags like {% url %}',
135
+ }));
136
+ }
137
+ }
138
+ // Warn about inline styles (should use design tokens)
139
+ const inlineStyleCount = (content.match(/style\s*=/gi) || []).length;
140
+ if (inlineStyleCount > 3) {
141
+ this.warnings.push(createWarning('inline_styles', `Found ${inlineStyleCount} inline style attributes`, {
142
+ path: templatePath,
143
+ suggestion: 'Consider using CSS classes and design tokens instead',
144
+ }));
145
+ }
146
+ // Check for missing alt attributes on images
147
+ const imgTags = content.match(/<img[^>]+>/gi);
148
+ if (imgTags) {
149
+ for (const imgTag of imgTags) {
150
+ if (!imgTag.includes('alt=')) {
151
+ this.warnings.push(createWarning('accessibility', 'Image tag missing alt attribute', {
152
+ path: templatePath,
153
+ suggestion: 'Add alt attribute for accessibility',
154
+ }));
155
+ }
156
+ }
157
+ }
158
+ }
159
+ /**
160
+ * Build validation result
161
+ */
162
+ buildResult() {
163
+ return {
164
+ isValid: this.errors.length === 0,
165
+ errors: this.errors,
166
+ warnings: this.warnings,
167
+ };
168
+ }
169
+ }
170
+ //# sourceMappingURL=template-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-validator.js","sourceRoot":"","sources":["../../src/validators/template-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Theme Validator
3
+ * Validates theme packages with bundled components
4
+ */
5
+ import { ManifestValidator } from './manifest-validator.js';
6
+ import { ValidationResult } from '../types/validation-result.js';
7
+ export declare class ThemeValidator extends ManifestValidator {
8
+ private themeDir;
9
+ private manifest;
10
+ constructor(themeDir: string);
11
+ /**
12
+ * Validate complete theme package
13
+ */
14
+ validate(): Promise<ValidationResult>;
15
+ /**
16
+ * Validate all bundled components
17
+ */
18
+ private validateBundledComponents;
19
+ /**
20
+ * Validate page schema files exist
21
+ */
22
+ private validatePageSchemas;
23
+ /**
24
+ * Validate design tokens file exists and is valid JSON
25
+ */
26
+ private validateDesignTokens;
27
+ /**
28
+ * Validate preview image exists
29
+ */
30
+ private validatePreviewImage;
31
+ /**
32
+ * Validate screenshot files exist
33
+ */
34
+ private validateScreenshots;
35
+ /**
36
+ * Build validation result
37
+ */
38
+ private buildResult;
39
+ /**
40
+ * Generate human-readable validation report
41
+ */
42
+ getValidationReport(): string;
43
+ }
44
+ //# sourceMappingURL=theme-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-validator.d.ts","sourceRoot":"","sources":["../../src/validators/theme-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACL,gBAAgB,EAGjB,MAAM,+BAA+B,CAAC;AAGvC,qBAAa,cAAe,SAAQ,iBAAiB;IACnD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAA8B;gBAElC,QAAQ,EAAE,MAAM;IAK5B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA6D3C;;OAEG;YACW,yBAAyB;IAyCvC;;OAEG;YACW,mBAAmB;IAwBjC;;OAEG;YACW,oBAAoB;IAiClC;;OAEG;YACW,oBAAoB;IA0BlC;;OAEG;YACW,mBAAmB;IAyBjC;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,mBAAmB,IAAI,MAAM;CAqC9B"}