@wireweave/core 1.0.0-beta.20260107130839 → 1.0.0-beta.20260107133417

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.
@@ -1,214 +0,0 @@
1
- /**
2
- * Parser module for wireweave
3
- *
4
- * Provides parse function to convert wireframe DSL to AST
5
- */
6
-
7
- import type { WireframeDocument, SourceLocation } from '../ast/types';
8
- // @ts-expect-error - generated parser has no type declarations
9
- import { parse as peggyParse } from './generated-parser.js';
10
-
11
- /**
12
- * Parse options
13
- */
14
- export interface ParseOptions {
15
- /** Starting rule (defaults to 'Document') */
16
- startRule?: string;
17
- /** Include source location in error messages */
18
- includeLocation?: boolean;
19
- }
20
-
21
- /**
22
- * Expected token description from Peggy
23
- */
24
- export interface ExpectedToken {
25
- type: string;
26
- description?: string;
27
- text?: string;
28
- }
29
-
30
- /**
31
- * Parse error with location information
32
- */
33
- export interface ParseError extends Error {
34
- name: 'ParseError';
35
- message: string;
36
- location: SourceLocation;
37
- expected: ExpectedToken[];
38
- found: string | null;
39
- }
40
-
41
- /**
42
- * Peggy error structure
43
- */
44
- interface PeggyError {
45
- message: string;
46
- location: SourceLocation;
47
- expected: ExpectedToken[];
48
- found: string | null;
49
- }
50
-
51
- /**
52
- * Parse result for tryParse
53
- */
54
- export interface ParseResult {
55
- success: boolean;
56
- document: WireframeDocument | null;
57
- errors: ParseErrorInfo[];
58
- }
59
-
60
- /**
61
- * Simplified error info
62
- */
63
- export interface ParseErrorInfo {
64
- message: string;
65
- location: {
66
- line: number;
67
- column: number;
68
- offset?: number;
69
- } | null;
70
- expected?: string[];
71
- found?: string | null;
72
- }
73
-
74
- /**
75
- * Parse wireframe DSL source code into AST
76
- *
77
- * @param source - wireweave source code
78
- * @param options - Parse options
79
- * @returns Parsed AST document
80
- * @throws {ParseError} When source contains syntax errors
81
- */
82
- export function parse(source: string, options?: ParseOptions): WireframeDocument {
83
- try {
84
- return peggyParse(source, options) as WireframeDocument;
85
- } catch (error: unknown) {
86
- throw enhanceError(error);
87
- }
88
- }
89
-
90
- /**
91
- * Parse wireframe DSL with error recovery
92
- *
93
- * @param source - wireweave source code
94
- * @param options - Parse options
95
- * @returns Parse result with AST or errors
96
- */
97
- export function tryParse(source: string, options?: ParseOptions): ParseResult {
98
- try {
99
- const document = parse(source, options);
100
- return { success: true, document, errors: [] };
101
- } catch (error) {
102
- const parseError = error as ParseError;
103
- return {
104
- success: false,
105
- document: null,
106
- errors: [
107
- {
108
- message: parseError.message,
109
- location: parseError.location
110
- ? {
111
- line: parseError.location.start.line,
112
- column: parseError.location.start.column,
113
- offset: parseError.location.start.offset,
114
- }
115
- : null,
116
- expected: parseError.expected?.map((e) => e.description || e.text || String(e)),
117
- found: parseError.found,
118
- },
119
- ],
120
- };
121
- }
122
- }
123
-
124
- /**
125
- * Enhance Peggy error with better formatting
126
- */
127
- function enhanceError(error: unknown): ParseError {
128
- if (error && typeof error === 'object' && 'location' in error) {
129
- const pegError = error as PeggyError;
130
- const enhanced = new Error(formatErrorMessage(pegError)) as ParseError;
131
- enhanced.name = 'ParseError';
132
- enhanced.location = pegError.location;
133
- enhanced.expected = pegError.expected || [];
134
- enhanced.found = pegError.found;
135
- return enhanced;
136
- }
137
-
138
- // Re-throw non-Peggy errors
139
- throw error;
140
- }
141
-
142
- /**
143
- * Format error message for better readability
144
- */
145
- function formatErrorMessage(error: PeggyError): string {
146
- const { location, expected, found } = error;
147
- const line = location?.start?.line ?? '?';
148
- const column = location?.start?.column ?? '?';
149
-
150
- // Format expected tokens
151
- let expectedDesc = 'something';
152
- if (expected && expected.length > 0) {
153
- const descriptions = expected
154
- .map((e) => e.description || e.text || String(e))
155
- .filter((d, i, arr) => arr.indexOf(d) === i) // unique
156
- .slice(0, 5); // limit to 5
157
-
158
- if (descriptions.length === 1) {
159
- expectedDesc = descriptions[0];
160
- } else if (descriptions.length === 2) {
161
- expectedDesc = `${descriptions[0]} or ${descriptions[1]}`;
162
- } else {
163
- const last = descriptions.pop();
164
- expectedDesc = `${descriptions.join(', ')}, or ${last}`;
165
- }
166
-
167
- if (expected.length > 5) {
168
- expectedDesc += ` (and ${expected.length - 5} more)`;
169
- }
170
- }
171
-
172
- // Format found token
173
- const foundDesc = found === null ? 'end of input' : `"${escapeString(found)}"`;
174
-
175
- return `Syntax error at line ${line}, column ${column}: Expected ${expectedDesc} but found ${foundDesc}`;
176
- }
177
-
178
- /**
179
- * Escape special characters in string for display
180
- */
181
- function escapeString(str: string): string {
182
- return str
183
- .replace(/\\/g, '\\\\')
184
- .replace(/\n/g, '\\n')
185
- .replace(/\r/g, '\\r')
186
- .replace(/\t/g, '\\t')
187
- .replace(/"/g, '\\"');
188
- }
189
-
190
- /**
191
- * Validate source code without throwing
192
- *
193
- * @param source - wireweave source code
194
- * @returns true if valid, false otherwise
195
- */
196
- export function isValid(source: string): boolean {
197
- try {
198
- parse(source);
199
- return true;
200
- } catch {
201
- return false;
202
- }
203
- }
204
-
205
- /**
206
- * Get syntax errors from source code
207
- *
208
- * @param source - wireweave source code
209
- * @returns Array of error info, empty if valid
210
- */
211
- export function getErrors(source: string): ParseErrorInfo[] {
212
- const result = tryParse(source);
213
- return result.errors;
214
- }
@@ -1,186 +0,0 @@
1
- /**
2
- * Base HTML Renderer for wireweave
3
- *
4
- * Provides abstract base class for HTML rendering with theme support
5
- */
6
-
7
- import type { WireframeDocument, AnyNode } from '../../ast/types';
8
- import type { RenderOptions, RenderResult, RenderContext, ThemeConfig } from '../types';
9
- import { defaultTheme, darkTheme } from '../types';
10
- import { generateStyles } from '../styles';
11
-
12
- /**
13
- * Default render options
14
- */
15
- const DEFAULT_OPTIONS: Required<RenderOptions> = {
16
- theme: 'light',
17
- scale: 1,
18
- includeStyles: true,
19
- minify: false,
20
- classPrefix: 'wf',
21
- };
22
-
23
- /**
24
- * Abstract base renderer class
25
- *
26
- * Provides core infrastructure for HTML rendering:
27
- * - Theme management
28
- * - Indentation and formatting
29
- * - Depth tracking for nested elements
30
- */
31
- export abstract class BaseRenderer {
32
- protected context: RenderContext;
33
-
34
- constructor(options: RenderOptions = {}) {
35
- const resolvedOptions: Required<RenderOptions> = {
36
- ...DEFAULT_OPTIONS,
37
- ...options,
38
- };
39
-
40
- this.context = {
41
- options: resolvedOptions,
42
- theme: this.buildTheme(resolvedOptions),
43
- depth: 0,
44
- };
45
- }
46
-
47
- /**
48
- * Build theme configuration based on options
49
- */
50
- protected buildTheme(options: Required<RenderOptions>): ThemeConfig {
51
- return options.theme === 'dark' ? { ...darkTheme } : { ...defaultTheme };
52
- }
53
-
54
- /**
55
- * Render a wireframe document to HTML and CSS
56
- */
57
- render(document: WireframeDocument): RenderResult {
58
- const html = this.renderDocument(document);
59
- const css = this.context.options.includeStyles
60
- ? generateStyles(this.context.theme, this.context.options.classPrefix)
61
- : '';
62
-
63
- return {
64
- html: this.context.options.minify ? this.minifyHtml(html) : html,
65
- css: this.context.options.minify ? this.minifyCss(css) : css,
66
- };
67
- }
68
-
69
- /**
70
- * Render a complete wireframe document
71
- */
72
- protected renderDocument(document: WireframeDocument): string {
73
- const pages = document.children
74
- .map((page) => this.renderPage(page))
75
- .join(this.context.options.minify ? '' : '\n');
76
-
77
- return pages;
78
- }
79
-
80
- /**
81
- * Render a page node (to be implemented by subclasses)
82
- */
83
- protected abstract renderPage(node: AnyNode): string;
84
-
85
- /**
86
- * Render any AST node (to be implemented by subclasses)
87
- */
88
- protected abstract renderNode(node: AnyNode): string;
89
-
90
- /**
91
- * Get the CSS class prefix
92
- */
93
- protected get prefix(): string {
94
- return this.context.options.classPrefix;
95
- }
96
-
97
- /**
98
- * Add indentation based on current depth
99
- */
100
- protected indent(content: string): string {
101
- if (this.context.options.minify) {
102
- return content;
103
- }
104
-
105
- const spaces = ' '.repeat(this.context.depth);
106
- return content
107
- .split('\n')
108
- .map((line) => (line.trim() ? spaces + line : line))
109
- .join('\n');
110
- }
111
-
112
- /**
113
- * Execute a function with increased depth
114
- */
115
- protected withDepth<T>(fn: () => T): T {
116
- this.context.depth++;
117
- const result = fn();
118
- this.context.depth--;
119
- return result;
120
- }
121
-
122
- /**
123
- * Escape HTML special characters
124
- */
125
- protected escapeHtml(text: string): string {
126
- const escapeMap: Record<string, string> = {
127
- '&': '&amp;',
128
- '<': '&lt;',
129
- '>': '&gt;',
130
- '"': '&quot;',
131
- "'": '&#39;',
132
- };
133
-
134
- return text.replace(/[&<>"']/g, (char) => escapeMap[char] || char);
135
- }
136
-
137
- /**
138
- * Build a CSS class string from an array of class names
139
- */
140
- protected buildClassString(classes: (string | undefined | false)[]): string {
141
- return classes.filter(Boolean).join(' ');
142
- }
143
-
144
- /**
145
- * Build HTML attributes string
146
- */
147
- protected buildAttrsString(attrs: Record<string, string | undefined | boolean>): string {
148
- const parts: string[] = [];
149
-
150
- for (const [key, value] of Object.entries(attrs)) {
151
- if (value === undefined || value === false) {
152
- continue;
153
- }
154
-
155
- if (value === true) {
156
- parts.push(key);
157
- } else {
158
- parts.push(`${key}="${this.escapeHtml(value)}"`);
159
- }
160
- }
161
-
162
- return parts.length > 0 ? ' ' + parts.join(' ') : '';
163
- }
164
-
165
- /**
166
- * Simple HTML minification
167
- */
168
- private minifyHtml(html: string): string {
169
- return html
170
- .replace(/\n\s*/g, '')
171
- .replace(/>\s+</g, '><')
172
- .trim();
173
- }
174
-
175
- /**
176
- * Simple CSS minification
177
- */
178
- private minifyCss(css: string): string {
179
- return css
180
- .replace(/\/\*[\s\S]*?\*\//g, '')
181
- .replace(/\s+/g, ' ')
182
- .replace(/\s*([{}:;,])\s*/g, '$1')
183
- .replace(/;}/g, '}')
184
- .trim();
185
- }
186
- }