@stati/core 1.4.0 → 1.6.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/README.md +1 -1
- package/dist/core/dev.d.ts.map +1 -1
- package/dist/core/dev.js +154 -87
- package/dist/core/isg/hash.d.ts.map +1 -1
- package/dist/core/isg/hash.js +13 -1
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +21 -2
- package/dist/core/preview.d.ts.map +1 -1
- package/dist/core/preview.js +17 -21
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +84 -10
- package/dist/core/utils/error-overlay.d.ts +31 -0
- package/dist/core/utils/error-overlay.d.ts.map +1 -0
- package/dist/core/utils/error-overlay.js +562 -0
- package/dist/core/utils/partial-validation.d.ts +6 -0
- package/dist/core/utils/partial-validation.d.ts.map +1 -0
- package/dist/core/utils/partial-validation.js +129 -0
- package/dist/core/utils/server.d.ts +23 -0
- package/dist/core/utils/server.d.ts.map +1 -0
- package/dist/core/utils/server.js +61 -0
- package/dist/core/utils/template-errors.d.ts +28 -0
- package/dist/core/utils/template-errors.d.ts.map +1 -0
- package/dist/core/utils/template-errors.js +128 -0
- package/dist/core/utils/template-utils.d.ts +20 -0
- package/dist/core/utils/template-utils.d.ts.map +1 -0
- package/dist/core/utils/template-utils.js +39 -0
- package/dist/core/utils/version.d.ts +6 -0
- package/dist/core/utils/version.d.ts.map +1 -0
- package/dist/core/utils/version.js +20 -0
- package/dist/env.d.ts +3 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates inline error overlay HTML for missing partials
|
|
3
|
+
*/
|
|
4
|
+
function createInlineErrorOverlay(partialName, suggestions) {
|
|
5
|
+
const suggestionText = suggestions.length > 0
|
|
6
|
+
? `Did you mean: ${suggestions.map((s) => `"${s}"`).join(', ')}?`
|
|
7
|
+
: 'No similar partials found';
|
|
8
|
+
return `
|
|
9
|
+
<!-- Stati Development Error Overlay -->
|
|
10
|
+
<div style="
|
|
11
|
+
position: fixed;
|
|
12
|
+
top: 20px;
|
|
13
|
+
right: 20px;
|
|
14
|
+
z-index: 999999;
|
|
15
|
+
background: #dc2626;
|
|
16
|
+
color: white;
|
|
17
|
+
padding: 16px;
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
21
|
+
font-size: 14px;
|
|
22
|
+
line-height: 1.4;
|
|
23
|
+
max-width: 400px;
|
|
24
|
+
border: 2px solid #fca5a5;
|
|
25
|
+
">
|
|
26
|
+
<div style="font-weight: 600; margin-bottom: 8px; font-size: 16px;">
|
|
27
|
+
⚠️ Template Error
|
|
28
|
+
</div>
|
|
29
|
+
<div style="margin-bottom: 8px;">
|
|
30
|
+
<strong>Partial "${partialName}" not found</strong>
|
|
31
|
+
</div>
|
|
32
|
+
<div style="color: #fca5a5; font-size: 13px;">
|
|
33
|
+
${suggestionText}
|
|
34
|
+
</div>
|
|
35
|
+
<div style="margin-top: 12px; padding-top: 8px; border-top: 1px solid #fca5a5; font-size: 12px; opacity: 0.8;">
|
|
36
|
+
Fix the partial name in your template to dismiss this error
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<!-- End Stati Error Overlay -->`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Finds similar partial names to suggest when a partial is not found
|
|
43
|
+
*/
|
|
44
|
+
function findSimilarPartialNames(targetName, availableNames) {
|
|
45
|
+
if (availableNames.length === 0)
|
|
46
|
+
return [];
|
|
47
|
+
// Simple similarity check based on common prefixes and substrings
|
|
48
|
+
const target = targetName.toLowerCase();
|
|
49
|
+
const suggestions = availableNames
|
|
50
|
+
.map((name) => {
|
|
51
|
+
const candidate = name.toLowerCase();
|
|
52
|
+
let score = 0;
|
|
53
|
+
// Exact match gets highest score
|
|
54
|
+
if (candidate === target)
|
|
55
|
+
return { name, score: 1000 };
|
|
56
|
+
// Check if one is contained in the other
|
|
57
|
+
if (candidate.includes(target) || target.includes(candidate)) {
|
|
58
|
+
score += 100;
|
|
59
|
+
}
|
|
60
|
+
// Check common prefix length
|
|
61
|
+
let prefixLen = 0;
|
|
62
|
+
for (let i = 0; i < Math.min(target.length, candidate.length); i++) {
|
|
63
|
+
if (target[i] === candidate[i]) {
|
|
64
|
+
prefixLen++;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
score += prefixLen * 10;
|
|
71
|
+
// Check common characters
|
|
72
|
+
const targetChars = new Set(target);
|
|
73
|
+
const candidateChars = new Set(candidate);
|
|
74
|
+
const commonChars = [...targetChars].filter((char) => candidateChars.has(char));
|
|
75
|
+
score += commonChars.length;
|
|
76
|
+
return { name, score };
|
|
77
|
+
})
|
|
78
|
+
.filter((item) => item.score > 0) // Only include items with some similarity
|
|
79
|
+
.sort((a, b) => b.score - a.score) // Sort by score descending
|
|
80
|
+
.slice(0, 3) // Top 3 suggestions
|
|
81
|
+
.map((item) => item.name);
|
|
82
|
+
return suggestions;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a development-mode Proxy for the partials object that throws errors
|
|
86
|
+
* when accessing non-existent partials instead of returning undefined
|
|
87
|
+
*/
|
|
88
|
+
export function createValidatingPartialsProxy(partials) {
|
|
89
|
+
// In production, return partials as-is
|
|
90
|
+
// Only skip validation if explicitly set to production
|
|
91
|
+
if (process.env.NODE_ENV === 'production') {
|
|
92
|
+
return partials;
|
|
93
|
+
}
|
|
94
|
+
return new Proxy(partials, {
|
|
95
|
+
get(target, prop, receiver) {
|
|
96
|
+
// Allow normal object operations
|
|
97
|
+
if (typeof prop === 'symbol') {
|
|
98
|
+
return Reflect.get(target, prop, receiver);
|
|
99
|
+
}
|
|
100
|
+
const propName = String(prop);
|
|
101
|
+
// Check if the property exists
|
|
102
|
+
if (propName in target) {
|
|
103
|
+
return target[propName];
|
|
104
|
+
}
|
|
105
|
+
// Special case: allow accessing length, toString, etc.
|
|
106
|
+
if (propName in Object.prototype || propName === 'length') {
|
|
107
|
+
return Reflect.get(target, prop, receiver);
|
|
108
|
+
}
|
|
109
|
+
// Property doesn't exist - return error overlay HTML instead of throwing
|
|
110
|
+
const availablePartials = Object.keys(target);
|
|
111
|
+
const suggestions = findSimilarPartialNames(propName, availablePartials);
|
|
112
|
+
// Special case: throw error if no partials are available at all
|
|
113
|
+
if (availablePartials.length === 0) {
|
|
114
|
+
throw new Error('No partials are available');
|
|
115
|
+
}
|
|
116
|
+
// In development, render an inline error overlay
|
|
117
|
+
return createInlineErrorOverlay(propName, suggestions);
|
|
118
|
+
},
|
|
119
|
+
has(target, prop) {
|
|
120
|
+
return prop in target;
|
|
121
|
+
},
|
|
122
|
+
ownKeys(target) {
|
|
123
|
+
return Reflect.ownKeys(target);
|
|
124
|
+
},
|
|
125
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
126
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of attempting to resolve a pretty URL path
|
|
3
|
+
*/
|
|
4
|
+
export interface PrettyUrlResult {
|
|
5
|
+
/** The resolved file path to serve */
|
|
6
|
+
filePath: string | null;
|
|
7
|
+
/** Whether the path was found */
|
|
8
|
+
found: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Attempts to resolve pretty URL paths by trying various fallback strategies.
|
|
12
|
+
* This handles common patterns like:
|
|
13
|
+
* - /path/ -> /path/index.html
|
|
14
|
+
* - /path/ -> /path.html (if no index.html exists)
|
|
15
|
+
* - /path -> /path.html (when original path is not found)
|
|
16
|
+
*
|
|
17
|
+
* @param outDir The output directory to serve files from
|
|
18
|
+
* @param requestPath The requested URL path
|
|
19
|
+
* @param originalFilePath The original file path that was attempted
|
|
20
|
+
* @returns Promise resolving to the file path to serve or null if not found
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolvePrettyUrl(outDir: string, requestPath: string, originalFilePath: string): Promise<PrettyUrlResult>;
|
|
23
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/utils/server.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iCAAiC;IACjC,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,eAAe,CAAC,CA+C1B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { stat } from 'fs/promises';
|
|
3
|
+
/**
|
|
4
|
+
* Attempts to resolve pretty URL paths by trying various fallback strategies.
|
|
5
|
+
* This handles common patterns like:
|
|
6
|
+
* - /path/ -> /path/index.html
|
|
7
|
+
* - /path/ -> /path.html (if no index.html exists)
|
|
8
|
+
* - /path -> /path.html (when original path is not found)
|
|
9
|
+
*
|
|
10
|
+
* @param outDir The output directory to serve files from
|
|
11
|
+
* @param requestPath The requested URL path
|
|
12
|
+
* @param originalFilePath The original file path that was attempted
|
|
13
|
+
* @returns Promise resolving to the file path to serve or null if not found
|
|
14
|
+
*/
|
|
15
|
+
export async function resolvePrettyUrl(outDir, requestPath, originalFilePath) {
|
|
16
|
+
try {
|
|
17
|
+
const stats = await stat(originalFilePath);
|
|
18
|
+
if (stats.isDirectory()) {
|
|
19
|
+
// Try to serve index.html from directory
|
|
20
|
+
const indexPath = join(originalFilePath, 'index.html');
|
|
21
|
+
try {
|
|
22
|
+
await stat(indexPath);
|
|
23
|
+
return { filePath: indexPath, found: true };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// If no index.html in directory, try to serve corresponding .html file
|
|
27
|
+
// For example: /examples/ -> examples.html
|
|
28
|
+
const directoryName = requestPath.replace(/\/$/, ''); // Remove trailing slash
|
|
29
|
+
const fallbackPath = join(outDir, `${directoryName}.html`);
|
|
30
|
+
try {
|
|
31
|
+
await stat(fallbackPath);
|
|
32
|
+
return { filePath: fallbackPath, found: true };
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { filePath: null, found: false };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// File exists and is not a directory
|
|
40
|
+
return { filePath: originalFilePath, found: true };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// File not found, try fallback strategies for pretty URLs
|
|
44
|
+
if (requestPath.endsWith('/')) {
|
|
45
|
+
// For requests ending with /, try the corresponding .html file
|
|
46
|
+
const pathWithoutSlash = requestPath.slice(0, -1);
|
|
47
|
+
const htmlPath = join(outDir, `${pathWithoutSlash}.html`);
|
|
48
|
+
try {
|
|
49
|
+
const stats = await stat(htmlPath);
|
|
50
|
+
if (stats.isFile()) {
|
|
51
|
+
return { filePath: htmlPath, found: true };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Continue to not found
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// No fallback worked
|
|
59
|
+
return { filePath: null, found: false };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ErrorDetails } from './error-overlay.js';
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced template error that includes file context and suggestions.
|
|
4
|
+
*/
|
|
5
|
+
export declare class TemplateError extends Error {
|
|
6
|
+
readonly filePath?: string;
|
|
7
|
+
readonly line?: number;
|
|
8
|
+
readonly column?: number;
|
|
9
|
+
readonly template?: string;
|
|
10
|
+
readonly context?: {
|
|
11
|
+
before?: string[];
|
|
12
|
+
after?: string[];
|
|
13
|
+
};
|
|
14
|
+
constructor(message: string, filePath?: string, line?: number, column?: number, template?: string);
|
|
15
|
+
/**
|
|
16
|
+
* Converts this template error to ErrorDetails for the overlay.
|
|
17
|
+
*/
|
|
18
|
+
toErrorDetails(): Promise<ErrorDetails>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parses Eta template errors to extract file location information.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseEtaError(error: Error, templatePath?: string): TemplateError;
|
|
24
|
+
/**
|
|
25
|
+
* Enhances a generic error with template-specific context.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createTemplateError(error: Error, templatePath?: string, _line?: number, _column?: number): TemplateError;
|
|
28
|
+
//# sourceMappingURL=template-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-errors.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-errors.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChC,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClC,SAAgB,OAAO,CAAC,EAAE;QACxB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;gBAGA,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM;IAUnB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC;CAoE9C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CA8BhF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,EACZ,YAAY,CAAC,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf,aAAa,CAMf"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { pathExists } from './fs.js';
|
|
3
|
+
/**
|
|
4
|
+
* Enhanced template error that includes file context and suggestions.
|
|
5
|
+
*/
|
|
6
|
+
export class TemplateError extends Error {
|
|
7
|
+
filePath;
|
|
8
|
+
line;
|
|
9
|
+
column;
|
|
10
|
+
template;
|
|
11
|
+
context;
|
|
12
|
+
constructor(message, filePath, line, column, template) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'TemplateError';
|
|
15
|
+
if (filePath !== undefined)
|
|
16
|
+
this.filePath = filePath;
|
|
17
|
+
if (line !== undefined)
|
|
18
|
+
this.line = line;
|
|
19
|
+
if (column !== undefined)
|
|
20
|
+
this.column = column;
|
|
21
|
+
if (template !== undefined)
|
|
22
|
+
this.template = template;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Converts this template error to ErrorDetails for the overlay.
|
|
26
|
+
*/
|
|
27
|
+
async toErrorDetails() {
|
|
28
|
+
const suggestions = [];
|
|
29
|
+
const message = this.message.toLowerCase();
|
|
30
|
+
// Add specific suggestions based on error type
|
|
31
|
+
if (message.includes('not found') || message.includes('cannot resolve')) {
|
|
32
|
+
suggestions.push('Check if the template file exists and has the correct path');
|
|
33
|
+
suggestions.push('Verify the template reference in your layout or include statement');
|
|
34
|
+
suggestions.push('Ensure the template file has the .eta extension');
|
|
35
|
+
}
|
|
36
|
+
else if (message.includes('syntax') || message.includes('unexpected')) {
|
|
37
|
+
suggestions.push('Check for unmatched brackets, quotes, or parentheses');
|
|
38
|
+
suggestions.push('Verify Eta template syntax is correct');
|
|
39
|
+
suggestions.push('Look for unclosed template tags');
|
|
40
|
+
}
|
|
41
|
+
else if (message.includes('undefined') || message.includes('null')) {
|
|
42
|
+
suggestions.push('Check if all required data is available in template context');
|
|
43
|
+
suggestions.push('Add conditional checks for optional template variables');
|
|
44
|
+
suggestions.push('Verify page frontMatter and data structure');
|
|
45
|
+
}
|
|
46
|
+
// Try to read file context if available
|
|
47
|
+
let context;
|
|
48
|
+
let code;
|
|
49
|
+
if (this.filePath && this.line && (await pathExists(this.filePath))) {
|
|
50
|
+
try {
|
|
51
|
+
const fileContent = await readFile(this.filePath, 'utf-8');
|
|
52
|
+
const lines = fileContent.split('\n');
|
|
53
|
+
const errorLineIndex = this.line - 1;
|
|
54
|
+
if (errorLineIndex >= 0 && errorLineIndex < lines.length) {
|
|
55
|
+
code = lines[errorLineIndex];
|
|
56
|
+
// Get surrounding context
|
|
57
|
+
const contextLines = 3;
|
|
58
|
+
const beforeLines = lines.slice(Math.max(0, errorLineIndex - contextLines), errorLineIndex);
|
|
59
|
+
const afterLines = lines.slice(errorLineIndex + 1, Math.min(lines.length, errorLineIndex + contextLines + 1));
|
|
60
|
+
context = {
|
|
61
|
+
before: beforeLines,
|
|
62
|
+
after: afterLines,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Ignore file read errors
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const errorDetails = {
|
|
71
|
+
type: 'template',
|
|
72
|
+
message: this.message,
|
|
73
|
+
suggestions,
|
|
74
|
+
};
|
|
75
|
+
if (this.stack !== undefined)
|
|
76
|
+
errorDetails.stack = this.stack;
|
|
77
|
+
if (this.filePath !== undefined)
|
|
78
|
+
errorDetails.file = this.filePath;
|
|
79
|
+
if (this.line !== undefined)
|
|
80
|
+
errorDetails.line = this.line;
|
|
81
|
+
if (this.column !== undefined)
|
|
82
|
+
errorDetails.column = this.column;
|
|
83
|
+
if (code !== undefined)
|
|
84
|
+
errorDetails.code = code;
|
|
85
|
+
if (context !== undefined)
|
|
86
|
+
errorDetails.context = context;
|
|
87
|
+
return errorDetails;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Parses Eta template errors to extract file location information.
|
|
92
|
+
*/
|
|
93
|
+
export function parseEtaError(error, templatePath) {
|
|
94
|
+
let filePath = templatePath;
|
|
95
|
+
let line;
|
|
96
|
+
let column;
|
|
97
|
+
// Try to parse error location from Eta error messages
|
|
98
|
+
const message = error.message;
|
|
99
|
+
// Eta syntax errors often include line/column info
|
|
100
|
+
const locationMatch = message.match(/at line (\d+), column (\d+)/i);
|
|
101
|
+
if (locationMatch && locationMatch[1] && locationMatch[2]) {
|
|
102
|
+
line = parseInt(locationMatch[1], 10);
|
|
103
|
+
column = parseInt(locationMatch[2], 10);
|
|
104
|
+
}
|
|
105
|
+
// Try to extract file path from stack trace if not provided
|
|
106
|
+
if (!filePath && error.stack) {
|
|
107
|
+
const stackLines = error.stack.split('\n');
|
|
108
|
+
for (const stackLine of stackLines) {
|
|
109
|
+
const fileMatch = stackLine.match(/at.*\(([^)]+\.eta):(\d+):(\d+)\)/);
|
|
110
|
+
if (fileMatch && fileMatch[1] && fileMatch[2] && fileMatch[3]) {
|
|
111
|
+
filePath = fileMatch[1];
|
|
112
|
+
line = parseInt(fileMatch[2], 10);
|
|
113
|
+
column = parseInt(fileMatch[3], 10);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return new TemplateError(message, filePath, line, column);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Enhances a generic error with template-specific context.
|
|
122
|
+
*/
|
|
123
|
+
export function createTemplateError(error, templatePath, _line, _column) {
|
|
124
|
+
if (error instanceof TemplateError) {
|
|
125
|
+
return error;
|
|
126
|
+
}
|
|
127
|
+
return parseEtaError(error, templatePath);
|
|
128
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Eta templates
|
|
3
|
+
*/
|
|
4
|
+
type PropValueArg = string | number | boolean | null | undefined | Record<string, boolean | string | number | null | undefined> | PropValueArg[];
|
|
5
|
+
/**
|
|
6
|
+
* Builds a property value from various inputs, similar to classnames but for any property.
|
|
7
|
+
* Accepts strings, arrays, and objects. Filters out falsy values.
|
|
8
|
+
*
|
|
9
|
+
* @param args - Values to combine
|
|
10
|
+
* @returns Combined property value string
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* propValue('class1', 'class2') // 'class1 class2'
|
|
14
|
+
* propValue(['class1', 'class2']) // 'class1 class2'
|
|
15
|
+
* propValue({ 'class1': true, 'class2': false }) // 'class1'
|
|
16
|
+
* propValue('class1', ['class2', 'class3'], { 'class4': true }) // 'class1 class2 class3 class4'
|
|
17
|
+
*/
|
|
18
|
+
export declare function propValue(...args: PropValueArg[]): string;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=template-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-utils.d.ts","sourceRoot":"","sources":["../../../src/core/utils/template-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,KAAK,YAAY,GACb,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5D,YAAY,EAAE,CAAC;AAEnB;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,GAAG,IAAI,EAAE,YAAY,EAAE,GAAG,MAAM,CAwBzD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Eta templates
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Builds a property value from various inputs, similar to classnames but for any property.
|
|
6
|
+
* Accepts strings, arrays, and objects. Filters out falsy values.
|
|
7
|
+
*
|
|
8
|
+
* @param args - Values to combine
|
|
9
|
+
* @returns Combined property value string
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* propValue('class1', 'class2') // 'class1 class2'
|
|
13
|
+
* propValue(['class1', 'class2']) // 'class1 class2'
|
|
14
|
+
* propValue({ 'class1': true, 'class2': false }) // 'class1'
|
|
15
|
+
* propValue('class1', ['class2', 'class3'], { 'class4': true }) // 'class1 class2 class3 class4'
|
|
16
|
+
*/
|
|
17
|
+
export function propValue(...args) {
|
|
18
|
+
const classes = [];
|
|
19
|
+
for (const arg of args) {
|
|
20
|
+
if (!arg)
|
|
21
|
+
continue;
|
|
22
|
+
if (typeof arg === 'string' || typeof arg === 'number') {
|
|
23
|
+
classes.push(String(arg));
|
|
24
|
+
}
|
|
25
|
+
else if (Array.isArray(arg)) {
|
|
26
|
+
classes.push(...arg
|
|
27
|
+
.filter((item) => item && (typeof item === 'string' || typeof item === 'number'))
|
|
28
|
+
.map(String));
|
|
29
|
+
}
|
|
30
|
+
else if (typeof arg === 'object') {
|
|
31
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
32
|
+
if (value) {
|
|
33
|
+
classes.push(key);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return classes.join(' ');
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/core/utils/version.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAWxC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
/**
|
|
5
|
+
* Gets the current version of Stati core from package.json
|
|
6
|
+
* @returns The version string
|
|
7
|
+
*/
|
|
8
|
+
export function getStatiVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
const packageJsonPath = join(__dirname, '../../package.json');
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
14
|
+
return packageJson.version;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Fallback for cases where package.json can't be read
|
|
18
|
+
return '1.0.0';
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,QAEhE;AAED,wBAAgB,MAAM,WAErB"}
|
package/dist/env.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export { createDevServer } from './core/dev.js';
|
|
|
29
29
|
export { createPreviewServer } from './core/preview.js';
|
|
30
30
|
export { loadConfig } from './config/loader.js';
|
|
31
31
|
export { invalidate } from './core/invalidate.js';
|
|
32
|
+
export { setEnv, getEnv } from './env.js';
|
|
32
33
|
import type { StatiConfig } from './types/index.js';
|
|
33
34
|
/**
|
|
34
35
|
* Helper function for defining Stati configuration with TypeScript IntelliSense.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAE7D"}
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export { createDevServer } from './core/dev.js';
|
|
|
24
24
|
export { createPreviewServer } from './core/preview.js';
|
|
25
25
|
export { loadConfig } from './config/loader.js';
|
|
26
26
|
export { invalidate } from './core/invalidate.js';
|
|
27
|
+
export { setEnv, getEnv } from './env.js';
|
|
27
28
|
/**
|
|
28
29
|
* Helper function for defining Stati configuration with TypeScript IntelliSense.
|
|
29
30
|
* Provides type checking and autocompletion for configuration options.
|