commit 47f67eea8ce9a595b94c0e9b68c3de48bff93d8e Author: obvTiger Date: Tue Jan 21 14:00:09 2025 +0100 release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63505c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +dist/ +node_modules/ +package-lock.json +bun.lockb \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..644b3c8 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# Blueprint 🎨 - Modern Web UI Language + +A modern programming language, which feels like SwiftUI, but for web development. + +## Quick Start 🚀 + +```bash +# Clone and setup +git clone https://github.com/epilogueteam/blueprint.git +cd blueprint +npm install + +# Development +npm run dev # Starts server at http://localhost:3000 + +# Production +npm run build # Generates production files +``` + +## Why Blueprint? ✨ + +- 🎯 SwiftUI-like syntax for web development +- ⚡️ Optimized performance & real-time updates +- 🌐 Cross-platform responsive design +- 💝 Free & open-source +- 🔄 Live reload development + +## Development Guide 💻 + +1. After installation, access your project at `http://localhost:3000` +2. Make changes and see them instantly with live reload +3. For production, build optimized files using `npm run build` +4. Deploy built files to your preferred hosting platform + diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..9b6c28a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,142 @@ +# Blueprint Documentation + +Blueprint is a modern, declarative UI framework for building beautiful web interfaces. It provides a simple, intuitive syntax for creating responsive, dark-themed web applications with consistent styling and behavior. + +## Core Features + +- **Declarative Syntax**: Write UI components using a clean, intuitive syntax +- **Dark Theme**: Beautiful dark theme with consistent styling +- **Responsive Design**: Built-in responsive design system +- **Component-Based**: Rich set of reusable components +- **Type-Safe**: Catch errors before they reach the browser +- **Custom Properties**: Direct control over styling when needed +- **Live Preview**: Changes appear instantly in your browser + +## Documentation Structure + +1. [Getting Started](getting-started.md) + - Installation + - Basic Usage + - Project Structure + - Property Types + - Page Configuration + - Error Handling + - Best Practices + +2. [Components](components.md) + - Layout Components (Section, Grid, Horizontal, Vertical) + - Typography (Title, Text) + - Navigation (Navbar, Links) + - Form Elements (Input, Textarea, Select, Checkbox, Radio, Switch) + - Interactive Components (Button, Card, Badge, Alert, Tooltip) + - Container Components (List, Table, Progress, Slider) + +3. [Styling](styling.md) + - Layout Properties + - Typography Properties + - Component Styles + - Interactive States + - Responsive Design + - Custom Properties + - Theme Variables + - Best Practices + +4. [Examples](examples.md) + - Basic Examples + - Layout Examples + - Form Examples + - Navigation Examples + - Complete Page Examples + +## Quick Start + +```blueprint +page { + title { "My First Blueprint Page" } + description { "A simple Blueprint page example" } + meta-viewport { "width=device-width, initial-scale=1" } +} + +navbar { + horizontal(spaced) { + text(bold) { "My App" } + links { + link(href:/) { "Home" } + link(href:/about) { "About" } + } + } +} + +section(wide, centered) { + vertical(gap:2) { + title(huge) { "Welcome to Blueprint" } + text(subtle) { "Start building beautiful UIs with Blueprint" } + + horizontal(centered, gap:2) { + button { "Get Started" } + button-light { "Learn More" } + } + } +} +``` + +## Key Concepts + +1. **Elements** + - Basic building blocks of Blueprint + - Each element maps to an HTML tag + - Elements can have properties and children + - Elements follow semantic naming + +2. **Properties** + - Flag properties (e.g., `centered`, `bold`) + - Key-value properties (e.g., `type:email`) + - Numeric properties (e.g., `width:80`) + - Color properties (e.g., `color:#ff0000`) + +3. **Styling** + - Consistent dark theme + - Built-in responsive design + - Direct style properties + - Theme variables + - Interactive states + +4. **Components** + - Layout components + - Form elements + - Interactive components + - Container components + - Typography elements + +## Best Practices + +1. **Organization** + - Group related elements + - Use consistent spacing + - Keep files focused + - Split into components + +2. **Styling** + - Use predefined properties + - Maintain consistency + - Leverage built-in features + - Custom styles sparingly + +3. **Performance** + - Small, focused files + - Optimize assets + - Use responsive features + - Minimize custom styles + +4. **Accessibility** + - Semantic elements + - Color contrast + - Focus states + - Screen reader support + +## Need Help? + +- Check the [examples](examples.md) for common patterns +- Read the [components guide](components.md) for detailed documentation +- Learn about styling in the [styling guide](styling.md) +- Start with the [getting started guide](getting-started.md) for basics \ No newline at end of file diff --git a/docs/components.md b/docs/components.md new file mode 100644 index 0000000..c8c9843 --- /dev/null +++ b/docs/components.md @@ -0,0 +1,365 @@ +# Blueprint Components + +Blueprint provides a rich set of components for building modern web interfaces. Each component is designed to be responsive, accessible, and consistent with the dark theme. + +## Layout Components + +### Section +Container for page sections: +```blueprint +section(wide, centered) { + // Content +} +``` +Properties: +- `wide`: Full width with max-width constraint (1200px) +- `centered`: Center content horizontally and vertically +- `alternate`: Alternate background color +- `padding`: Custom padding in pixels +- `margin`: Custom margin in pixels + +### Grid +Responsive grid layout: +```blueprint +grid(columns:3) { + // Grid items +} +``` +Properties: +- `columns`: Number of columns (default: auto-fit) +- `responsive`: Enable responsive behavior +- `gap`: Custom gap size between items +- `width`: Custom width in percentage + +### Horizontal +Horizontal flex container: +```blueprint +horizontal(centered, spaced) { + // Horizontal items +} +``` +Properties: +- `centered`: Center items vertically +- `spaced`: Space between items +- `gap`: Custom gap size +- `width`: Custom width in percentage +- `responsive`: Wrap items on small screens + +### Vertical +Vertical flex container: +```blueprint +vertical(centered) { + // Vertical items +} +``` +Properties: +- `centered`: Center items horizontally +- `spaced`: Space between items +- `gap`: Custom gap size +- `width`: Custom width in percentage + +## Typography + +### Title +Page or section titles: +```blueprint +title(huge) { "Main Title" } +title(large) { "Section Title" } +``` +Properties: +- `huge`: Very large size (4rem) +- `large`: Large size (2rem) +- `bold`: Bold weight +- `centered`: Center align +- `color`: Custom text color + +### Text +Regular text content: +```blueprint +text(large) { "Large text" } +text(subtle) { "Subtle text" } +``` +Properties: +- `large`: Larger size +- `small`: Smaller size (0.875rem) +- `subtle`: Muted color +- `bold`: Bold weight +- `color`: Custom text color + +## Navigation + +### Navbar +Fixed navigation bar: +```blueprint +navbar { + horizontal { + text(bold) { "Brand" } + links { + link(href:home) { "Home" } + link(href:about) { "About" } + } + } +} +``` +Properties: +- `sticky`: Fixed to top +- `transparent`: Transparent background +- `backgroundColor`: Custom background color + +### Links +Navigation link group: +```blueprint +links { + link(href:page1) { "Link 1" } + link(href:page2) { "Link 2" } +} +``` +Properties: +- `spaced`: Add spacing between links +- `vertical`: Vertical orientation +- `gap`: Custom gap size + +### Link +Individual link: +```blueprint +link(href:page, text:"Click here") { } +link(href:https://example.com) { "External Link" } +``` +Properties: +- `href`: Target URL or page +- `text`: Link text (optional) +- `external`: Open in new tab (automatic for http/https URLs) +- `color`: Custom text color + +## Interactive Components + +### Button +Various button styles: +```blueprint +button { "Primary" } +button-secondary { "Secondary" } +button-light { "Light" } +button-compact { "Compact" } +``` +Properties: +- `disabled`: Disabled state +- `width`: Custom width in percentage +- `backgroundColor`: Custom background color +- `color`: Custom text color + +### Card +Content container with hover effect: +```blueprint +card { + title { "Card Title" } + text { "Card content" } + button { "Action" } +} +``` +Properties: +- `raised`: Add shadow and hover effect +- `width`: Custom width in percentage +- `padding`: Custom padding in pixels +- `backgroundColor`: Custom background color + +### Badge +Status indicators: +```blueprint +badge { "New" } +badge(color:blue) { "Status" } +``` +Properties: +- `color`: Custom badge color +- `backgroundColor`: Custom background color +- `width`: Custom width in percentage + +### Alert +Notification messages: +```blueprint +alert(type:info) { "Information message" } +``` +Properties: +- `type`: info, success, warning, error +- `backgroundColor`: Custom background color +- `color`: Custom text color +- `width`: Custom width in percentage + +### Tooltip +Hover tooltips: +```blueprint +tooltip(text:"More info") { + text { "Hover me" } +} +``` +Properties: +- `text`: Tooltip text +- `position`: top, right, bottom, left +- `backgroundColor`: Custom background color +- `color`: Custom text color + +## Form Elements + +### Input +Text input field: +```blueprint +input(placeholder:"Type here") { } +``` +Properties: +- `placeholder`: Placeholder text +- `type`: Input type (text, email, password, etc.) +- `required`: Required field +- `disabled`: Disabled state +- `width`: Custom width in percentage + +### Textarea +Multi-line text input: +```blueprint +textarea(placeholder:"Enter message") { } +``` +Properties: +- `placeholder`: Placeholder text +- `rows`: Number of visible rows +- `required`: Required field +- `width`: Custom width in percentage + +### Select +Dropdown selection: +```blueprint +select { + option { "Option 1" } + option { "Option 2" } +} +``` +Properties: +- `placeholder`: Placeholder text +- `required`: Required field +- `disabled`: Disabled state +- `width`: Custom width in percentage + +### Checkbox +Checkbox input: +```blueprint +horizontal { + checkbox { } + text { "Accept terms" } +} +``` +Properties: +- `checked`: Default checked state +- `required`: Required field +- `disabled`: Disabled state +- `width`: Custom width in percentage + +### Radio +Radio button input: +```blueprint +vertical { + horizontal { + radio(name:"choice") { } + text { "Option 1" } + } + horizontal { + radio(name:"choice") { } + text { "Option 2" } + } +} +``` +Properties: +- `name`: Group name +- `checked`: Default checked state +- `disabled`: Disabled state +- `width`: Custom width in percentage + +### Switch +Toggle switch: +```blueprint +horizontal { + switch { } + text { "Enable feature" } +} +``` +Properties: +- `checked`: Default checked state +- `disabled`: Disabled state +- `width`: Custom width in percentage + +## Container Components + +### List +Ordered or unordered lists: +```blueprint +list { + text { "Item 1" } + text { "Item 2" } +} +``` +Properties: +- `ordered`: Use ordered list +- `bullet`: Show bullets +- `spaced`: Add spacing +- `width`: Custom width in percentage + +### Table +Data tables: +```blueprint +table { + row { + cell { "Header 1" } + cell { "Header 2" } + } + row { + cell { "Data 1" } + cell { "Data 2" } + } +} +``` +Properties: +- `striped`: Alternate row colors +- `bordered`: Add borders +- `compact`: Reduced padding +- `width`: Custom width in percentage + +### Progress +Progress indicators: +```blueprint +progress(value:75, max:100) { } +``` +Properties: +- `value`: Current value +- `max`: Maximum value +- `indeterminate`: Loading state +- `width`: Custom width in percentage + +### Slider +Range input: +```blueprint +slider(min:0, max:100, value:50) { } +``` +Properties: +- `min`: Minimum value +- `max`: Maximum value +- `step`: Step increment +- `disabled`: Disabled state +- `width`: Custom width in percentage + +### Media +Images and videos with responsive behavior: +```blueprint +media(src:/path/to/image.jpg) { "Image description" } +media(src:https://example.com/video.mp4, type:video) { "Video description" } +``` +Properties: +- `src`: URL or path to the media file (required) +- `type`: Media type (`img` or `video`, defaults to `img`) +- `width`: Custom width in percentage +- `height`: Custom height in percentage +- `padding`: Custom padding in pixels +- `margin`: Custom margin in pixels + +The media component automatically: +- Scales images/videos responsively (max-width: 100%) +- Maintains aspect ratio (height: auto) +- Adds rounded corners +- Includes a subtle hover effect +- Uses the content as alt text for images +- Adds video controls when type is video \ No newline at end of file diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 0000000..27e4cc4 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,375 @@ +# Blueprint Examples + +This guide provides comprehensive examples of common UI patterns and layouts using Blueprint. + +## Basic Examples + +### Page Setup +```blueprint +page { + title { "My Blueprint Page" } + description { "A comprehensive example page" } + keywords { "blueprint, example, ui" } + author { "Blueprint Team" } +} + +navbar { + horizontal { + text(bold) { "My App" } + links { + link(href:home) { "Home" } + link(href:about) { "About" } + link(href:contact) { "Contact" } + } + } +} + +section(wide, centered) { + title(huge) { "Welcome" } + text(subtle) { "Start building beautiful UIs" } +} +``` + +### Basic Card +```blueprint +card { + title { "Simple Card" } + text { "This is a basic card with some content." } + button { "Learn More" } +} +``` + +### Alert Messages +```blueprint +vertical(gap:2) { + alert(type:info) { "This is an information message" } + alert(type:success) { "Operation completed successfully" } + alert(type:warning) { "Please review your input" } + alert(type:error) { "An error occurred" } +} +``` + +## Layout Examples + +### Grid Layout +```blueprint +section(wide) { + title { "Our Features" } + + grid(columns:3) { + card { + title { "Feature 1" } + text { "Description of feature 1" } + button-secondary { "Learn More" } + } + card { + title { "Feature 2" } + text { "Description of feature 2" } + button-secondary { "Learn More" } + } + card { + title { "Feature 3" } + text { "Description of feature 3" } + button-secondary { "Learn More" } + } + } +} +``` + +### Responsive Layout +```blueprint +section(wide) { + horizontal(mobile-stack) { + vertical(width:40) { + title { "Left Column" } + text { "This column takes 40% width on desktop" } + } + vertical(width:60) { + title { "Right Column" } + text { "This column takes 60% width on desktop" } + } + } +} +``` + +### Nested Layout +```blueprint +section(wide) { + vertical(centered) { + title(huge) { "Nested Layout" } + + horizontal(centered, gap:4) { + vertical(centered) { + title { "Column 1" } + text { "Content" } + } + vertical(centered) { + title { "Column 2" } + text { "Content" } + } + } + } +} +``` + +## Form Examples + +### Login Form +```blueprint +section(wide, centered) { + card { + title { "Login" } + vertical(gap:2) { + vertical { + text(bold) { "Email" } + input(type:email, placeholder:"Enter your email") { } + } + vertical { + text(bold) { "Password" } + input(type:password, placeholder:"Enter your password") { } + } + horizontal { + checkbox { } + text { "Remember me" } + } + button { "Sign In" } + text(small, centered) { "Forgot password?" } + } + } +} +``` + +### Contact Form +```blueprint +section(wide) { + card { + title { "Contact Us" } + vertical(gap:2) { + horizontal(gap:2) { + vertical { + text(bold) { "First Name" } + input(placeholder:"John") { } + } + vertical { + text(bold) { "Last Name" } + input(placeholder:"Doe") { } + } + } + vertical { + text(bold) { "Email" } + input(type:email, placeholder:"john@example.com") { } + } + vertical { + text(bold) { "Message" } + textarea(placeholder:"Your message here...") { } + } + button { "Send Message" } + } + } +} +``` + +### Settings Form +```blueprint +section(wide) { + card { + title { "Settings" } + vertical(gap:3) { + horizontal { + vertical(width:70) { + title(small) { "Notifications" } + text(subtle) { "Manage your notification preferences" } + } + switch { } + } + horizontal { + vertical(width:70) { + title(small) { "Dark Mode" } + text(subtle) { "Toggle dark/light theme" } + } + switch { } + } + horizontal { + vertical(width:70) { + title(small) { "Email Updates" } + text(subtle) { "Receive email updates about your account" } + } + switch { } + } + } + } +} +``` + +## Navigation Examples + +### Complex Navbar +```blueprint +navbar { + horizontal { + horizontal(gap:2) { + text(bold) { "Logo" } + links { + link(href:home) { "Home" } + link(href:products) { "Products" } + link(href:pricing) { "Pricing" } + link(href:about) { "About" } + } + } + horizontal(gap:2) { + button-light { "Sign In" } + button { "Get Started" } + } + } +} +``` + +### Sidebar Navigation +```blueprint +horizontal { + vertical(width:20) { + title { "Dashboard" } + links(vertical) { + link(href:home) { "Home" } + link(href:profile) { "Profile" } + link(href:settings) { "Settings" } + link(href:help) { "Help" } + } + } + vertical(width:80) { + title { "Main Content" } + text { "Your content here" } + } +} +``` + +### Breadcrumb Navigation +```blueprint +horizontal(gap:1) { + link(href:home) { "Home" } + text { ">" } + link(href:products) { "Products" } + text { ">" } + text(bold) { "Current Page" } +} +``` + +## Complete Page Examples + +### Landing Page +```blueprint +page { + title { "Blueprint - Modern UI Framework" } + description { "Build beautiful web interfaces with Blueprint" } +} + +navbar { + horizontal { + text(bold) { "Blueprint" } + links { + link(href:features) { "Features" } + link(href:docs) { "Docs" } + link(href:pricing) { "Pricing" } + button { "Get Started" } + } + } +} + +section(wide, centered) { + vertical(centered) { + title(huge) { "Build Beautiful UIs" } + text(large, subtle) { "Create modern web interfaces with ease" } + horizontal(centered, gap:2) { + button { "Get Started" } + button-light { "Learn More" } + } + } +} + +section(wide) { + grid(columns:3) { + card { + title { "Easy to Use" } + text { "Simple, declarative syntax for building UIs" } + button-secondary { "Learn More" } + } + card { + title { "Modern Design" } + text { "Beautiful dark theme with consistent styling" } + button-secondary { "View Examples" } + } + card { + title { "Responsive" } + text { "Looks great on all devices out of the box" } + button-secondary { "See Details" } + } + } +} +``` + +### Dashboard Page +```blueprint +page { + title { "Dashboard - My App" } +} + +navbar { + horizontal { + text(bold) { "Dashboard" } + horizontal { + text { "Welcome back, " } + text(bold) { "John" } + } + } +} + +section(wide) { + grid(columns:4) { + card { + title { "Total Users" } + text(huge) { "1,234" } + text(subtle) { "+12% this month" } + } + card { + title { "Revenue" } + text(huge) { "$5,678" } + text(subtle) { "+8% this month" } + } + card { + title { "Active Users" } + text(huge) { "892" } + text(subtle) { "Currently online" } + } + card { + title { "Conversion" } + text(huge) { "3.2%" } + text(subtle) { "+0.8% this month" } + } + } + + horizontal(gap:4) { + vertical(width:60) { + card { + title { "Recent Activity" } + list { + text { "User signup: John Doe" } + text { "New order: #12345" } + text { "Payment received: $99" } + } + } + } + vertical(width:40) { + card { + title { "Quick Actions" } + vertical(gap:2) { + button { "Create User" } + button-secondary { "View Reports" } + button-light { "Export Data" } + } + } + } + } +} +``` + +These examples demonstrate common UI patterns and how to implement them using Blueprint. Use them as a starting point for your own projects and customize them to match your needs. \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..e9935b0 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,213 @@ +# Getting Started with Blueprint + +## Installation + +1. Clone the repository: +```bash +git clone https://github.com/yourusername/blueprint.git +cd blueprint +``` + +2. Install dependencies: +```bash +npm install +``` + +3. Create your first Blueprint file: +```bash +mkdir src +touch src/index.bp +``` + +## Basic Usage + +Blueprint uses a declarative syntax to define UI components. Each file with a `.bp` extension will be compiled into HTML and CSS. + +### Basic Structure + +A Blueprint file consists of elements, which can have properties and children. Properties can be flags or key-value pairs: + +```blueprint +element(flag1, key:value) { + child-element { + // Content + } +} +``` + +### Property Types + +Blueprint supports several types of properties: + +1. **Flag Properties** + ```blueprint + button(bold, centered) { "Text" } + ``` + +2. **Key-Value Properties** + ```blueprint + input(type:email, placeholder:"Enter email") + ``` + +3. **Numeric Properties** + ```blueprint + section(width:80, padding:20) + ``` + +4. **Color Properties** + ```blueprint + text(color:#ff0000) { "Red text" } + ``` + +### Page Configuration + +Every Blueprint page can have metadata defined using the `page` element: + +```blueprint +page { + title { "My Page Title" } + description { "Page description for SEO" } + keywords { "keyword1, keyword2, keyword3" } + author { "Author Name" } + meta-viewport { "width=device-width, initial-scale=1" } +} +``` + +Available page metadata: +- `title`: Page title (appears in browser tab) +- `description`: Meta description for SEO +- `keywords`: Meta keywords for SEO +- `author`: Page author +- `meta-*`: Custom meta tags (e.g., meta-viewport, meta-robots) + +### Basic Layout + +A typical page structure: + +```blueprint +page { + title { "My First Page" } + description { "A simple Blueprint page" } + meta-viewport { "width=device-width, initial-scale=1" } +} + +navbar { + horizontal(spaced) { + text(bold) { "My App" } + links { + link(href:/) { "Home" } + link(href:/about) { "About" } + link(href:/contact) { "Contact" } + } + } +} + +section(wide, centered) { + vertical(gap:2) { + title(huge) { "Welcome to Blueprint" } + text(subtle) { "Start building beautiful UIs with Blueprint" } + + horizontal(centered, gap:2) { + button { "Get Started" } + button-light { "Learn More" } + } + } +} + +section(wide) { + grid(columns:3) { + card { + title { "Feature 1" } + text { "Description of feature 1" } + button-secondary { "Learn More" } + } + card { + title { "Feature 2" } + text { "Description of feature 2" } + button-secondary { "Learn More" } + } + card { + title { "Feature 3" } + text { "Description of feature 3" } + button-secondary { "Learn More" } + } + } +} +``` + +## Project Structure + +A typical Blueprint project has the following structure: + +``` +my-blueprint-project/ +├── src/ # Source Blueprint files +│ ├── index.bp # Main page +│ ├── about.bp # About page +│ └── contact.bp # Contact page +├── public/ # Static assets +│ ├── images/ # Image files +│ ├── fonts/ # Font files +│ └── favicon.ico # Favicon +├── dist/ # Generated files (auto-generated) +│ ├── index.html # Compiled HTML +│ ├── index.css # Generated CSS +│ └── ... +└── package.json # Project configuration +``` + +## Error Handling + +Blueprint provides helpful error messages when something goes wrong: + +``` +BlueprintError at line 5, column 10: +Unknown element type: invalid-element +``` + +Common errors include: +- Missing closing braces +- Unknown element types +- Invalid property values +- Unterminated strings +- Missing required properties +- Invalid color values +- Invalid numeric values + +## Best Practices + +1. **Organization** + - Group related elements logically + - Use consistent spacing and indentation + - Keep files focused on a single purpose + - Split large files into components + +2. **Naming** + - Use descriptive names for links and sections + - Follow a consistent naming convention + - Use semantic element names + +3. **Layout** + - Use semantic elements (`section`, `navbar`, etc.) + - Leverage the grid system for responsive layouts + - Use appropriate spacing with `gap` property + - Use `width` and `padding` for fine-tuned control + +4. **Styling** + - Use predefined style properties when possible + - Group related styles together + - Keep styling consistent across pages + - Use custom properties sparingly + +5. **Performance** + - Keep files small and focused + - Use appropriate image formats and sizes + - Minimize custom styles + - Leverage built-in responsive features + +## Next Steps + +- Explore available [components](components.md) +- Learn about [styling](styling.md) +- Check out [examples](examples.md) +- Read about advanced features in the component documentation \ No newline at end of file diff --git a/docs/styling.md b/docs/styling.md new file mode 100644 index 0000000..473a2e6 --- /dev/null +++ b/docs/styling.md @@ -0,0 +1,233 @@ +# Blueprint Styling Guide + +Blueprint provides a comprehensive styling system that ensures consistent, beautiful dark-themed UIs. This guide covers all available styling properties and how to use them effectively. + +## Style Properties + +### Layout Properties + +#### Spacing and Sizing +- `wide`: Full width with max-width constraint (1200px) +- `compact`: Reduced padding (0.75rem) +- `spaced`: Space between items (gap: 1.5rem) +- `gap`: Custom gap size between items +- `width`: Custom width in percentage +- `height`: Custom height in percentage +- `padding`: Custom padding in pixels +- `margin`: Custom margin in pixels + +#### Positioning +- `centered`: Center content horizontally and vertically +- `sticky`: Fixed position at top with blur backdrop +- `fixed`: Fixed position +- `relative`: Relative positioning +- `absolute`: Absolute positioning + +#### Display and Flex +- `horizontal`: Horizontal flex layout with 1.5rem gap +- `vertical`: Vertical flex layout with 1.5rem gap +- `grid`: Grid layout with auto-fit columns +- `responsive`: Enable responsive wrapping +- `hidden`: Hide element +- `visible`: Show element + +### Typography Properties + +#### Text Size +- `huge`: Very large text (clamp(2.5rem, 5vw, 4rem)) +- `large`: Large text (clamp(1.5rem, 3vw, 2rem)) +- `small`: Small text (0.875rem) +- `tiny`: Very small text (0.75rem) + +#### Text Weight +- `bold`: Bold weight (600) +- `light`: Light weight +- `normal`: Normal weight + +#### Text Style +- `italic`: Italic text +- `underline`: Underlined text +- `strike`: Strikethrough text +- `uppercase`: All uppercase +- `lowercase`: All lowercase +- `capitalize`: Capitalize first letter + +#### Text Color +- `subtle`: Muted text color (#8b949e) +- `accent`: Accent color text (#3b82f6) +- `error`: Error color text +- `success`: Success color text +- `warning`: Warning color text +- Custom colors using `color:value` + +### Component Styles + +#### Button Styles +- `prominent`: Primary button style + - Background: #3b82f6 + - Hover: Scale up and glow +- `secondary`: Secondary button style + - Background: #1f2937 + - Hover: Slight raise +- `light`: Light button style + - Background: Transparent + - Border: 1px solid rgba(48, 54, 61, 0.6) +- `compact`: Compact button style + - Padding: 0.75rem + - Border-radius: 12px + +#### Card Styles +- `raised`: Card with hover effect + - Background: #111827 + - Border: 1px solid rgba(48, 54, 61, 0.6) + - Hover: Raise and glow +- `interactive`: Interactive card style + - Hover: Scale and border color change + +#### Input Styles +- `input`: Standard input style + - Background: #111827 + - Border: 1px solid rgba(48, 54, 61, 0.6) + - Focus: Blue glow +- `textarea`: Textarea style + - Min-height: 120px + - Resize: vertical +- `select`: Select input style + - Custom dropdown arrow + - Focus: Blue glow +- `checkbox`: Checkbox style + - Custom checkmark + - Hover: Blue border +- `radio`: Radio button style + - Custom radio dot + - Hover: Blue border +- `switch`: Toggle switch style + - Animated toggle + - Checked: Blue background + +### Interactive States + +#### Hover Effects +```blueprint +button(hover-scale) { "Scale on Hover" } +link(hover-underline) { "Underline on Hover" } +card(hover-raise) { "Raise on Hover" } +``` + +Available hover properties: +- `hover-scale`: Scale up on hover (1.1) +- `hover-raise`: Raise with shadow +- `hover-glow`: Glow effect +- `hover-underline`: Underline on hover +- `hover-fade`: Fade effect + +#### Focus States +```blueprint +input(focus-glow) { } +button(focus-outline) { "Click me" } +``` + +Available focus properties: +- `focus-glow`: Blue glow effect +- `focus-outline`: Blue outline +- `focus-scale`: Scale effect + +#### Active States +```blueprint +button(active-scale) { "Click me" } +link(active-color) { "Click me" } +``` + +Available active properties: +- `active-scale`: Scale down +- `active-color`: Color change +- `active-raise`: Raise effect + +### Responsive Design + +#### Breakpoints +Blueprint automatically handles responsive design, but you can use specific properties: + +```blueprint +section(mobile-stack) { + horizontal(tablet-wrap) { + card(desktop-wide) { } + card(desktop-wide) { } + } +} +``` + +Available responsive properties: +- `mobile-stack`: Stack elements on mobile +- `mobile-hide`: Hide on mobile +- `tablet-wrap`: Wrap on tablet +- `tablet-hide`: Hide on tablet +- `desktop-wide`: Full width on desktop +- `desktop-hide`: Hide on desktop + +#### Grid System +The grid system automatically adjusts based on screen size: + +```blueprint +grid(columns:3, responsive) { + card { } + card { } + card { } +} +``` + +### Custom Properties + +#### Direct Style Properties +You can use these properties directly: +- `width`: Set width in percentage (e.g., width:80) +- `height`: Set height in percentage (e.g., height:50) +- `padding`: Set padding in pixels (e.g., padding:20) +- `margin`: Set margin in pixels (e.g., margin:10) +- `color`: Set text color (e.g., color:#ffffff) +- `backgroundColor`: Set background color (e.g., backgroundColor:#000000) + +### Theme Variables + +Blueprint uses CSS variables for consistent theming: + +```css +:root { + --navbar-height: 4rem; + --primary-color: #3b82f6; + --secondary-color: #1f2937; + --text-color: #e6edf3; + --subtle-color: #8b949e; + --border-color: rgba(48, 54, 61, 0.6); + --background-color: #0d1117; + --hover-color: rgba(255, 255, 255, 0.1); +} +``` + +### Best Practices + +1. **Consistency** + - Use predefined properties when possible + - Maintain consistent spacing + - Follow the color theme + - Use semantic styles + +2. **Responsive Design** + - Test at all breakpoints + - Use relative units + - Consider mobile-first + - Use grid and flex layouts + +3. **Performance** + - Minimize custom styles + - Use system properties + - Avoid deep nesting + - Optimize animations + +4. **Accessibility** + - Maintain color contrast + - Use semantic markup + - Consider focus states + - Test with screen readers +``` + \ No newline at end of file diff --git a/examples/blueprint-home/about.bp b/examples/blueprint-home/about.bp new file mode 100644 index 0000000..331d604 --- /dev/null +++ b/examples/blueprint-home/about.bp @@ -0,0 +1,57 @@ +page(favicon:"/favicon.ico") { + title { "Blueprint - About" } + description { "A modern, declarative UI framework for building beautiful web interfaces" } + keywords { "blueprint, ui, framework, web development" } + author { "Blueprint Team" } +} + +navbar { + horizontal { + link(href:index) { text(bold) { "Blueprint Live" } } + links { + link(href:index) { "Home" } + link(href:components) { "Components" } + link(href:about) { "About" } + link(href:contact) { "Contact" } + } + } +} + +section(wide) { + title { "About Blueprint" } + text(subtle) { "A modern UI compiler with live reload support" } + + vertical { + card { + title { "Our Story" } + text { "Blueprint was created to make UI development faster and more enjoyable. With live reload support, you can see your changes instantly without manual refreshing." } + } + + card { + title { "Features" } + vertical { + horizontal { + badge { "New" } + text { "Live Reload Support" } + } + horizontal { + badge { "✨" } + text { "Modern Dark Theme" } + } + horizontal { + badge { "🚀" } + text { "Fast Development" } + } + } + } + + card { + title { "Get Started" } + text { "Try Blueprint now with our development server:" } + codeblock { + "node dev.js --live --readable" + } + link(text:"Get Help") { "Contact" } + } + } +} \ No newline at end of file diff --git a/examples/blueprint-home/components.bp b/examples/blueprint-home/components.bp new file mode 100644 index 0000000..4867679 --- /dev/null +++ b/examples/blueprint-home/components.bp @@ -0,0 +1,152 @@ +page(favicon:"/favicon.ico") { + title { "Blueprint - Components" } + description { "A modern, declarative UI framework for building beautiful web interfaces" } + keywords { "blueprint, ui, framework, web development" } + author { "Blueprint Team" } +} + +navbar { + horizontal { + link(href:index) { text(bold) { "Blueprint Live" } } + links { + link(href:index) { "Home" } + link(href:components) { "Components" } + link(href:about) { "About" } + link(href:contact) { "Contact" } + } + } +} + +section(wide, centered) { + title(huge) { "Modern UI Components" } + text(large, subtle) { "A showcase of beautiful, dark-themed UI elements" } +} + +section(wide) { + title { "Form Elements" } + + grid(columns:2) { + card { + title { "Text Inputs" } + vertical { + text(subtle) { "Regular input:" } + input { "Type something..." } + + text(subtle) { "Textarea:" } + textarea { "Multiple lines of text..." } + + text(subtle) { "Select dropdown:" } + select { + "Option 1" + "Option 2" + "Option 3" + } + } + } + + card { + title { "Toggle Controls" } + vertical { + horizontal { + checkbox { } + text { "Enable notifications" } + } + + horizontal { + radio { } + text { "Light theme" } + } + + horizontal { + radio { } + text { "Dark theme" } + } + + horizontal { + switch { } + text { "Airplane mode" } + } + } + } + } +} + +section(wide) { + title { "Progress Elements" } + + grid(columns:2) { + card { + title { "Progress Indicators" } + vertical { + text(subtle) { "Download progress:" } + progress(value:75, max:100) { } + + text(subtle) { "Volume control:" } + slider(value:50, min:0, max:100) { } + } + } + + card { + title { "Status Indicators" } + vertical { + horizontal(spaced) { + badge { "New" } + badge { "Updated" } + badge { "Popular" } + } + + alert { "✨ Welcome to the new UI Kit!" } + + horizontal { + tooltip(data-tooltip:"Click to learn more") { + text { "Hover me" } + } + } + } + } + } +} + +section(wide) { + title { "Button Variations" } + + grid(columns:3) { + card { + title { "Primary Actions" } + vertical { + button(prominent) { "Save Changes" } + button { "Cancel" } + } + } + + card { + title { "Button Groups" } + horizontal { + button(prominent) { "Previous" } + button(prominent) { "Next" } + } + } + + card { + title { "Icon Buttons" } + horizontal { + button(compact) { "👍" } + button(compact) { "❤️" } + button(compact) { "🔔" } + } + } + } +} + +section(wide, alternate) { + title(centered) { "Ready to Build?" } + + vertical(centered) { + text(large, subtle) { "Start creating your own modern UI today" } + + horizontal(centered, spaced) { + button(prominent) { "Get Started" } + button(prominent) { "View Documentation" } + } + } +} \ No newline at end of file diff --git a/examples/blueprint-home/contact.bp b/examples/blueprint-home/contact.bp new file mode 100644 index 0000000..ba473e8 --- /dev/null +++ b/examples/blueprint-home/contact.bp @@ -0,0 +1,54 @@ +page(favicon:"/favicon.ico") { + title { "Blueprint - Contact" } + description { "A modern, declarative UI framework for building beautiful web interfaces" } + keywords { "blueprint, ui, framework, web development" } + author { "Blueprint Team" } +} + +navbar { + horizontal { + link(href:index) { text(bold) { "Blueprint Live" } } + links { + link(href:index) { "Home" } + link(href:components) { "Components" } + link(href:about) { "About" } + link(href:contact) { "Contact" } + } + } +} + +section(vertical, centered) { + card(width:100) { + title { "Contact Us" } + text(subtle) { "Get in touch with the Blueprint team" } + + vertical { + text(subtle) { "Name" } + input { "Your name" } + + text(subtle) { "Email" } + input { "you@example.com" } + + text(subtle) { "Message" } + textarea { "Type your message here..." } + + horizontal { + checkbox { } + text { "Subscribe to updates" } + } + + link(href:submit) { button { "Send Message" } } + } + } + + horizontal(centered) { + text(subtle) { "Or connect with us on social media:" } + } + + horizontal(centered) { + link(href:twitter) { button-compact { "𝕏" } } + link(href:facebook) { button-compact { "📘" } } + link(href:linkedin) { button-compact { "💼" } } + link(href:instagram) { button-compact { "📱" } } + } +} \ No newline at end of file diff --git a/examples/blueprint-home/index.bp b/examples/blueprint-home/index.bp new file mode 100644 index 0000000..fbaf101 --- /dev/null +++ b/examples/blueprint-home/index.bp @@ -0,0 +1,50 @@ +page(favicon:"/favicon.ico") { + title { "Blueprint - Modern UI Framework" } + description { "A modern, declarative UI framework for building beautiful web interfaces" } + keywords { "blueprint, ui, framework, web development" } + author { "Blueprint Team" } +} + +navbar { + horizontal { + link(href:index) { text(bold) { "Blueprint Live" } } + links { + link(href:index) { "Home" } + link(href:components) { "Components" } + link(href:about) { "About" } + link(href:contact) { "Contact" } + } + } +} + +section(wide, centered) { + vertical(centered,wide) { + title(huge) { "Welcome to blueprint" } + text(subtle) { "You can now edit files in the src/ directory" } + } + + horizontal(centered) { + link(href:index) { button { "Get started" } } + link(href:about) { button-light { "About" } } + } +} + +section(wide) { + grid(columns:3) { + card { + title { "Live Reloads" } + text { "Changes appear instantly in your browser" } + link(href:https://example.com) { button-secondary { "Try Blueprint" } } + } + card { + title { "Modern Design" } + text { "Beautiful dark theme with consistent styling" } + link(href:about) { button-secondary { "About" } } + } + card { + title { "Easy to Use" } + text { "Simple, declarative syntax for building UIs" } + link(href:contact) { button-secondary { "Contact" } } + } + } +} \ No newline at end of file diff --git a/extension/blueprint-language-0.0.1.vsix b/extension/blueprint-language-0.0.1.vsix new file mode 100644 index 0000000..c03e9ad Binary files /dev/null and b/extension/blueprint-language-0.0.1.vsix differ diff --git a/extension/client/out/.tsbuildinfo b/extension/client/out/.tsbuildinfo new file mode 100644 index 0000000..ab54d4c --- /dev/null +++ b/extension/client/out/.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/@types/vscode/index.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/dom-events.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/vscode-languageserver-types/lib/umd/main.d.ts","../../node_modules/vscode-jsonrpc/typings/thenable.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messages.d.ts","../../node_modules/vscode-jsonrpc/lib/common/linkedmap.d.ts","../../node_modules/vscode-jsonrpc/lib/common/disposable.d.ts","../../node_modules/vscode-jsonrpc/lib/common/events.d.ts","../../node_modules/vscode-jsonrpc/lib/common/cancellation.d.ts","../../node_modules/vscode-jsonrpc/lib/common/encoding.d.ts","../../node_modules/vscode-jsonrpc/lib/common/ral.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagereader.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagewriter.d.ts","../../node_modules/vscode-jsonrpc/lib/common/connection.d.ts","../../node_modules/vscode-jsonrpc/lib/common/sharedarraycancellation.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagebuffer.d.ts","../../node_modules/vscode-jsonrpc/lib/common/api.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/messages.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.typedefinition.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.workspacefolder.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.colorprovider.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.callhierarchy.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.semantictokens.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.showdocument.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.linkededitingrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.fileoperations.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.typehierarchy.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.inlinevalue.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayhint.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/connection.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/api.d.ts","../../node_modules/vscode-languageclient/lib/common/codeconverter.d.ts","../../node_modules/vscode-languageclient/lib/common/protocolcompletionitem.d.ts","../../node_modules/vscode-languageclient/lib/common/protocolconverter.d.ts","../../node_modules/vscode-languageclient/lib/common/semantictokens.d.ts","../../node_modules/vscode-languageclient/lib/common/textsynchronization.d.ts","../../node_modules/vscode-languageclient/lib/common/codelens.d.ts","../../node_modules/vscode-languageclient/lib/common/inlinevalue.d.ts","../../node_modules/vscode-languageclient/lib/common/inlayhint.d.ts","../../node_modules/vscode-languageclient/lib/common/diagnostic.d.ts","../../node_modules/vscode-languageclient/lib/common/notebook.d.ts","../../node_modules/vscode-languageclient/lib/common/features.d.ts","../../node_modules/vscode-languageclient/lib/common/configuration.d.ts","../../node_modules/vscode-languageclient/lib/common/completion.d.ts","../../node_modules/vscode-languageclient/lib/common/hover.d.ts","../../node_modules/vscode-languageclient/lib/common/definition.d.ts","../../node_modules/vscode-languageclient/lib/common/signaturehelp.d.ts","../../node_modules/vscode-languageclient/lib/common/documenthighlight.d.ts","../../node_modules/vscode-languageclient/lib/common/documentsymbol.d.ts","../../node_modules/vscode-languageclient/lib/common/workspacesymbol.d.ts","../../node_modules/vscode-languageclient/lib/common/reference.d.ts","../../node_modules/vscode-languageclient/lib/common/typedefinition.d.ts","../../node_modules/vscode-languageclient/lib/common/implementation.d.ts","../../node_modules/vscode-languageclient/lib/common/colorprovider.d.ts","../../node_modules/vscode-languageclient/lib/common/codeaction.d.ts","../../node_modules/vscode-languageclient/lib/common/formatting.d.ts","../../node_modules/vscode-languageclient/lib/common/rename.d.ts","../../node_modules/vscode-languageclient/lib/common/documentlink.d.ts","../../node_modules/vscode-languageclient/lib/common/executecommand.d.ts","../../node_modules/vscode-languageclient/lib/common/foldingrange.d.ts","../../node_modules/vscode-languageclient/lib/common/declaration.d.ts","../../node_modules/vscode-languageclient/lib/common/selectionrange.d.ts","../../node_modules/vscode-languageclient/lib/common/callhierarchy.d.ts","../../node_modules/vscode-languageclient/lib/common/linkededitingrange.d.ts","../../node_modules/vscode-languageclient/lib/common/typehierarchy.d.ts","../../node_modules/vscode-languageclient/lib/common/workspacefolder.d.ts","../../node_modules/vscode-languageclient/lib/common/fileoperations.d.ts","../../node_modules/vscode-languageclient/lib/common/client.d.ts","../../node_modules/vscode-jsonrpc/lib/node/main.d.ts","../../node_modules/vscode-jsonrpc/node.d.ts","../../node_modules/vscode-languageserver-protocol/lib/node/main.d.ts","../../node_modules/vscode-languageserver-protocol/node.d.ts","../../node_modules/vscode-languageclient/lib/common/api.d.ts","../../node_modules/vscode-languageclient/lib/node/main.d.ts","../../node_modules/vscode-languageclient/node.d.ts","../src/extension.ts","../../node_modules/@types/json-schema/index.d.ts","../../node_modules/@types/semver/classes/semver.d.ts","../../node_modules/@types/semver/functions/parse.d.ts","../../node_modules/@types/semver/functions/valid.d.ts","../../node_modules/@types/semver/functions/clean.d.ts","../../node_modules/@types/semver/functions/inc.d.ts","../../node_modules/@types/semver/functions/diff.d.ts","../../node_modules/@types/semver/functions/major.d.ts","../../node_modules/@types/semver/functions/minor.d.ts","../../node_modules/@types/semver/functions/patch.d.ts","../../node_modules/@types/semver/functions/prerelease.d.ts","../../node_modules/@types/semver/functions/compare.d.ts","../../node_modules/@types/semver/functions/rcompare.d.ts","../../node_modules/@types/semver/functions/compare-loose.d.ts","../../node_modules/@types/semver/functions/compare-build.d.ts","../../node_modules/@types/semver/functions/sort.d.ts","../../node_modules/@types/semver/functions/rsort.d.ts","../../node_modules/@types/semver/functions/gt.d.ts","../../node_modules/@types/semver/functions/lt.d.ts","../../node_modules/@types/semver/functions/eq.d.ts","../../node_modules/@types/semver/functions/neq.d.ts","../../node_modules/@types/semver/functions/gte.d.ts","../../node_modules/@types/semver/functions/lte.d.ts","../../node_modules/@types/semver/functions/cmp.d.ts","../../node_modules/@types/semver/functions/coerce.d.ts","../../node_modules/@types/semver/classes/comparator.d.ts","../../node_modules/@types/semver/classes/range.d.ts","../../node_modules/@types/semver/functions/satisfies.d.ts","../../node_modules/@types/semver/ranges/max-satisfying.d.ts","../../node_modules/@types/semver/ranges/min-satisfying.d.ts","../../node_modules/@types/semver/ranges/to-comparators.d.ts","../../node_modules/@types/semver/ranges/min-version.d.ts","../../node_modules/@types/semver/ranges/valid.d.ts","../../node_modules/@types/semver/ranges/outside.d.ts","../../node_modules/@types/semver/ranges/gtr.d.ts","../../node_modules/@types/semver/ranges/ltr.d.ts","../../node_modules/@types/semver/ranges/intersects.d.ts","../../node_modules/@types/semver/ranges/simplify.d.ts","../../node_modules/@types/semver/ranges/subset.d.ts","../../node_modules/@types/semver/internals/identifiers.d.ts","../../node_modules/@types/semver/index.d.ts"],"fileIdsList":[[46,51,56,78,186],[51,56],[51,53,56],[51,55,56],[56],[51,56,61,88],[51,56,57,68,69,76,85,96],[51,56,57,58,68,76],[47,48,51,56],[51,56,59,97],[51,56,60,61,69,77],[51,56,61,85,93],[51,56,62,64,68,76],[51,56,63],[51,56,64,65],[51,56,68],[51,56,67,68],[51,55,56,68],[51,56,68,69,70,85,96],[51,56,68,69,70,85],[51,56,68,71,76,85,96],[51,56,68,69,71,72,76,85,93,96],[51,56,71,73,85,93,96],[49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102],[51,56,68,74],[51,56,75,96,101],[51,56,64,68,76,85],[51,56,77],[51,56,78],[51,55,56,79],[51,56,80,95,101],[51,56,81],[51,56,82],[51,56,68,83],[51,56,83,84,97,99],[51,56,68,85,86,87],[51,56,85,87],[51,56,85,86],[51,56,88],[51,56,89],[51,56,68,91,92],[51,56,91,92],[51,56,61,76,85,93],[51,56,94],[51,56,76,95],[51,56,71,82,96],[51,56,61,97],[51,56,85,98],[51,56,99],[51,56,100],[51,56,61,68,70,79,85,96,99,101],[51,56,85,102],[51,56,189,228],[51,56,189,213,228],[51,56,228],[51,56,189],[51,56,189,214,228],[51,56,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227],[51,56,214,228],[51,56,105,106,107,108,109,110,111,112,113,114,115,116,117],[51,56,108,109],[51,56,106,108,109,110,113,114],[51,56,106,112],[51,56,108],[51,56,112],[51,56,106,109,111,112,118],[51,56,106,109,111,112],[51,56,108,111],[51,56,106,110,115],[51,56,57,76,101,103,118],[51,56,180],[51,56,142,143,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,177,178,179],[46,51,56,142,153],[46,51,56,142,143,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178],[46,51,56,142],[46,51,56,142,143,145,146,147,148,149,150,151,152],[46,51,56,142,144],[46,51,56,57,103,179,183,184],[51,56,185],[51,56,104,118,119,140,141],[51,56,118,119],[51,56,118],[51,56,104,118,119,140],[51,56,104,118,119],[51,56,104,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139],[51,56,119,140],[51,56,104,119,140],[51,56,103,142,181],[51,56,182]],"fileInfos":[{"version":"e41c290ef7dd7dab3493e6cbe5909e0148edf4a8dad0271be08edec368a0f7b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"62bb211266ee48b2d0edf0d8d1b191f0c24fc379a82bd4c1692a082c540bc6b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1e2a172204962276504466a6393426d2ca9c54894b1ad0a6c9dad867a65f876","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"caaf6bf4dd0a3f88b50670f5786141b209edb54ba17eb6268c2d28919c813606","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e864ea827318e5f490863a8cd412744d9ddb175acf488dd02a941703dad1e38","impliedFormat":1},{"version":"a79e62f1e20467e11a904399b8b18b18c0c6eea6b50c1168bf215356d5bebfaf","affectsGlobalScope":true,"impliedFormat":1},{"version":"23301069cfa7a4c6dd68915eeccc7a2ae0bd3018ff4a6288dd9e0c8b4238fab6","affectsGlobalScope":true,"impliedFormat":1},{"version":"df01885cc27c14632a8c38bdeb053295e69209107bb6c53988b78db5f450cb3c","affectsGlobalScope":true,"impliedFormat":1},{"version":"38379fa748cc5d259c96da356a849bd290a159ae218e06ec1daa166850e4bf50","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"f51b4042a3ac86f1f707500a9768f88d0b0c1fc3f3e45a73333283dea720cdc6","impliedFormat":1},{"version":"a29bc8aa8cc100d0c09370c03508f1245853efe017bb98699d4c690868371fc7","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f95830ca11e2c7e82235b73dc149e68a0632b41e671724d12adc83a6750746d","impliedFormat":1},{"version":"7aa011cda7cf0b9e87c85d128b2eeac9930bda215b0fee265d8bf2cec039fb5f","impliedFormat":1},{"version":"92ec1aeca4e94bdab04083daa6039f807c0fce8f09bc42e8b24bf49fa5cdbbff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"8463ab6a156dc96200b3d8b8a52dc8d878f13a6b7404439aa2f911d568132808","impliedFormat":1},{"version":"6c39d4dbdb372b364442854e42d8c473e2ec67badb226745af17ed5ac41ce6f5","impliedFormat":1},{"version":"7693b90b3075deaccafd5efb467bf9f2b747a3075be888652ef73e64396d8628","impliedFormat":1},{"version":"bd01a987f0fcf2344a405e542ee681e420651eaff1222a5a6e0c02fda52343bc","impliedFormat":1},{"version":"693e50962e90a3548f41bff2c22676e3964212a836022d82e49eca0b20320a38","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"300b0c12998391154d7b9115a85554e91632a3d3e1b66038e98f2b9cb3c1061d","impliedFormat":1},{"version":"222e742815b14d54db034788a7bee2d51197a2588c35b1fbefe04add6393021c","affectsGlobalScope":true,"impliedFormat":1},{"version":"93891e576a698609695e5b8117bb128336e4b7b28772e7d7e38e8075790eb42f","impliedFormat":1},{"version":"5293d799856f47259146ccf0be9a1cc0a4a5343696182d7206ed25ea67d67920","impliedFormat":1},{"version":"d723063c56101b34a7be5b28dbde80a3ae3dfd5e08fd49a3b569473337ead1f9","impliedFormat":1},{"version":"fab49059d6c2026bdb2e53e4e5cde1a39da44e61daff1867c8b3b10b507bfe17","impliedFormat":1},{"version":"5a551275f85bcc4003e543a1951a5b2f682cfba9b2922f65ae0df40ab71724a5","impliedFormat":1},{"version":"22d1a3163b9a961dbe78b0aedbd7bcbc071ce1f31efb76eb013b0aee230fef0e","impliedFormat":1},{"version":"c31695696ade4514cfcbb22799997b690d3dca7fb72beab68fb2e73b6ef450dd","affectsGlobalScope":true,"impliedFormat":1},{"version":"d99ad56d57f2c96daaf4475a8b64344b24dedafdb8f3c32d43552bcc72279a75","impliedFormat":1},{"version":"a101ef17aece908c1029a1bd3f97132794dcff21b4ca0b997d9a633f962c46aa","impliedFormat":1},{"version":"511575e18249b64b90d8f884fdb8a383c767d1a7efccd9d66a4e125a4dc5c462","impliedFormat":1},{"version":"6d8001f2c3b86c4f1de1d45ecb3f87f287ed7313d6999f8c8318cec4f50e6323","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e413bb587e01ba0cb1a87828cc9116669a4a71a61fe3a89b252f86f0c824bc2","affectsGlobalScope":true,"impliedFormat":1},{"version":"9c3d1222e6e3d8c35a4293d7a54d4142ebb8f7f70ec4111b8136df07fdc66169","impliedFormat":1},{"version":"70173c475c6e76ccebc37412b02b2e26f62bf45fc1534c3ebe6d7fa60fb88819","impliedFormat":1},{"version":"87ced739f77d80886ef2b923a7c52c363c549ad8799ae28eb8cc810892f511ad","impliedFormat":1},{"version":"863bc4e31de6c75423bb02da16190d582b0a69b8964b61d45920e5b2cb3832dd","impliedFormat":1},{"version":"849484324695b587f06abee7579641efe061b7338f9694ec410a76f477fe4df3","impliedFormat":1},{"version":"269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","impliedFormat":1},{"version":"6e191fea1db6e9e4fa828259cf489e820ec9170effff57fb081a2f3295db4722","impliedFormat":1},{"version":"49e0da63a2398d2ae88467f60a69b07e594b7777e01120cd9ebcefa1932484cf","impliedFormat":1},{"version":"0435070b07e646b406b1c9b8b1b1878ea6917c32abc47e6435ec26d71212d513","impliedFormat":1},{"version":"f71188f97c9f7d309798ec02a56dd3bf50a4e4d079b3480f275ac13719953898","impliedFormat":1},{"version":"c4454589a0aa92c10d684c8c9584574bc404d1db556d72196cd31f8f7651af1a","affectsGlobalScope":true,"impliedFormat":1},{"version":"b17790866e140a630fa8891d7105c728a1bd60f4e35822e4b345af166a4a728c","impliedFormat":1},{"version":"c50c75f4360f6fc06c4be29dafe28210e15c50cd6b04ad19c4808fa504efb51a","impliedFormat":1},{"version":"d4a1f5f7ee89b2afffd3c74282f8ee65b24266c92b7d40398c12a27054ed745c","impliedFormat":1},{"version":"900b5a9802192bc77eba35a5b87ce770df7b867a6d61772c554058c9ed635386","impliedFormat":1},{"version":"d291d3d16fa252f6d460687491ea2c5c23098c9dc0d3e106b2803fdc98f48f29","affectsGlobalScope":true,"impliedFormat":1},{"version":"f43fcf89d75f13d0908a77cd3fa32b9fd28c915deded9b2778b08f2e242d07a7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b9a616dec7430044ae735250f8d6a7183f5a9fba63f813e3d29dcab819fd7058","impliedFormat":1},{"version":"aebf613f7831125038942eba891005fd25fa5cadcc3e3d13af4768dc7549161f","impliedFormat":1},{"version":"0faee6b555890a1cb106e2adc5d3ffd89545b1da894d474e9d436596d654998f","impliedFormat":1},{"version":"247e5c34784d185bc81442e8b1a371a36c4a5307a766a3725454c0a191b5cfad","impliedFormat":1},{"version":"1c382a6446d63340be549a616ff5142a91653cea45d6d137e25b929130a4f29a","impliedFormat":1},{"version":"9cf81848d806418e203efa6df299e0c5bfb5c137369337b0547117b2f0d44892","impliedFormat":1},{"version":"f0142b712ca22ad863476d9f3ae74e8b2766f3507a6fb5018882074f65ed0195","impliedFormat":1},{"version":"65b9243c80068ec9696b1fbdd23c9acf80d51df02f97b2d7a0514312b0a9fe7d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0def2c37cadfd7bf074fe9566cb83518f24d67193c79741b2d83ec290b945725","impliedFormat":1},{"version":"049e3511439f11e1285bec4647ab8aac53e0c06951b93ba507565dbde851ba31","impliedFormat":1},{"version":"f0745ab78e18a2befaf1d9951481973318722c4e2f33e859239f55fa999ff2b1","impliedFormat":1},{"version":"886e183dd0199e7de45d6308ac3e2185dac6f83283d1b8200ea62cf5c43966a1","impliedFormat":1},{"version":"392dd7b1117b588cba36c04909efd24b0458980506e8e8c1966114f8989058e2","impliedFormat":1},{"version":"ec9d55888e353f9b5cdda761308dffc7eeb6aa0b7b25d328c64d3776a1cf2a7e","impliedFormat":1},{"version":"1f8fedf144a967560be9e58fa32de75e4ca379c3549710d027a07be6a9414073","impliedFormat":1},{"version":"3ca7b2e8012b9a6be09fafd62f8f3937388b9e1600a59c98887d2b11f6d01b43","impliedFormat":1},{"version":"b138b3f30708386023a7dc9981bb867808e5ff3383429ac7f69b7bfd0dcc5bd5","impliedFormat":1},{"version":"a42c8992e2cf55a4a2d661fac251bc803fe119dad49327477d439268e42953d8","impliedFormat":1},{"version":"13ec544ab0a3a7ff96afac1016f55b264c812428e37d595dc33b688296435469","impliedFormat":1},{"version":"4962729121c2cb97a4481cdb06dfc720a79a3bc2fc9330ff2bcf604cfc541177","impliedFormat":1},{"version":"bc641da6705e45737a6c85bf6c7460e9298e5f5b1021abf035cb760d313cda1a","impliedFormat":1},{"version":"4284412700d89f927c8f5092a8e8c2a20a596349f2819148952b07f2cba9177a","impliedFormat":1},{"version":"4d08d58c94c1462506783c35009ddaeb70e54632310e384aa572ed7667333c8f","impliedFormat":1},{"version":"067f06a3d8abb66e4db6c22e34a076808b4c39418e45690f1abf37bcd4725f1c","impliedFormat":1},{"version":"05f6b2b3bef27dfc0e2464197510d08f275f2464363b441def7f309cbf42f51d","impliedFormat":1},{"version":"15055a0f3fe6c7e9d98bf9de36bdc9102ab324debbe2d4170ffe557115a199fc","impliedFormat":1},{"version":"33e11cee43184a95afe9a450f7dde6bd2b6a03fc9643f898268e8594c266554a","impliedFormat":1},{"version":"c13aaf7191fbccaf0f4e9e520c720b870c6339080eb1699439a392589fc85a96","impliedFormat":1},{"version":"41af0cbfe30738008b3765c30059580972362b70b8dcafd791908923e907c3a6","impliedFormat":1},{"version":"b5d49f459d2efc77cff4ab27d929aa67d0c9121bc20763d84942c7fca2cc7b8f","impliedFormat":1},{"version":"96c0c4b30165eaedb3ade3b4e9f491113a1816c448d67fff542b2793bf565b04","impliedFormat":1},{"version":"29a456c61c3d93e36f5eba4c0ed567d7896a9c08a38b537c3fc192a99d03b348","impliedFormat":1},{"version":"3b67dd4fbeec66a7d2acd2be4f65219d85abd04e6eb9cc96fd862ddf70e02eec","impliedFormat":1},{"version":"0a61f7b50171225629903175e062d3f43225e6eba24eb2e50f88ca05fb441aa6","impliedFormat":1},{"version":"818d9a0841c884447fbd61b934c6743aea1fa6f1c0159ef44ef55b8f02b9120f","impliedFormat":1},{"version":"b5f234cb0cb6ceb839fe2875ada30e62082707eaa7a36bfc4a4df9d287b901c7","impliedFormat":1},{"version":"facdb012edb0931c21556ace5bf7c0194c8389b1248fdbd94d09f793b311517c","impliedFormat":1},{"version":"98528506b6a07d49efdd7a65da416af50bfbfea67fbdca941ba55753e171a3db","impliedFormat":1},{"version":"8370c10834a51543556e92367c7c564723ae83b97199413a8eca6f5d70036cd5","impliedFormat":1},{"version":"8c1036c47d3e04eca9bd5fc5e0cdd219a78e4061a4bb4b55f4a4f0cbc621e66f","impliedFormat":1},{"version":"8db15e1da6050330d9e36bddd03131d5a02d56fac2e919fd8360892616357863","impliedFormat":1},{"version":"44874584b7c30882ea2cb1b9b0df0e198221afee1ee5cc4d04deb4c8a3c6345a","impliedFormat":1},{"version":"09839c769382d4763700d97d6e9ceae5c9ab3c34cf288229d9879b63c7206c60","impliedFormat":1},{"version":"c0c205fec8b10f3ad0e65af65dd20ea7cf633df0964c84305e375ccdc4f5557e","impliedFormat":1},{"version":"37c2423005b2ec6130903de29aec9fcf1680ab1b2336efa0ff828980e92da7e9","impliedFormat":1},{"version":"49cdd2b992fe2447994e995576addbc286913ddbebf928750074a6b1fcb24671","impliedFormat":1},{"version":"8479e373e70dedc75d9b1250a349e1efc4553af8a76bbd2ab4de7d9923fb6d1a","impliedFormat":1},{"version":"162e1ddfbe11f8052e38c8d6f69ea4df6fc12dab3902a79321ac0d5f88fe409e","impliedFormat":1},{"version":"d7a0eb5c9aff2237ec7b74a8d40e4221e5c0ef95019114e4a445eecf8f3d5946","impliedFormat":1},{"version":"6ec38a746ebcc6293af84cbf97f66b5a525a6d10424a0475e130ff8b6636a0a4","impliedFormat":1},{"version":"601d0bb63ace18781df556257caa4c3912ffefb599a59de91370b78d60c82969","impliedFormat":1},{"version":"bc9440b60655653ba1f5b94e02e831f1e935c652e2dc005836e7613c3a1d978d","impliedFormat":1},{"version":"2663a2923b6a66ae1729a9ad57db83a8b7578cdf1a545cd8a77ccc19b754038e","impliedFormat":1},{"version":"3062a3cccb480f7c798b8ca39128e368528f8b7f3fe3b72589bed8f5c7782d09","impliedFormat":1},{"version":"c983813ab0f99f37cf8b175a6761c2335df4cf1ed7515c7a19359797e9aa2639","impliedFormat":1},{"version":"7078d4a06f8f6944d23a57b0576bce9fe9eed5da1e02e89939cd5f534101a7d5","impliedFormat":1},{"version":"7dfd08c6f2628f5e2d4751d0a658bd12fa80e7c193f8845adda34eb46573457c","impliedFormat":1},{"version":"3f89dd0b5281bb1bcfe8207f88ecfa4d8de5388088f54cb012696f259d0f342c","impliedFormat":1},{"version":"46a2abc591dbc99debdb61cd1d25cfd80dd2fba1b9d341abb422a6e40e43449c","impliedFormat":1},{"version":"6a74f94c6f4282c5d0689e9b3edc08c6f744e7be8447e915c61aadd81339fe54","impliedFormat":1},{"version":"404d27a1f6dffc4dfbfeffcf483931faa4efd392a8b46c7e0ed9c1cb59f7ad15","impliedFormat":1},{"version":"ecb2d23ac823bf3c5d6735a973006fff1a0a1a5b5a5290f102426ffa00adda68","impliedFormat":1},{"version":"536044ec95d80b94b1fc6301205a0c8fe53887851d39a61d4d3c5564a6dd51eb","impliedFormat":1},{"version":"394ecd2838c8c55972676fe04b930bb32cd7aa0e8b7761b15527e71179bc2684","impliedFormat":1},{"version":"500ab366288ecf09ec637b0d984d41c6dd3ad8115c83da8ab9e004e3e63aa8bd","impliedFormat":1},{"version":"7429792de33c2c59148b2a26f29b26dda256a8d29e9f7b08d4aa5835f8b5e39f","impliedFormat":1},{"version":"d331cdb16cfded5638a2fcce3edb40452afbc3b486c5f0286af44a1aedb7a345","impliedFormat":1},{"version":"542178afcf014b2eab72333f205fc2ccc41217495bcc4cc1ed6e60ad9f1bd11b","impliedFormat":1},{"version":"d2e09ad5eb8111c3564ee743948b4e5915f5aee3d81c480d425eb5cee026fae6","impliedFormat":1},{"version":"ea3ea9ee8165da7b3432e4a4e94e9a0980d6aaf22bcd2d71204d407f106f2fa0","impliedFormat":1},{"version":"83567a9792c293d0f9d90feb9918e88b454ee8544e3d0ea06f9454477df010d1","impliedFormat":1},{"version":"eb314a7ab84c4f504444b53ec2b2d2557b0a06d79a7ce98e9bd2608cee5f946d","impliedFormat":1},{"version":"179f43f3b09b175b85e326ed59b1a2347b4d12fe7d67a4d88dee831f513119bd","impliedFormat":1},{"version":"b9e644c0e84188695a1d3d6d7d03740d7eaaf4bde5d6d25cbdb11df8347657d7","impliedFormat":1},{"version":"bd217bd008c0e8ec5332b6e905768fbadb3d925991dbf821307effd330e182d8","impliedFormat":1},{"version":"b355f2c3451ebc59d3b2fe47346f6a55da91dbcb9f2ad3b48b6bb5173fe77bb1","impliedFormat":1},{"version":"44263a5f285acc47f07cfa058edd282d7d06b026d85741b436372165337d6d2e","impliedFormat":1},{"version":"270314b700dfa1219abce94c5d46da873bfc958129426645ceff8cf559c2fec3","impliedFormat":1},{"version":"37ff500e6e9fe54a3a7e6f8533d4e65dfbb581625d0127836019ab6c86c64462","impliedFormat":1},{"version":"a9d6d153f6ca6ed0e992f3ecc9d684f16cbc0acaa33ab999aa826e80bb67365c","impliedFormat":1},{"version":"b19ef881994f1e0256e37589fadee9a93997400af999f33e2c3e638a6fcccb02","impliedFormat":1},{"version":"6b761b42779653f857ed9d9504f84a016cdfd16a95d044999a2b71331a18bcfd","impliedFormat":1},{"version":"67d37ef881a81aefe3a0f70f78e3835be950f2359487d3eb61b0a3bb9af172bc","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"d789022bf705385490fe89811bc7850225c207f37dd706ada2509eb1d8f31f12","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"e06388af85e67651e7bd2d13170e4dd9399ee93858cb1142fadfd99873535624","impliedFormat":1},{"version":"9a8bbbe55d20a047e89677cafc553879afb38d41a100ed7e6bb78e4b71203578","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"ba7789cb1790df485402b99531fb5f863194bcb76d64656bdec53a00bb200b0a","signature":"28fd02b23f22a42df03edc496d91b458cbb5c0b39a9933a40f136e465bf6dc1f"},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"cf3d384d082b933d987c4e2fe7bfb8710adfd9dc8155190056ed6695a25a559e","impliedFormat":1},{"version":"9871b7ee672bc16c78833bdab3052615834b08375cb144e4d2cba74473f4a589","impliedFormat":1},{"version":"c863198dae89420f3c552b5a03da6ed6d0acfa3807a64772b895db624b0de707","impliedFormat":1},{"version":"8b03a5e327d7db67112ebbc93b4f744133eda2c1743dbb0a990c61a8007823ef","impliedFormat":1},{"version":"86c73f2ee1752bac8eeeece234fd05dfcf0637a4fbd8032e4f5f43102faa8eec","impliedFormat":1},{"version":"42fad1f540271e35ca37cecda12c4ce2eef27f0f5cf0f8dd761d723c744d3159","impliedFormat":1},{"version":"ff3743a5de32bee10906aff63d1de726f6a7fd6ee2da4b8229054dfa69de2c34","impliedFormat":1},{"version":"83acd370f7f84f203e71ebba33ba61b7f1291ca027d7f9a662c6307d74e4ac22","impliedFormat":1},{"version":"1445cec898f90bdd18b2949b9590b3c012f5b7e1804e6e329fb0fe053946d5ec","impliedFormat":1},{"version":"0e5318ec2275d8da858b541920d9306650ae6ac8012f0e872fe66eb50321a669","impliedFormat":1},{"version":"cf530297c3fb3a92ec9591dd4fa229d58b5981e45fe6702a0bd2bea53a5e59be","impliedFormat":1},{"version":"c1f6f7d08d42148ddfe164d36d7aba91f467dbcb3caa715966ff95f55048b3a4","impliedFormat":1},{"version":"f4e9bf9103191ef3b3612d3ec0044ca4044ca5be27711fe648ada06fad4bcc85","impliedFormat":1},{"version":"0c1ee27b8f6a00097c2d6d91a21ee4d096ab52c1e28350f6362542b55380059a","impliedFormat":1},{"version":"7677d5b0db9e020d3017720f853ba18f415219fb3a9597343b1b1012cfd699f7","impliedFormat":1},{"version":"bc1c6bc119c1784b1a2be6d9c47addec0d83ef0d52c8fbe1f14a51b4dfffc675","impliedFormat":1},{"version":"52cf2ce99c2a23de70225e252e9822a22b4e0adb82643ab0b710858810e00bf1","impliedFormat":1},{"version":"770625067bb27a20b9826255a8d47b6b5b0a2d3dfcbd21f89904c731f671ba77","impliedFormat":1},{"version":"d1ed6765f4d7906a05968fb5cd6d1db8afa14dbe512a4884e8ea5c0f5e142c80","impliedFormat":1},{"version":"799c0f1b07c092626cf1efd71d459997635911bb5f7fc1196efe449bba87e965","impliedFormat":1},{"version":"2a184e4462b9914a30b1b5c41cf80c6d3428f17b20d3afb711fff3f0644001fd","impliedFormat":1},{"version":"9eabde32a3aa5d80de34af2c2206cdc3ee094c6504a8d0c2d6d20c7c179503cc","impliedFormat":1},{"version":"397c8051b6cfcb48aa22656f0faca2553c5f56187262135162ee79d2b2f6c966","impliedFormat":1},{"version":"a8ead142e0c87dcd5dc130eba1f8eeed506b08952d905c47621dc2f583b1bff9","impliedFormat":1},{"version":"a02f10ea5f73130efca046429254a4e3c06b5475baecc8f7b99a0014731be8b3","impliedFormat":1},{"version":"c2576a4083232b0e2d9bd06875dd43d371dee2e090325a9eac0133fd5650c1cb","impliedFormat":1},{"version":"4c9a0564bb317349de6a24eb4efea8bb79898fa72ad63a1809165f5bd42970dd","impliedFormat":1},{"version":"f40ac11d8859092d20f953aae14ba967282c3bb056431a37fced1866ec7a2681","impliedFormat":1},{"version":"cc11e9e79d4746cc59e0e17473a59d6f104692fd0eeea1bdb2e206eabed83b03","impliedFormat":1},{"version":"b444a410d34fb5e98aa5ee2b381362044f4884652e8bc8a11c8fe14bbd85518e","impliedFormat":1},{"version":"c35808c1f5e16d2c571aa65067e3cb95afeff843b259ecfa2fc107a9519b5392","impliedFormat":1},{"version":"14d5dc055143e941c8743c6a21fa459f961cbc3deedf1bfe47b11587ca4b3ef5","impliedFormat":1},{"version":"a3ad4e1fc542751005267d50a6298e6765928c0c3a8dce1572f2ba6ca518661c","impliedFormat":1},{"version":"f237e7c97a3a89f4591afd49ecb3bd8d14f51a1c4adc8fcae3430febedff5eb6","impliedFormat":1},{"version":"3ffdfbec93b7aed71082af62b8c3e0cc71261cc68d796665faa1e91604fbae8f","impliedFormat":1},{"version":"662201f943ed45b1ad600d03a90dffe20841e725203ced8b708c91fcd7f9379a","impliedFormat":1},{"version":"c9ef74c64ed051ea5b958621e7fb853fe3b56e8787c1587aefc6ea988b3c7e79","impliedFormat":1},{"version":"2462ccfac5f3375794b861abaa81da380f1bbd9401de59ffa43119a0b644253d","impliedFormat":1},{"version":"34baf65cfee92f110d6653322e2120c2d368ee64b3c7981dff08ed105c4f19b0","impliedFormat":1},{"version":"7d8ddf0f021c53099e34ee831a06c394d50371816caa98684812f089b4c6b3d4","impliedFormat":1}],"root":[187],"options":{"composite":true,"module":1,"outDir":"./","rootDir":"../src","sourceMap":true,"strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[187,1],[188,2],[53,3],[54,3],[55,4],[51,5],[56,6],[57,7],[58,8],[49,9],[47,2],[48,2],[59,10],[60,11],[61,12],[62,13],[63,14],[64,15],[65,15],[66,16],[67,17],[68,18],[69,19],[70,20],[52,2],[50,2],[71,21],[72,22],[73,23],[103,24],[74,25],[75,26],[76,27],[77,28],[78,29],[79,30],[80,31],[81,32],[82,33],[83,34],[84,35],[85,36],[87,37],[86,38],[88,39],[89,40],[90,2],[91,41],[92,42],[93,43],[94,44],[95,45],[96,46],[97,47],[98,48],[99,49],[100,50],[101,51],[102,52],[213,53],[214,54],[189,55],[192,55],[211,53],[212,53],[202,53],[201,56],[199,53],[194,53],[207,53],[205,53],[209,53],[193,53],[206,53],[210,53],[195,53],[196,53],[208,53],[190,53],[197,53],[198,53],[200,53],[204,53],[215,57],[203,53],[191,53],[228,58],[227,2],[222,57],[224,59],[223,57],[216,57],[217,57],[219,57],[221,57],[225,59],[226,59],[218,59],[220,59],[46,2],[44,2],[45,2],[9,2],[8,2],[2,2],[10,2],[11,2],[12,2],[13,2],[14,2],[15,2],[16,2],[17,2],[3,2],[18,2],[19,2],[4,2],[20,2],[24,2],[21,2],[22,2],[23,2],[25,2],[26,2],[27,2],[5,2],[28,2],[29,2],[30,2],[31,2],[6,2],[35,2],[32,2],[33,2],[34,2],[36,2],[7,2],[37,2],[42,2],[43,2],[38,2],[39,2],[40,2],[41,2],[1,2],[118,60],[110,61],[115,62],[108,2],[111,63],[109,64],[107,2],[117,65],[113,66],[106,2],[114,67],[112,68],[116,69],[180,70],[181,71],[105,2],[184,72],[174,73],[179,74],[166,73],[143,75],[148,73],[165,73],[155,73],[154,73],[172,73],[157,73],[151,73],[159,73],[169,73],[160,73],[170,73],[153,76],[178,73],[171,73],[167,73],[156,73],[164,73],[150,73],[149,73],[175,73],[152,73],[144,75],[145,77],[162,73],[168,73],[173,73],[146,73],[158,73],[147,73],[163,73],[176,73],[177,73],[161,73],[185,78],[186,79],[142,80],[141,81],[119,82],[129,83],[124,83],[123,84],[140,85],[126,83],[138,83],[133,84],[125,83],[120,83],[137,83],[136,83],[132,83],[134,86],[139,87],[128,84],[127,83],[130,83],[131,84],[121,83],[135,83],[122,84],[182,88],[183,89],[104,2]],"latestChangedDtsFile":"./extension.d.ts","version":"5.7.3"} \ No newline at end of file diff --git a/extension/client/out/extension.d.ts b/extension/client/out/extension.d.ts new file mode 100644 index 0000000..d42c8cc --- /dev/null +++ b/extension/client/out/extension.d.ts @@ -0,0 +1,3 @@ +import { ExtensionContext } from 'vscode'; +export declare function activate(context: ExtensionContext): void; +export declare function deactivate(): Thenable | undefined; diff --git a/extension/client/out/extension.js b/extension/client/out/extension.js new file mode 100644 index 0000000..fd43ff7 --- /dev/null +++ b/extension/client/out/extension.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.activate = activate; +exports.deactivate = deactivate; +// File: client/src/extension.ts +const path = require("path"); +const vscode_1 = require("vscode"); +const node_1 = require("vscode-languageclient/node"); +let client; +function activate(context) { + // The server is implemented in node + const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js')); + // The debug options for the server + const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + const serverOptions = { + run: { module: serverModule, transport: node_1.TransportKind.ipc }, + debug: { + module: serverModule, + transport: node_1.TransportKind.ipc, + options: debugOptions + } + }; + // Options to control the language client + const clientOptions = { + // Register the server for Blueprint documents + documentSelector: [{ scheme: 'file', language: 'blueprint' }], + synchronize: { + // Notify the server about file changes to '.bp files contained in the workspace + fileEvents: vscode_1.workspace.createFileSystemWatcher('**/*.bp') + } + }; + // Create and start the client + client = new node_1.LanguageClient('blueprintLanguageServer', 'Blueprint Language Server', serverOptions, clientOptions); + // Start the client. This will also launch the server + client.start(); +} +function deactivate() { + if (!client) { + return undefined; + } + return client.stop(); +} +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/extension/client/out/extension.js.map b/extension/client/out/extension.js.map new file mode 100644 index 0000000..6c9d462 --- /dev/null +++ b/extension/client/out/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;AAYA,4BAwCC;AAED,gCAKC;AA3DD,gCAAgC;AAChC,6BAA6B;AAC7B,mCAAqD;AACrD,qDAKoC;AAEpC,IAAI,MAAsB,CAAC;AAE3B,SAAgB,QAAQ,CAAC,OAAyB;IAC9C,oCAAoC;IACpC,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAC1C,CAAC;IAEF,mCAAmC;IACnC,MAAM,YAAY,GAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,CAAC;IAElE,oFAAoF;IACpF,qCAAqC;IACrC,MAAM,aAAa,GAAkB;QACjC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,oBAAa,CAAC,GAAG,EAAE;QAC3D,KAAK,EAAE;YACH,MAAM,EAAE,YAAY;YACpB,SAAS,EAAE,oBAAa,CAAC,GAAG;YAC5B,OAAO,EAAE,YAAY;SACxB;KACJ,CAAC;IAEF,yCAAyC;IACzC,MAAM,aAAa,GAA0B;QACzC,8CAA8C;QAC9C,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAC7D,WAAW,EAAE;YACT,gFAAgF;YAChF,UAAU,EAAE,kBAAS,CAAC,uBAAuB,CAAC,SAAS,CAAC;SAC3D;KACJ,CAAC;IAEF,8BAA8B;IAC9B,MAAM,GAAG,IAAI,qBAAc,CACvB,yBAAyB,EACzB,2BAA2B,EAC3B,aAAa,EACb,aAAa,CAChB,CAAC;IAEF,qDAAqD;IACrD,MAAM,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,SAAgB,UAAU;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC"} \ No newline at end of file diff --git a/extension/client/src/extension.ts b/extension/client/src/extension.ts new file mode 100644 index 0000000..28f82d8 --- /dev/null +++ b/extension/client/src/extension.ts @@ -0,0 +1,60 @@ +// File: client/src/extension.ts +import * as path from 'path'; +import { workspace, ExtensionContext } from 'vscode'; +import { + LanguageClient, + LanguageClientOptions, + ServerOptions, + TransportKind +} from 'vscode-languageclient/node'; + +let client: LanguageClient; + +export function activate(context: ExtensionContext) { + // The server is implemented in node + const serverModule = context.asAbsolutePath( + path.join('server', 'out', 'server.js') + ); + + // The debug options for the server + const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; + + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + const serverOptions: ServerOptions = { + run: { module: serverModule, transport: TransportKind.ipc }, + debug: { + module: serverModule, + transport: TransportKind.ipc, + options: debugOptions + } + }; + + // Options to control the language client + const clientOptions: LanguageClientOptions = { + // Register the server for Blueprint documents + documentSelector: [{ scheme: 'file', language: 'blueprint' }], + synchronize: { + // Notify the server about file changes to '.bp files contained in the workspace + fileEvents: workspace.createFileSystemWatcher('**/*.bp') + } + }; + + // Create and start the client + client = new LanguageClient( + 'blueprintLanguageServer', + 'Blueprint Language Server', + serverOptions, + clientOptions + ); + + // Start the client. This will also launch the server + client.start(); +} + +export function deactivate(): Thenable | undefined { + if (!client) { + return undefined; + } + return client.stop(); +} \ No newline at end of file diff --git a/extension/client/tsconfig.json b/extension/client/tsconfig.json new file mode 100644 index 0000000..7ec5113 --- /dev/null +++ b/extension/client/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "strict": true, + "outDir": "out", + "rootDir": "src", + "composite": true, + "tsBuildInfoFile": "./out/.tsbuildinfo" + }, + "include": ["src"], + "exclude": ["node_modules", ".vscode-test"] +} \ No newline at end of file diff --git a/extension/extension/client/out/extension.js b/extension/extension/client/out/extension.js new file mode 100644 index 0000000..5d185f5 --- /dev/null +++ b/extension/extension/client/out/extension.js @@ -0,0 +1,77 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.activate = activate; +exports.deactivate = deactivate; +// File: client/src/extension.ts +const path = __importStar(require("path")); +const vscode_1 = require("vscode"); +const node_1 = require("vscode-languageclient/node"); +let client; +function activate(context) { + // The server is implemented in node + const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js')); + // The debug options for the server + const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + const serverOptions = { + run: { module: serverModule, transport: node_1.TransportKind.ipc }, + debug: { + module: serverModule, + transport: node_1.TransportKind.ipc, + options: debugOptions + } + }; + // Options to control the language client + const clientOptions = { + // Register the server for Blueprint documents + documentSelector: [{ scheme: 'file', language: 'blueprint' }], + synchronize: { + // Notify the server about file changes to '.bp files contained in the workspace + fileEvents: vscode_1.workspace.createFileSystemWatcher('**/*.bp') + } + }; + // Create and start the client + client = new node_1.LanguageClient('blueprintLanguageServer', 'Blueprint Language Server', serverOptions, clientOptions); + // Start the client. This will also launch the server + client.start(); +} +function deactivate() { + if (!client) { + return undefined; + } + return client.stop(); +} diff --git a/extension/extension/tsconfig.tsbuildinfo b/extension/extension/tsconfig.tsbuildinfo new file mode 100644 index 0000000..0355f34 --- /dev/null +++ b/extension/extension/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["../client/src/extension.ts"],"version":"5.7.2"} \ No newline at end of file diff --git a/extension/out/tsconfig.tsbuildinfo b/extension/out/tsconfig.tsbuildinfo new file mode 100644 index 0000000..b05e939 --- /dev/null +++ b/extension/out/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["../client/src/extension.ts","../server/src/server.ts"],"version":"5.7.3"} \ No newline at end of file diff --git a/extension/package.json b/extension/package.json new file mode 100644 index 0000000..a0c0d01 --- /dev/null +++ b/extension/package.json @@ -0,0 +1,49 @@ +{ + "name": "blueprint-language", + "displayName": "Blueprint Language Support", + "description": "Language support for Blueprint layout files", + "version": "0.0.1", + "engines": { + "vscode": "^1.75.0" + }, + "categories": [ + "Programming Languages" + ], + "main": "./client/out/extension.js", + "contributes": { + "languages": [{ + "id": "blueprint", + "aliases": ["Blueprint", "blueprint"], + "extensions": [".bp"], + "configuration": "./language-configuration.json" + }], + "grammars": [{ + "language": "blueprint", + "scopeName": "source.blueprint", + "path": "./syntaxes/blueprint.tmLanguage.json" + }] + }, + "activationEvents": [ + "onLanguage:blueprint" + ], + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -b", + "watch": "tsc -b -w", + "compile:client": "tsc -b ./client/tsconfig.json", + "compile:server": "tsc -b ./server/tsconfig.json" + }, + "dependencies": { + "vscode-languageclient": "^8.1.0", + "vscode-languageserver": "^8.1.0", + "vscode-languageserver-textdocument": "^1.0.8" + }, + "devDependencies": { + "@types/node": "^16.11.7", + "@types/vscode": "^1.75.0", + "@typescript-eslint/eslint-plugin": "^5.54.0", + "@typescript-eslint/parser": "^5.54.0", + "eslint": "^8.35.0", + "typescript": "^5.0.2" + } +} \ No newline at end of file diff --git a/extension/server/out/.tsbuildinfo b/extension/server/out/.tsbuildinfo new file mode 100644 index 0000000..11c62bb --- /dev/null +++ b/extension/server/out/.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/vscode-languageserver/typings/thenable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/dom-events.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/vscode-languageserver-types/lib/umd/main.d.ts","../../node_modules/vscode-jsonrpc/typings/thenable.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messages.d.ts","../../node_modules/vscode-jsonrpc/lib/common/linkedmap.d.ts","../../node_modules/vscode-jsonrpc/lib/common/disposable.d.ts","../../node_modules/vscode-jsonrpc/lib/common/events.d.ts","../../node_modules/vscode-jsonrpc/lib/common/cancellation.d.ts","../../node_modules/vscode-jsonrpc/lib/common/encoding.d.ts","../../node_modules/vscode-jsonrpc/lib/common/ral.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagereader.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagewriter.d.ts","../../node_modules/vscode-jsonrpc/lib/common/connection.d.ts","../../node_modules/vscode-jsonrpc/lib/common/sharedarraycancellation.d.ts","../../node_modules/vscode-jsonrpc/lib/common/messagebuffer.d.ts","../../node_modules/vscode-jsonrpc/lib/common/api.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/messages.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.typedefinition.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.workspacefolder.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.colorprovider.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.callhierarchy.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.semantictokens.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.showdocument.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.linkededitingrange.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.fileoperations.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.typehierarchy.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.inlinevalue.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayhint.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/protocol.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/connection.d.ts","../../node_modules/vscode-languageserver-protocol/lib/common/api.d.ts","../../node_modules/vscode-languageserver/lib/common/progress.d.ts","../../node_modules/vscode-languageserver/lib/common/configuration.d.ts","../../node_modules/vscode-languageserver/lib/common/workspacefolder.d.ts","../../node_modules/vscode-languageserver/lib/common/callhierarchy.d.ts","../../node_modules/vscode-languageserver/lib/common/semantictokens.d.ts","../../node_modules/vscode-languageserver/lib/common/showdocument.d.ts","../../node_modules/vscode-languageserver/lib/common/fileoperations.d.ts","../../node_modules/vscode-languageserver/lib/common/linkededitingrange.d.ts","../../node_modules/vscode-languageserver/lib/common/typehierarchy.d.ts","../../node_modules/vscode-languageserver/lib/common/inlinevalue.d.ts","../../node_modules/vscode-languageserver/lib/common/inlayhint.d.ts","../../node_modules/vscode-languageserver/lib/common/diagnostic.d.ts","../../node_modules/vscode-languageserver/lib/common/textdocuments.d.ts","../../node_modules/vscode-languageserver/lib/common/notebook.d.ts","../../node_modules/vscode-languageserver/lib/common/moniker.d.ts","../../node_modules/vscode-languageserver/lib/common/server.d.ts","../../node_modules/vscode-languageserver/lib/node/files.d.ts","../../node_modules/vscode-jsonrpc/lib/node/main.d.ts","../../node_modules/vscode-jsonrpc/node.d.ts","../../node_modules/vscode-languageserver-protocol/lib/node/main.d.ts","../../node_modules/vscode-languageserver-protocol/node.d.ts","../../node_modules/vscode-languageserver/lib/common/api.d.ts","../../node_modules/vscode-languageserver/lib/node/main.d.ts","../../node_modules/vscode-languageserver/node.d.ts","../../node_modules/vscode-languageserver-textdocument/lib/umd/main.d.ts","../src/server.ts","../../node_modules/@types/json-schema/index.d.ts","../../node_modules/@types/semver/classes/semver.d.ts","../../node_modules/@types/semver/functions/parse.d.ts","../../node_modules/@types/semver/functions/valid.d.ts","../../node_modules/@types/semver/functions/clean.d.ts","../../node_modules/@types/semver/functions/inc.d.ts","../../node_modules/@types/semver/functions/diff.d.ts","../../node_modules/@types/semver/functions/major.d.ts","../../node_modules/@types/semver/functions/minor.d.ts","../../node_modules/@types/semver/functions/patch.d.ts","../../node_modules/@types/semver/functions/prerelease.d.ts","../../node_modules/@types/semver/functions/compare.d.ts","../../node_modules/@types/semver/functions/rcompare.d.ts","../../node_modules/@types/semver/functions/compare-loose.d.ts","../../node_modules/@types/semver/functions/compare-build.d.ts","../../node_modules/@types/semver/functions/sort.d.ts","../../node_modules/@types/semver/functions/rsort.d.ts","../../node_modules/@types/semver/functions/gt.d.ts","../../node_modules/@types/semver/functions/lt.d.ts","../../node_modules/@types/semver/functions/eq.d.ts","../../node_modules/@types/semver/functions/neq.d.ts","../../node_modules/@types/semver/functions/gte.d.ts","../../node_modules/@types/semver/functions/lte.d.ts","../../node_modules/@types/semver/functions/cmp.d.ts","../../node_modules/@types/semver/functions/coerce.d.ts","../../node_modules/@types/semver/classes/comparator.d.ts","../../node_modules/@types/semver/classes/range.d.ts","../../node_modules/@types/semver/functions/satisfies.d.ts","../../node_modules/@types/semver/ranges/max-satisfying.d.ts","../../node_modules/@types/semver/ranges/min-satisfying.d.ts","../../node_modules/@types/semver/ranges/to-comparators.d.ts","../../node_modules/@types/semver/ranges/min-version.d.ts","../../node_modules/@types/semver/ranges/valid.d.ts","../../node_modules/@types/semver/ranges/outside.d.ts","../../node_modules/@types/semver/ranges/gtr.d.ts","../../node_modules/@types/semver/ranges/ltr.d.ts","../../node_modules/@types/semver/ranges/intersects.d.ts","../../node_modules/@types/semver/ranges/simplify.d.ts","../../node_modules/@types/semver/ranges/subset.d.ts","../../node_modules/@types/semver/internals/identifiers.d.ts","../../node_modules/@types/semver/index.d.ts","../../node_modules/@types/vscode/index.d.ts"],"fileIdsList":[[51,56],[51,53,56],[51,55,56],[56],[51,56,61,88],[51,56,57,68,69,76,85,96],[51,56,57,58,68,76],[47,48,51,56],[51,56,59,97],[51,56,60,61,69,77],[51,56,61,85,93],[51,56,62,64,68,76],[51,56,63],[51,56,64,65],[51,56,68],[51,56,67,68],[51,55,56,68],[51,56,68,69,70,85,96],[51,56,68,69,70,85],[51,56,68,71,76,85,96],[51,56,68,69,71,72,76,85,93,96],[51,56,71,73,85,93,96],[49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102],[51,56,68,74],[51,56,75,96,101],[51,56,64,68,76,85],[51,56,77],[51,56,78],[51,55,56,79],[51,56,80,95,101],[51,56,81],[51,56,82],[51,56,68,83],[51,56,83,84,97,99],[51,56,68,85,86,87],[51,56,85,87],[51,56,85,86],[51,56,88],[51,56,89],[51,56,68,91,92],[51,56,91,92],[51,56,61,76,85,93],[51,56,94],[51,56,76,95],[51,56,71,82,96],[51,56,61,97],[51,56,85,98],[51,56,99],[51,56,100],[51,56,61,68,70,79,85,96,99,101],[51,56,85,102],[51,56,170,209],[51,56,170,194,209],[51,56,209],[51,56,170],[51,56,170,195,209],[51,56,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],[51,56,195,209],[51,56,105,106,107,108,109,110,111,112,113,114,115,116,117],[51,56,108,109],[51,56,106,108,109,110,113,114],[51,56,106,112],[51,56,108],[51,56,112],[51,56,106,109,111,112,118],[51,56,106,109,111,112],[51,56,108,111],[51,56,106,110,115],[51,56,57,76,101,103,118],[51,56,160],[51,56,104,118,119,140,141],[51,56,118,119],[51,56,118],[51,56,104,118,119,140],[51,56,104,118,119],[51,56,104,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139],[51,56,119,140],[51,56,104,119,140],[51,56,103,142,161],[51,56,162],[51,56,142,143,147,155,156,158],[51,56,142,158],[51,56,142,155,158],[51,56,142,143,144,145,146,147,148,149,150,151,152,153,154,156,157],[51,56,142],[46,51,56,103,158,159,163,164],[51,56,165],[51,56,166,167]],"fileInfos":[{"version":"e41c290ef7dd7dab3493e6cbe5909e0148edf4a8dad0271be08edec368a0f7b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"62bb211266ee48b2d0edf0d8d1b191f0c24fc379a82bd4c1692a082c540bc6b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1e2a172204962276504466a6393426d2ca9c54894b1ad0a6c9dad867a65f876","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"65b9243c80068ec9696b1fbdd23c9acf80d51df02f97b2d7a0514312b0a9fe7d","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e864ea827318e5f490863a8cd412744d9ddb175acf488dd02a941703dad1e38","impliedFormat":1},{"version":"a79e62f1e20467e11a904399b8b18b18c0c6eea6b50c1168bf215356d5bebfaf","affectsGlobalScope":true,"impliedFormat":1},{"version":"23301069cfa7a4c6dd68915eeccc7a2ae0bd3018ff4a6288dd9e0c8b4238fab6","affectsGlobalScope":true,"impliedFormat":1},{"version":"df01885cc27c14632a8c38bdeb053295e69209107bb6c53988b78db5f450cb3c","affectsGlobalScope":true,"impliedFormat":1},{"version":"38379fa748cc5d259c96da356a849bd290a159ae218e06ec1daa166850e4bf50","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"f51b4042a3ac86f1f707500a9768f88d0b0c1fc3f3e45a73333283dea720cdc6","impliedFormat":1},{"version":"a29bc8aa8cc100d0c09370c03508f1245853efe017bb98699d4c690868371fc7","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f95830ca11e2c7e82235b73dc149e68a0632b41e671724d12adc83a6750746d","impliedFormat":1},{"version":"7aa011cda7cf0b9e87c85d128b2eeac9930bda215b0fee265d8bf2cec039fb5f","impliedFormat":1},{"version":"92ec1aeca4e94bdab04083daa6039f807c0fce8f09bc42e8b24bf49fa5cdbbff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"8463ab6a156dc96200b3d8b8a52dc8d878f13a6b7404439aa2f911d568132808","impliedFormat":1},{"version":"6c39d4dbdb372b364442854e42d8c473e2ec67badb226745af17ed5ac41ce6f5","impliedFormat":1},{"version":"7693b90b3075deaccafd5efb467bf9f2b747a3075be888652ef73e64396d8628","impliedFormat":1},{"version":"bd01a987f0fcf2344a405e542ee681e420651eaff1222a5a6e0c02fda52343bc","impliedFormat":1},{"version":"693e50962e90a3548f41bff2c22676e3964212a836022d82e49eca0b20320a38","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"300b0c12998391154d7b9115a85554e91632a3d3e1b66038e98f2b9cb3c1061d","impliedFormat":1},{"version":"222e742815b14d54db034788a7bee2d51197a2588c35b1fbefe04add6393021c","affectsGlobalScope":true,"impliedFormat":1},{"version":"93891e576a698609695e5b8117bb128336e4b7b28772e7d7e38e8075790eb42f","impliedFormat":1},{"version":"5293d799856f47259146ccf0be9a1cc0a4a5343696182d7206ed25ea67d67920","impliedFormat":1},{"version":"d723063c56101b34a7be5b28dbde80a3ae3dfd5e08fd49a3b569473337ead1f9","impliedFormat":1},{"version":"fab49059d6c2026bdb2e53e4e5cde1a39da44e61daff1867c8b3b10b507bfe17","impliedFormat":1},{"version":"5a551275f85bcc4003e543a1951a5b2f682cfba9b2922f65ae0df40ab71724a5","impliedFormat":1},{"version":"22d1a3163b9a961dbe78b0aedbd7bcbc071ce1f31efb76eb013b0aee230fef0e","impliedFormat":1},{"version":"c31695696ade4514cfcbb22799997b690d3dca7fb72beab68fb2e73b6ef450dd","affectsGlobalScope":true,"impliedFormat":1},{"version":"d99ad56d57f2c96daaf4475a8b64344b24dedafdb8f3c32d43552bcc72279a75","impliedFormat":1},{"version":"a101ef17aece908c1029a1bd3f97132794dcff21b4ca0b997d9a633f962c46aa","impliedFormat":1},{"version":"511575e18249b64b90d8f884fdb8a383c767d1a7efccd9d66a4e125a4dc5c462","impliedFormat":1},{"version":"6d8001f2c3b86c4f1de1d45ecb3f87f287ed7313d6999f8c8318cec4f50e6323","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e413bb587e01ba0cb1a87828cc9116669a4a71a61fe3a89b252f86f0c824bc2","affectsGlobalScope":true,"impliedFormat":1},{"version":"9c3d1222e6e3d8c35a4293d7a54d4142ebb8f7f70ec4111b8136df07fdc66169","impliedFormat":1},{"version":"70173c475c6e76ccebc37412b02b2e26f62bf45fc1534c3ebe6d7fa60fb88819","impliedFormat":1},{"version":"87ced739f77d80886ef2b923a7c52c363c549ad8799ae28eb8cc810892f511ad","impliedFormat":1},{"version":"863bc4e31de6c75423bb02da16190d582b0a69b8964b61d45920e5b2cb3832dd","impliedFormat":1},{"version":"849484324695b587f06abee7579641efe061b7338f9694ec410a76f477fe4df3","impliedFormat":1},{"version":"269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","impliedFormat":1},{"version":"6e191fea1db6e9e4fa828259cf489e820ec9170effff57fb081a2f3295db4722","impliedFormat":1},{"version":"49e0da63a2398d2ae88467f60a69b07e594b7777e01120cd9ebcefa1932484cf","impliedFormat":1},{"version":"0435070b07e646b406b1c9b8b1b1878ea6917c32abc47e6435ec26d71212d513","impliedFormat":1},{"version":"f71188f97c9f7d309798ec02a56dd3bf50a4e4d079b3480f275ac13719953898","impliedFormat":1},{"version":"c4454589a0aa92c10d684c8c9584574bc404d1db556d72196cd31f8f7651af1a","affectsGlobalScope":true,"impliedFormat":1},{"version":"b17790866e140a630fa8891d7105c728a1bd60f4e35822e4b345af166a4a728c","impliedFormat":1},{"version":"c50c75f4360f6fc06c4be29dafe28210e15c50cd6b04ad19c4808fa504efb51a","impliedFormat":1},{"version":"d4a1f5f7ee89b2afffd3c74282f8ee65b24266c92b7d40398c12a27054ed745c","impliedFormat":1},{"version":"900b5a9802192bc77eba35a5b87ce770df7b867a6d61772c554058c9ed635386","impliedFormat":1},{"version":"d291d3d16fa252f6d460687491ea2c5c23098c9dc0d3e106b2803fdc98f48f29","affectsGlobalScope":true,"impliedFormat":1},{"version":"f43fcf89d75f13d0908a77cd3fa32b9fd28c915deded9b2778b08f2e242d07a7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b9a616dec7430044ae735250f8d6a7183f5a9fba63f813e3d29dcab819fd7058","impliedFormat":1},{"version":"aebf613f7831125038942eba891005fd25fa5cadcc3e3d13af4768dc7549161f","impliedFormat":1},{"version":"0faee6b555890a1cb106e2adc5d3ffd89545b1da894d474e9d436596d654998f","impliedFormat":1},{"version":"247e5c34784d185bc81442e8b1a371a36c4a5307a766a3725454c0a191b5cfad","impliedFormat":1},{"version":"1c382a6446d63340be549a616ff5142a91653cea45d6d137e25b929130a4f29a","impliedFormat":1},{"version":"9cf81848d806418e203efa6df299e0c5bfb5c137369337b0547117b2f0d44892","impliedFormat":1},{"version":"f0142b712ca22ad863476d9f3ae74e8b2766f3507a6fb5018882074f65ed0195","impliedFormat":1},{"version":"65b9243c80068ec9696b1fbdd23c9acf80d51df02f97b2d7a0514312b0a9fe7d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0def2c37cadfd7bf074fe9566cb83518f24d67193c79741b2d83ec290b945725","impliedFormat":1},{"version":"049e3511439f11e1285bec4647ab8aac53e0c06951b93ba507565dbde851ba31","impliedFormat":1},{"version":"f0745ab78e18a2befaf1d9951481973318722c4e2f33e859239f55fa999ff2b1","impliedFormat":1},{"version":"886e183dd0199e7de45d6308ac3e2185dac6f83283d1b8200ea62cf5c43966a1","impliedFormat":1},{"version":"392dd7b1117b588cba36c04909efd24b0458980506e8e8c1966114f8989058e2","impliedFormat":1},{"version":"ec9d55888e353f9b5cdda761308dffc7eeb6aa0b7b25d328c64d3776a1cf2a7e","impliedFormat":1},{"version":"1f8fedf144a967560be9e58fa32de75e4ca379c3549710d027a07be6a9414073","impliedFormat":1},{"version":"3ca7b2e8012b9a6be09fafd62f8f3937388b9e1600a59c98887d2b11f6d01b43","impliedFormat":1},{"version":"b138b3f30708386023a7dc9981bb867808e5ff3383429ac7f69b7bfd0dcc5bd5","impliedFormat":1},{"version":"a42c8992e2cf55a4a2d661fac251bc803fe119dad49327477d439268e42953d8","impliedFormat":1},{"version":"13ec544ab0a3a7ff96afac1016f55b264c812428e37d595dc33b688296435469","impliedFormat":1},{"version":"4962729121c2cb97a4481cdb06dfc720a79a3bc2fc9330ff2bcf604cfc541177","impliedFormat":1},{"version":"bc641da6705e45737a6c85bf6c7460e9298e5f5b1021abf035cb760d313cda1a","impliedFormat":1},{"version":"4284412700d89f927c8f5092a8e8c2a20a596349f2819148952b07f2cba9177a","impliedFormat":1},{"version":"4d08d58c94c1462506783c35009ddaeb70e54632310e384aa572ed7667333c8f","impliedFormat":1},{"version":"067f06a3d8abb66e4db6c22e34a076808b4c39418e45690f1abf37bcd4725f1c","impliedFormat":1},{"version":"05f6b2b3bef27dfc0e2464197510d08f275f2464363b441def7f309cbf42f51d","impliedFormat":1},{"version":"15055a0f3fe6c7e9d98bf9de36bdc9102ab324debbe2d4170ffe557115a199fc","impliedFormat":1},{"version":"33e11cee43184a95afe9a450f7dde6bd2b6a03fc9643f898268e8594c266554a","impliedFormat":1},{"version":"c13aaf7191fbccaf0f4e9e520c720b870c6339080eb1699439a392589fc85a96","impliedFormat":1},{"version":"41af0cbfe30738008b3765c30059580972362b70b8dcafd791908923e907c3a6","impliedFormat":1},{"version":"b5d49f459d2efc77cff4ab27d929aa67d0c9121bc20763d84942c7fca2cc7b8f","impliedFormat":1},{"version":"96c0c4b30165eaedb3ade3b4e9f491113a1816c448d67fff542b2793bf565b04","impliedFormat":1},{"version":"29a456c61c3d93e36f5eba4c0ed567d7896a9c08a38b537c3fc192a99d03b348","impliedFormat":1},{"version":"3b67dd4fbeec66a7d2acd2be4f65219d85abd04e6eb9cc96fd862ddf70e02eec","impliedFormat":1},{"version":"0a61f7b50171225629903175e062d3f43225e6eba24eb2e50f88ca05fb441aa6","impliedFormat":1},{"version":"818d9a0841c884447fbd61b934c6743aea1fa6f1c0159ef44ef55b8f02b9120f","impliedFormat":1},{"version":"b5f234cb0cb6ceb839fe2875ada30e62082707eaa7a36bfc4a4df9d287b901c7","impliedFormat":1},{"version":"facdb012edb0931c21556ace5bf7c0194c8389b1248fdbd94d09f793b311517c","impliedFormat":1},{"version":"98528506b6a07d49efdd7a65da416af50bfbfea67fbdca941ba55753e171a3db","impliedFormat":1},{"version":"8370c10834a51543556e92367c7c564723ae83b97199413a8eca6f5d70036cd5","impliedFormat":1},{"version":"8c1036c47d3e04eca9bd5fc5e0cdd219a78e4061a4bb4b55f4a4f0cbc621e66f","impliedFormat":1},{"version":"8db15e1da6050330d9e36bddd03131d5a02d56fac2e919fd8360892616357863","impliedFormat":1},{"version":"44874584b7c30882ea2cb1b9b0df0e198221afee1ee5cc4d04deb4c8a3c6345a","impliedFormat":1},{"version":"09839c769382d4763700d97d6e9ceae5c9ab3c34cf288229d9879b63c7206c60","impliedFormat":1},{"version":"c0c205fec8b10f3ad0e65af65dd20ea7cf633df0964c84305e375ccdc4f5557e","impliedFormat":1},{"version":"37c2423005b2ec6130903de29aec9fcf1680ab1b2336efa0ff828980e92da7e9","impliedFormat":1},{"version":"f1f23acd4a8193453749f69d4432f5f122d6d572b793a8b630dd12fe80b0c3d3","impliedFormat":1},{"version":"7662d6994d28c9ebbe61b88cc35c3d705804351eedbf363df30ea9fe8c4961dc","impliedFormat":1},{"version":"1fb68106bddae35448e5279095461a4b54c4bbb42787cd629f70924b17e9a11e","impliedFormat":1},{"version":"46a9b0122b230cb2fab65999ba92f98a16fd8f1c25efaed47141cbf5056f6928","impliedFormat":1},{"version":"5a9a4741aa510bdee406441f77186c6d2005be78e78c2e0da8201d9991950164","impliedFormat":1},{"version":"351bbf43d585484825ee6c4b4805aac137ffc8e8a3b9812af99945a202db7c02","impliedFormat":1},{"version":"3990ae796cc23fb9829eae206eff1eddded9465504467a4433f2509e18ef1aed","impliedFormat":1},{"version":"b557ea3605e52406e35eeea468cb96f25b1ca906f2055f376597f0b02492d94c","impliedFormat":1},{"version":"f384bb303dbc114af6460e7cb30b766cc92eed33fccb331126b08bb63f15a034","impliedFormat":1},{"version":"8a9bd1cf8c1f75435f83595b43737c135e7f73bde39ba4c9339dc6a31e8bb069","impliedFormat":1},{"version":"8274bfd5de49f9f072be2f39c34e390101a8b69844e55eda36c7df23ba6d03e2","impliedFormat":1},{"version":"f8b482dddda55dd6677d7895a3fef8cd9d067f8c36c63cc7fe93b82a6dd4f10c","impliedFormat":1},{"version":"71d11ad1f05b0b90e95591fa85c1c8043e590d67972dcaba9b50435a0c04d8fa","impliedFormat":1},{"version":"c77c8f4aa3f4b849eda044768882bb102edf211b1c26b04a3c6ad921110f2fa4","impliedFormat":1},{"version":"a980ce9470dc95ac355d7efb729f9cfb0564505eba96da4bbde504299efb833a","impliedFormat":1},{"version":"eed44483a64b3c5a643663f8827c868ef3888965c7f3654e816debd03c621da0","impliedFormat":1},{"version":"a58402dc75738c188a741ccca86ccf898b0af98d305ad075c428171f193a6cd5","impliedFormat":1},{"version":"67d37ef881a81aefe3a0f70f78e3835be950f2359487d3eb61b0a3bb9af172bc","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"d789022bf705385490fe89811bc7850225c207f37dd706ada2509eb1d8f31f12","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"d29fa1f984b6d5ec55c37e6f65474ea4acaf9ba92d2b1d502ca824abca86b430","impliedFormat":1},{"version":"abd02654e7ae1f70f68ec509b2c3c1e388c0142d169ba37a157f558709efe2a1","impliedFormat":1},{"version":"9c98df0145d99011af92c397fa787fc39d42cc04019614ab5581febe71fb32e1","impliedFormat":1},{"version":"96a56b3bbf8346c584c5d58db4fb8adc58982e4e9f2929488ad5aeb89ddc19f8","impliedFormat":1},{"version":"db744053fe42f80b7777c89f39bc6cf351f7796b1c828550a37cdc17cba0e056","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"cf3d384d082b933d987c4e2fe7bfb8710adfd9dc8155190056ed6695a25a559e","impliedFormat":1},{"version":"9871b7ee672bc16c78833bdab3052615834b08375cb144e4d2cba74473f4a589","impliedFormat":1},{"version":"c863198dae89420f3c552b5a03da6ed6d0acfa3807a64772b895db624b0de707","impliedFormat":1},{"version":"8b03a5e327d7db67112ebbc93b4f744133eda2c1743dbb0a990c61a8007823ef","impliedFormat":1},{"version":"86c73f2ee1752bac8eeeece234fd05dfcf0637a4fbd8032e4f5f43102faa8eec","impliedFormat":1},{"version":"42fad1f540271e35ca37cecda12c4ce2eef27f0f5cf0f8dd761d723c744d3159","impliedFormat":1},{"version":"ff3743a5de32bee10906aff63d1de726f6a7fd6ee2da4b8229054dfa69de2c34","impliedFormat":1},{"version":"83acd370f7f84f203e71ebba33ba61b7f1291ca027d7f9a662c6307d74e4ac22","impliedFormat":1},{"version":"1445cec898f90bdd18b2949b9590b3c012f5b7e1804e6e329fb0fe053946d5ec","impliedFormat":1},{"version":"0e5318ec2275d8da858b541920d9306650ae6ac8012f0e872fe66eb50321a669","impliedFormat":1},{"version":"cf530297c3fb3a92ec9591dd4fa229d58b5981e45fe6702a0bd2bea53a5e59be","impliedFormat":1},{"version":"c1f6f7d08d42148ddfe164d36d7aba91f467dbcb3caa715966ff95f55048b3a4","impliedFormat":1},{"version":"f4e9bf9103191ef3b3612d3ec0044ca4044ca5be27711fe648ada06fad4bcc85","impliedFormat":1},{"version":"0c1ee27b8f6a00097c2d6d91a21ee4d096ab52c1e28350f6362542b55380059a","impliedFormat":1},{"version":"7677d5b0db9e020d3017720f853ba18f415219fb3a9597343b1b1012cfd699f7","impliedFormat":1},{"version":"bc1c6bc119c1784b1a2be6d9c47addec0d83ef0d52c8fbe1f14a51b4dfffc675","impliedFormat":1},{"version":"52cf2ce99c2a23de70225e252e9822a22b4e0adb82643ab0b710858810e00bf1","impliedFormat":1},{"version":"770625067bb27a20b9826255a8d47b6b5b0a2d3dfcbd21f89904c731f671ba77","impliedFormat":1},{"version":"d1ed6765f4d7906a05968fb5cd6d1db8afa14dbe512a4884e8ea5c0f5e142c80","impliedFormat":1},{"version":"799c0f1b07c092626cf1efd71d459997635911bb5f7fc1196efe449bba87e965","impliedFormat":1},{"version":"2a184e4462b9914a30b1b5c41cf80c6d3428f17b20d3afb711fff3f0644001fd","impliedFormat":1},{"version":"9eabde32a3aa5d80de34af2c2206cdc3ee094c6504a8d0c2d6d20c7c179503cc","impliedFormat":1},{"version":"397c8051b6cfcb48aa22656f0faca2553c5f56187262135162ee79d2b2f6c966","impliedFormat":1},{"version":"a8ead142e0c87dcd5dc130eba1f8eeed506b08952d905c47621dc2f583b1bff9","impliedFormat":1},{"version":"a02f10ea5f73130efca046429254a4e3c06b5475baecc8f7b99a0014731be8b3","impliedFormat":1},{"version":"c2576a4083232b0e2d9bd06875dd43d371dee2e090325a9eac0133fd5650c1cb","impliedFormat":1},{"version":"4c9a0564bb317349de6a24eb4efea8bb79898fa72ad63a1809165f5bd42970dd","impliedFormat":1},{"version":"f40ac11d8859092d20f953aae14ba967282c3bb056431a37fced1866ec7a2681","impliedFormat":1},{"version":"cc11e9e79d4746cc59e0e17473a59d6f104692fd0eeea1bdb2e206eabed83b03","impliedFormat":1},{"version":"b444a410d34fb5e98aa5ee2b381362044f4884652e8bc8a11c8fe14bbd85518e","impliedFormat":1},{"version":"c35808c1f5e16d2c571aa65067e3cb95afeff843b259ecfa2fc107a9519b5392","impliedFormat":1},{"version":"14d5dc055143e941c8743c6a21fa459f961cbc3deedf1bfe47b11587ca4b3ef5","impliedFormat":1},{"version":"a3ad4e1fc542751005267d50a6298e6765928c0c3a8dce1572f2ba6ca518661c","impliedFormat":1},{"version":"f237e7c97a3a89f4591afd49ecb3bd8d14f51a1c4adc8fcae3430febedff5eb6","impliedFormat":1},{"version":"3ffdfbec93b7aed71082af62b8c3e0cc71261cc68d796665faa1e91604fbae8f","impliedFormat":1},{"version":"662201f943ed45b1ad600d03a90dffe20841e725203ced8b708c91fcd7f9379a","impliedFormat":1},{"version":"c9ef74c64ed051ea5b958621e7fb853fe3b56e8787c1587aefc6ea988b3c7e79","impliedFormat":1},{"version":"2462ccfac5f3375794b861abaa81da380f1bbd9401de59ffa43119a0b644253d","impliedFormat":1},{"version":"34baf65cfee92f110d6653322e2120c2d368ee64b3c7981dff08ed105c4f19b0","impliedFormat":1},{"version":"7d8ddf0f021c53099e34ee831a06c394d50371816caa98684812f089b4c6b3d4","impliedFormat":1},{"version":"caaf6bf4dd0a3f88b50670f5786141b209edb54ba17eb6268c2d28919c813606","affectsGlobalScope":true,"impliedFormat":1}],"root":[168],"options":{"composite":true,"module":1,"outDir":"./","rootDir":"../src","sourceMap":true,"strict":true,"target":7,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[169,1],[53,2],[54,2],[55,3],[51,4],[56,5],[57,6],[58,7],[49,8],[47,1],[48,1],[59,9],[60,10],[61,11],[62,12],[63,13],[64,14],[65,14],[66,15],[67,16],[68,17],[69,18],[70,19],[52,1],[50,1],[71,20],[72,21],[73,22],[103,23],[74,24],[75,25],[76,26],[77,27],[78,28],[79,29],[80,30],[81,31],[82,32],[83,33],[84,34],[85,35],[87,36],[86,37],[88,38],[89,39],[90,1],[91,40],[92,41],[93,42],[94,43],[95,44],[96,45],[97,46],[98,47],[99,48],[100,49],[101,50],[102,51],[194,52],[195,53],[170,54],[173,54],[192,52],[193,52],[183,52],[182,55],[180,52],[175,52],[188,52],[186,52],[190,52],[174,52],[187,52],[191,52],[176,52],[177,52],[189,52],[171,52],[178,52],[179,52],[181,52],[185,52],[196,56],[184,52],[172,52],[209,57],[208,1],[203,56],[205,58],[204,56],[197,56],[198,56],[200,56],[202,56],[206,58],[207,58],[199,58],[201,58],[210,1],[44,1],[45,1],[9,1],[8,1],[2,1],[10,1],[11,1],[12,1],[13,1],[14,1],[15,1],[16,1],[17,1],[3,1],[18,1],[19,1],[4,1],[20,1],[24,1],[21,1],[22,1],[23,1],[25,1],[26,1],[27,1],[5,1],[28,1],[29,1],[30,1],[31,1],[6,1],[35,1],[32,1],[33,1],[34,1],[36,1],[7,1],[37,1],[42,1],[43,1],[38,1],[39,1],[40,1],[41,1],[1,1],[118,59],[110,60],[115,61],[108,1],[111,62],[109,63],[107,1],[117,64],[113,65],[106,1],[114,66],[112,67],[116,68],[160,69],[161,70],[105,1],[142,71],[141,72],[119,73],[129,74],[124,74],[123,75],[140,76],[126,74],[138,74],[133,75],[125,74],[120,74],[137,74],[136,74],[132,74],[134,77],[139,78],[128,75],[127,74],[130,74],[131,75],[121,74],[135,74],[122,75],[162,79],[163,80],[167,1],[104,1],[164,81],[146,82],[144,82],[154,82],[149,82],[153,82],[152,82],[150,82],[157,82],[156,83],[143,82],[147,82],[158,84],[148,82],[155,85],[151,82],[145,82],[159,1],[165,86],[166,87],[46,1],[168,88]],"latestChangedDtsFile":"./server.d.ts","version":"5.7.3"} \ No newline at end of file diff --git a/extension/server/out/server.d.ts b/extension/server/out/server.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/extension/server/out/server.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/extension/server/out/server.js b/extension/server/out/server.js new file mode 100644 index 0000000..527af30 --- /dev/null +++ b/extension/server/out/server.js @@ -0,0 +1,223 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const node_1 = require("vscode-languageserver/node"); +const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); +// Create a connection for the server +const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all); +// Create a text document manager +const documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument); +// Blueprint template +const blueprintTemplate = `page { + title { "$1" } + description { "$2" } + keywords { "$3" } + author { "$4" } +} + +navbar { + horizontal { + link(href:$5) { text(bold) { "$6" } } + links { + link(href:$7) { "$8" } + link(href:$9) { "$10" } + link(href:$11) { "$12" } + } + } +} + +horizontal(centered) { + vertical(centered) { + title(huge,margin:0) { "$13" } + text(subtle,margin:0) { "$14" } + } +}`; +// Blueprint elements that can be used +const elements = [ + 'section', 'grid', 'horizontal', 'vertical', 'title', 'text', + 'link', 'links', 'button', 'button-light', 'button-secondary', 'button-compact', + 'card', 'badge', 'alert', 'tooltip', 'input', 'textarea', 'select', + 'checkbox', 'radio', 'switch', 'list', 'table', 'progress', 'slider' +]; +// Single instance elements +const singleElements = ['page', 'navbar']; +// Blueprint properties +const properties = [ + 'wide', 'centered', 'alternate', 'padding', 'margin', 'columns', 'responsive', + 'gap', 'spaced', 'huge', 'large', 'small', 'tiny', 'bold', 'light', 'normal', + 'italic', 'underline', 'strike', 'uppercase', 'lowercase', 'capitalize', + 'subtle', 'accent', 'error', 'success', 'warning', 'hover-scale', 'hover-raise', + 'hover-glow', 'hover-underline', 'hover-fade', 'focus-glow', 'focus-outline', + 'focus-scale', 'active-scale', 'active-color', 'active-raise', 'mobile-stack', + 'mobile-hide', 'tablet-wrap', 'tablet-hide', 'desktop-wide', 'desktop-hide' +]; +// Page configuration properties +const pageProperties = ['title', 'description', 'keywords', 'author']; +// Container elements that can have children +const containerElements = [ + 'horizontal', 'vertical', 'section', 'grid', 'navbar', + 'links', 'card' +]; +connection.onInitialize((params) => { + const result = { + capabilities: { + textDocumentSync: node_1.TextDocumentSyncKind.Incremental, + completionProvider: { + resolveProvider: false, + triggerCharacters: ['{', '(', ' ', '!'] + } + } + }; + return result; +}); +// Check if an element exists in the document +function elementExists(text, element) { + const regex = new RegExp(`\\b${element}\\s*{`, 'i'); + return regex.test(text); +} +// This handler provides the initial list of completion items. +connection.onCompletion((textDocumentPosition) => { + const document = documents.get(textDocumentPosition.textDocument.uri); + if (!document) { + return []; + } + const text = document.getText(); + const lines = text.split('\n'); + const position = textDocumentPosition.position; + const line = lines[position.line]; + const linePrefix = line.slice(0, position.character); + // Check if this is a template completion trigger + if (linePrefix.trim() === '!') { + return [{ + label: '!blueprint', + kind: node_1.CompletionItemKind.Snippet, + insertText: blueprintTemplate, + insertTextFormat: node_1.InsertTextFormat.Snippet, + documentation: 'Insert Blueprint starter template with customizable placeholders', + preselect: true, + // Add a command to delete the '!' character + additionalTextEdits: [{ + range: { + start: { line: position.line, character: linePrefix.indexOf('!') }, + end: { line: position.line, character: linePrefix.indexOf('!') + 1 } + }, + newText: '' + }] + }]; + } + // Inside page block + if (text.includes('page {') && !text.includes('}')) { + return pageProperties.map(prop => ({ + label: prop, + kind: node_1.CompletionItemKind.Property, + insertText: `${prop} { "$1" }`, + insertTextFormat: node_1.InsertTextFormat.Snippet, + documentation: `Add ${prop} to the page configuration` + })); + } + // After an opening parenthesis, suggest properties + if (linePrefix.trim().endsWith('(')) { + return properties.map(prop => ({ + label: prop, + kind: node_1.CompletionItemKind.Property, + documentation: `Apply ${prop} property` + })); + } + // After a container element's opening brace, suggest child elements + const containerMatch = /\b(horizontal|vertical|section|grid|navbar|links|card)\s*{\s*$/.exec(linePrefix); + if (containerMatch) { + const parentElement = containerMatch[1]; + let suggestedElements = elements; + // Customize suggestions based on parent element + switch (parentElement) { + case 'navbar': + suggestedElements = ['horizontal', 'vertical', 'link', 'links', 'text']; + break; + case 'links': + suggestedElements = ['link']; + break; + case 'card': + suggestedElements = ['title', 'text', 'button', 'image']; + break; + } + return suggestedElements.map(element => ({ + label: element, + kind: node_1.CompletionItemKind.Class, + insertText: `${element} {\n $1\n}`, + insertTextFormat: node_1.InsertTextFormat.Snippet, + documentation: `Create a ${element} block inside ${parentElement}` + })); + } + // Get available single instance elements + const availableSingleElements = singleElements.filter(element => !elementExists(text, element)); + // Combine regular elements with available single instance elements + const availableElements = [ + ...elements, + ...availableSingleElements + ]; + // Default: suggest elements + return availableElements.map(element => { + const isPage = element === 'page'; + const insertText = isPage ? + 'page {\n title { "$1" }\n description { "$2" }\n keywords { "$3" }\n author { "$4" }\n}' : + `${element} {\n $1\n}`; + return { + label: element, + kind: node_1.CompletionItemKind.Class, + insertText: insertText, + insertTextFormat: node_1.InsertTextFormat.Snippet, + documentation: `Create a ${element} block${isPage ? ' (only one allowed per file)' : ''}` + }; + }); +}); +// Find all occurrences of an element in the document +function findElementOccurrences(text, element) { + const occurrences = []; + const lines = text.split('\n'); + const regex = new RegExp(`\\b(${element})\\s*{`, 'g'); + lines.forEach((line, lineIndex) => { + let match; + while ((match = regex.exec(line)) !== null) { + const startChar = match.index; + const endChar = match.index + match[1].length; + occurrences.push({ + start: { line: lineIndex, character: startChar }, + end: { line: lineIndex, character: endChar } + }); + } + }); + return occurrences; +} +// Validate the document for duplicate elements +function validateDocument(document) { + const text = document.getText(); + const diagnostics = []; + // Check for duplicate single instance elements + singleElements.forEach(element => { + const occurrences = findElementOccurrences(text, element); + if (occurrences.length > 1) { + // Add diagnostic for each duplicate occurrence (skip the first one) + occurrences.slice(1).forEach(occurrence => { + diagnostics.push({ + severity: node_1.DiagnosticSeverity.Error, + range: node_1.Range.create(occurrence.start, occurrence.end), + message: `Only one ${element} element is allowed per file.`, + source: 'blueprint' + }); + }); + } + }); + // Send the diagnostics to the client + connection.sendDiagnostics({ uri: document.uri, diagnostics }); +} +// Set up document validation events +documents.onDidChangeContent((change) => { + validateDocument(change.document); +}); +documents.onDidOpen((event) => { + validateDocument(event.document); +}); +// Make the text document manager listen on the connection +documents.listen(connection); +// Listen on the connection +connection.listen(); +//# sourceMappingURL=server.js.map \ No newline at end of file diff --git a/extension/server/out/server.js.map b/extension/server/out/server.js.map new file mode 100644 index 0000000..383896b --- /dev/null +++ b/extension/server/out/server.js.map @@ -0,0 +1 @@ +{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;AAAA,qDAgBoC;AAEpC,2FAAkE;AAElE,qCAAqC;AACrC,MAAM,UAAU,GAAG,IAAA,uBAAgB,EAAC,uBAAgB,CAAC,GAAG,CAAC,CAAC;AAE1D,iCAAiC;AACjC,MAAM,SAAS,GAAgC,IAAI,oBAAa,CAAC,iDAAY,CAAC,CAAC;AAE/E,qBAAqB;AACrB,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;EAuBxB,CAAC;AAEH,sCAAsC;AACtC,MAAM,QAAQ,GAAG;IACb,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM;IAC5D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB;IAC/E,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ;IAClE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ;CACvE,CAAC;AAEF,2BAA2B;AAC3B,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAE1C,uBAAuB;AACvB,MAAM,UAAU,GAAG;IACf,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY;IAC7E,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;IAC5E,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY;IACvE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa;IAC/E,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe;IAC5E,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc;IAC7E,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc;CAC9E,CAAC;AAEF,gCAAgC;AAChC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAEtE,4CAA4C;AAC5C,MAAM,iBAAiB,GAAG;IACtB,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ;IACrD,OAAO,EAAE,MAAM;CAClB,CAAC;AAEF,UAAU,CAAC,YAAY,CAAC,CAAC,MAAwB,EAAE,EAAE;IACjD,MAAM,MAAM,GAAqB;QAC7B,YAAY,EAAE;YACV,gBAAgB,EAAE,2BAAoB,CAAC,WAAW;YAClD,kBAAkB,EAAE;gBAChB,eAAe,EAAE,KAAK;gBACtB,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;aAC1C;SACJ;KACJ,CAAC;IACF,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,6CAA6C;AAC7C,SAAS,aAAa,CAAC,IAAY,EAAE,OAAe;IAChD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,OAAO,OAAO,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,8DAA8D;AAC9D,UAAU,CAAC,YAAY,CACnB,CAAC,oBAAgD,EAAoB,EAAE;IACnE,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,oBAAoB,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACtE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,QAAQ,CAAC;IAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAErD,iDAAiD;IACjD,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;QAC5B,OAAO,CAAC;gBACJ,KAAK,EAAE,YAAY;gBACnB,IAAI,EAAE,yBAAkB,CAAC,OAAO;gBAChC,UAAU,EAAE,iBAAiB;gBAC7B,gBAAgB,EAAE,uBAAgB,CAAC,OAAO;gBAC1C,aAAa,EAAE,kEAAkE;gBACjF,SAAS,EAAE,IAAI;gBACf,4CAA4C;gBAC5C,mBAAmB,EAAE,CAAC;wBAClB,KAAK,EAAE;4BACH,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;4BAClE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;yBACvE;wBACD,OAAO,EAAE,EAAE;qBACd,CAAC;aACL,CAAC,CAAC;IACP,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/B,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,yBAAkB,CAAC,QAAQ;YACjC,UAAU,EAAE,GAAG,IAAI,WAAW;YAC9B,gBAAgB,EAAE,uBAAgB,CAAC,OAAO;YAC1C,aAAa,EAAE,OAAO,IAAI,4BAA4B;SACzD,CAAC,CAAC,CAAC;IACR,CAAC;IAED,mDAAmD;IACnD,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3B,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,yBAAkB,CAAC,QAAQ;YACjC,aAAa,EAAE,SAAS,IAAI,WAAW;SAC1C,CAAC,CAAC,CAAC;IACR,CAAC;IAED,oEAAoE;IACpE,MAAM,cAAc,GAAG,gEAAgE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzG,IAAI,cAAc,EAAE,CAAC;QACjB,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACxC,IAAI,iBAAiB,GAAG,QAAQ,CAAC;QAEjC,gDAAgD;QAChD,QAAQ,aAAa,EAAE,CAAC;YACpB,KAAK,QAAQ;gBACT,iBAAiB,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;gBACxE,MAAM;YACV,KAAK,OAAO;gBACR,iBAAiB,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC7B,MAAM;YACV,KAAK,MAAM;gBACP,iBAAiB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACzD,MAAM;QACd,CAAC;QAED,OAAO,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACrC,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,yBAAkB,CAAC,KAAK;YAC9B,UAAU,EAAE,GAAG,OAAO,eAAe;YACrC,gBAAgB,EAAE,uBAAgB,CAAC,OAAO;YAC1C,aAAa,EAAE,YAAY,OAAO,iBAAiB,aAAa,EAAE;SACrE,CAAC,CAAC,CAAC;IACR,CAAC;IAED,yCAAyC;IACzC,MAAM,uBAAuB,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAEhG,mEAAmE;IACnE,MAAM,iBAAiB,GAAG;QACtB,GAAG,QAAQ;QACX,GAAG,uBAAuB;KAC7B,CAAC;IAEF,4BAA4B;IAC5B,OAAO,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;QACnC,MAAM,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;QAClC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC;YACvB,qGAAqG,CAAC,CAAC;YACvG,GAAG,OAAO,eAAe,CAAC;QAE9B,OAAO;YACH,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,yBAAkB,CAAC,KAAK;YAC9B,UAAU,EAAE,UAAU;YACtB,gBAAgB,EAAE,uBAAgB,CAAC,OAAO;YAC1C,aAAa,EAAE,YAAY,OAAO,SAAS,MAAM,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,EAAE,EAAE;SAC5F,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CACJ,CAAC;AAEF,qDAAqD;AACrD,SAAS,sBAAsB,CAAC,IAAY,EAAE,OAAe;IACzD,MAAM,WAAW,GAA0C,EAAE,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,OAAO,QAAQ,EAAE,GAAG,CAAC,CAAC;IAEtD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QAC9B,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;YAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAC9C,WAAW,CAAC,IAAI,CAAC;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE;gBAChD,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE;aAC/C,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACvB,CAAC;AAED,+CAA+C;AAC/C,SAAS,gBAAgB,CAAC,QAAsB;IAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,+CAA+C;IAC/C,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC7B,MAAM,WAAW,GAAG,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,oEAAoE;YACpE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;gBACtC,WAAW,CAAC,IAAI,CAAC;oBACb,QAAQ,EAAE,yBAAkB,CAAC,KAAK;oBAClC,KAAK,EAAE,YAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC;oBACrD,OAAO,EAAE,YAAY,OAAO,+BAA+B;oBAC3D,MAAM,EAAE,WAAW;iBACtB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,qCAAqC;IACrC,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,oCAAoC;AACpC,SAAS,CAAC,kBAAkB,CAAC,CAAC,MAA6C,EAAE,EAAE;IAC3E,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,SAAS,CAAC,CAAC,KAA4C,EAAE,EAAE;IACjE,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,0DAA0D;AAC1D,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAE7B,2BAA2B;AAC3B,UAAU,CAAC,MAAM,EAAE,CAAC"} \ No newline at end of file diff --git a/extension/server/src/server.ts b/extension/server/src/server.ts new file mode 100644 index 0000000..2eb0f5f --- /dev/null +++ b/extension/server/src/server.ts @@ -0,0 +1,271 @@ +import { + createConnection, + TextDocuments, + ProposedFeatures, + InitializeParams, + TextDocumentSyncKind, + InitializeResult, + CompletionItem, + CompletionItemKind, + TextDocumentPositionParams, + InsertTextFormat, + Diagnostic, + DiagnosticSeverity, + Position, + Range, + TextDocumentChangeEvent +} from 'vscode-languageserver/node'; + +import { TextDocument } from 'vscode-languageserver-textdocument'; + +// Create a connection for the server +const connection = createConnection(ProposedFeatures.all); + +// Create a text document manager +const documents: TextDocuments = new TextDocuments(TextDocument); + +// Blueprint template +const blueprintTemplate = `page { + title { "$1" } + description { "$2" } + keywords { "$3" } + author { "$4" } +} + +navbar { + horizontal { + link(href:$5) { text(bold) { "$6" } } + links { + link(href:$7) { "$8" } + link(href:$9) { "$10" } + link(href:$11) { "$12" } + } + } +} + +horizontal(centered) { + vertical(centered) { + title(huge,margin:0) { "$13" } + text(subtle,margin:0) { "$14" } + } +}`; + +// Blueprint elements that can be used +const elements = [ + 'section', 'grid', 'horizontal', 'vertical', 'title', 'text', + 'link', 'links', 'button', 'button-light', 'button-secondary', 'button-compact', + 'card', 'badge', 'alert', 'tooltip', 'input', 'textarea', 'select', + 'checkbox', 'radio', 'switch', 'list', 'table', 'progress', 'slider' +]; + +// Single instance elements +const singleElements = ['page', 'navbar']; + +// Blueprint properties +const properties = [ + 'wide', 'centered', 'alternate', 'padding', 'margin', 'columns', 'responsive', + 'gap', 'spaced', 'huge', 'large', 'small', 'tiny', 'bold', 'light', 'normal', + 'italic', 'underline', 'strike', 'uppercase', 'lowercase', 'capitalize', + 'subtle', 'accent', 'error', 'success', 'warning', 'hover-scale', 'hover-raise', + 'hover-glow', 'hover-underline', 'hover-fade', 'focus-glow', 'focus-outline', + 'focus-scale', 'active-scale', 'active-color', 'active-raise', 'mobile-stack', + 'mobile-hide', 'tablet-wrap', 'tablet-hide', 'desktop-wide', 'desktop-hide' +]; + +// Page configuration properties +const pageProperties = ['title', 'description', 'keywords', 'author']; + +// Container elements that can have children +const containerElements = [ + 'horizontal', 'vertical', 'section', 'grid', 'navbar', + 'links', 'card' +]; + +connection.onInitialize((params: InitializeParams) => { + const result: InitializeResult = { + capabilities: { + textDocumentSync: TextDocumentSyncKind.Incremental, + completionProvider: { + resolveProvider: false, + triggerCharacters: ['{', '(', ' ', '!'] + } + } + }; + return result; +}); + +// Check if an element exists in the document +function elementExists(text: string, element: string): boolean { + const regex = new RegExp(`\\b${element}\\s*{`, 'i'); + return regex.test(text); +} + +// This handler provides the initial list of completion items. +connection.onCompletion( + (textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => { + const document = documents.get(textDocumentPosition.textDocument.uri); + if (!document) { + return []; + } + + const text = document.getText(); + const lines = text.split('\n'); + const position = textDocumentPosition.position; + const line = lines[position.line]; + const linePrefix = line.slice(0, position.character); + + // Check if this is a template completion trigger + if (linePrefix.trim() === '!') { + return [{ + label: '!blueprint', + kind: CompletionItemKind.Snippet, + insertText: blueprintTemplate, + insertTextFormat: InsertTextFormat.Snippet, + documentation: 'Insert Blueprint starter template with customizable placeholders', + preselect: true, + // Add a command to delete the '!' character + additionalTextEdits: [{ + range: { + start: { line: position.line, character: linePrefix.indexOf('!') }, + end: { line: position.line, character: linePrefix.indexOf('!') + 1 } + }, + newText: '' + }] + }]; + } + + // Inside page block + if (text.includes('page {') && !text.includes('}')) { + return pageProperties.map(prop => ({ + label: prop, + kind: CompletionItemKind.Property, + insertText: `${prop} { "$1" }`, + insertTextFormat: InsertTextFormat.Snippet, + documentation: `Add ${prop} to the page configuration` + })); + } + + // After an opening parenthesis, suggest properties + if (linePrefix.trim().endsWith('(')) { + return properties.map(prop => ({ + label: prop, + kind: CompletionItemKind.Property, + documentation: `Apply ${prop} property` + })); + } + + // After a container element's opening brace, suggest child elements + const containerMatch = /\b(horizontal|vertical|section|grid|navbar|links|card)\s*{\s*$/.exec(linePrefix); + if (containerMatch) { + const parentElement = containerMatch[1]; + let suggestedElements = elements; + + // Customize suggestions based on parent element + switch (parentElement) { + case 'navbar': + suggestedElements = ['horizontal', 'vertical', 'link', 'links', 'text']; + break; + case 'links': + suggestedElements = ['link']; + break; + case 'card': + suggestedElements = ['title', 'text', 'button', 'image']; + break; + } + + return suggestedElements.map(element => ({ + label: element, + kind: CompletionItemKind.Class, + insertText: `${element} {\n $1\n}`, + insertTextFormat: InsertTextFormat.Snippet, + documentation: `Create a ${element} block inside ${parentElement}` + })); + } + + // Get available single instance elements + const availableSingleElements = singleElements.filter(element => !elementExists(text, element)); + + // Combine regular elements with available single instance elements + const availableElements = [ + ...elements, + ...availableSingleElements + ]; + + // Default: suggest elements + return availableElements.map(element => { + const isPage = element === 'page'; + const insertText = isPage ? + 'page {\n title { "$1" }\n description { "$2" }\n keywords { "$3" }\n author { "$4" }\n}' : + `${element} {\n $1\n}`; + + return { + label: element, + kind: CompletionItemKind.Class, + insertText: insertText, + insertTextFormat: InsertTextFormat.Snippet, + documentation: `Create a ${element} block${isPage ? ' (only one allowed per file)' : ''}` + }; + }); + } +); + +// Find all occurrences of an element in the document +function findElementOccurrences(text: string, element: string): { start: Position; end: Position; }[] { + const occurrences: { start: Position; end: Position; }[] = []; + const lines = text.split('\n'); + const regex = new RegExp(`\\b(${element})\\s*{`, 'g'); + + lines.forEach((line, lineIndex) => { + let match; + while ((match = regex.exec(line)) !== null) { + const startChar = match.index; + const endChar = match.index + match[1].length; + occurrences.push({ + start: { line: lineIndex, character: startChar }, + end: { line: lineIndex, character: endChar } + }); + } + }); + + return occurrences; +} + +// Validate the document for duplicate elements +function validateDocument(document: TextDocument): void { + const text = document.getText(); + const diagnostics: Diagnostic[] = []; + + // Check for duplicate single instance elements + singleElements.forEach(element => { + const occurrences = findElementOccurrences(text, element); + if (occurrences.length > 1) { + // Add diagnostic for each duplicate occurrence (skip the first one) + occurrences.slice(1).forEach(occurrence => { + diagnostics.push({ + severity: DiagnosticSeverity.Error, + range: Range.create(occurrence.start, occurrence.end), + message: `Only one ${element} element is allowed per file.`, + source: 'blueprint' + }); + }); + } + }); + + // Send the diagnostics to the client + connection.sendDiagnostics({ uri: document.uri, diagnostics }); +} + +// Set up document validation events +documents.onDidChangeContent((change: TextDocumentChangeEvent) => { + validateDocument(change.document); +}); + +documents.onDidOpen((event: TextDocumentChangeEvent) => { + validateDocument(event.document); +}); + +// Make the text document manager listen on the connection +documents.listen(connection); + +// Listen on the connection +connection.listen(); \ No newline at end of file diff --git a/extension/server/tsconfig.json b/extension/server/tsconfig.json new file mode 100644 index 0000000..7ec5113 --- /dev/null +++ b/extension/server/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "strict": true, + "outDir": "out", + "rootDir": "src", + "composite": true, + "tsBuildInfoFile": "./out/.tsbuildinfo" + }, + "include": ["src"], + "exclude": ["node_modules", ".vscode-test"] +} \ No newline at end of file diff --git a/extension/syntaxes/blueprint.tmLanguage.json b/extension/syntaxes/blueprint.tmLanguage.json new file mode 100644 index 0000000..4071964 --- /dev/null +++ b/extension/syntaxes/blueprint.tmLanguage.json @@ -0,0 +1,136 @@ +{ + "name": "Blueprint", + "scopeName": "source.blueprint", + "fileTypes": ["bp"], + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#page-config" + }, + { + "include": "#elements" + }, + { + "include": "#properties" + }, + { + "include": "#strings" + }, + { + "include": "#punctuation" + } + ], + "repository": { + "comments": { + "match": "//.*$", + "name": "comment.line.double-slash.blueprint" + }, + "page-config": { + "begin": "\\b(page)\\b", + "end": "(?=})", + "beginCaptures": { + "1": { "name": "entity.name.tag.blueprint" } + }, + "patterns": [ + { + "begin": "\\b(description|keywords|author)\\b\\s*\\{", + "end": "\\}", + "beginCaptures": { + "1": { "name": "entity.name.tag.blueprint" } + }, + "patterns": [ + { "include": "#strings" } + ] + }, + { + "begin": "\\b(title)\\b\\s*\\{", + "end": "\\}", + "beginCaptures": { + "1": { "name": "entity.name.tag.title.blueprint" } + }, + "patterns": [ + { "include": "#strings" } + ] + } + ] + }, + "elements": { + "patterns": [ + { + "match": "\\b(section|grid|horizontal|vertical|navbar|title|text|link|links|button|button-light|button-secondary|button-compact|card|badge|alert|tooltip|input|textarea|select|checkbox|radio|switch|list|table|progress|slider|media)\\b", + "name": "entity.name.tag.blueprint" + } + ] + }, + "properties": { + "patterns": [ + { + "match": "\\b(wide|centered|alternate|padding|margin|columns|responsive|gap|spaced|huge|large|small|tiny|bold|light|normal|italic|underline|strike|uppercase|lowercase|capitalize|subtle|accent|error|success|warning|hover-scale|hover-raise|hover-glow|hover-underline|hover-fade|focus-glow|focus-outline|focus-scale|active-scale|active-color|active-raise|mobile-stack|mobile-hide|tablet-wrap|tablet-hide|desktop-wide|desktop-hide)\\b", + "name": "support.type.property-name.blueprint" + }, + { + "match": "(? { + const seen = new WeakSet(); + return (key, value) => { + if (key === "parent") return "[Circular:Parent]"; + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return "[Circular]"; + } + seen.add(value); + } + return value; + }; + }; + + try { + return JSON.stringify(node, getCircularReplacer(), 2); + } catch (err) { + return `[Unable to stringify: ${err.message}]`; + } + } + + /** + * Constructs an Abstract Syntax Tree (AST) from a sequence of tokens. + * + * This function iterates over the provided tokens to build a hierarchical + * AST structure. It identifies elements, their properties, and any nested + * child elements, converting them into structured nodes. Each node is + * represented as an object containing type, tag, properties, children, + * and position information (line and column). + * + * Throws an error if unexpected tokens are encountered or if there are + * mismatched braces. + * + * @param {Array} tokens - The list of tokens to be parsed into an AST. + * @returns {Object} - The constructed AST root node with its children. + * Each child represents either an element or text node. + * @throws {BlueprintError} - If unexpected tokens or structural issues are found. + */ + + buildAST(tokens) { + if (this.options.debug) { + console.log("\n[ASTBuilder] Starting AST construction"); + console.log(`[ASTBuilder] Processing ${tokens.length} tokens`); + console.log( + "[ASTBuilder] First few tokens:", + tokens + .slice(0, 3) + .map((t) => this.debugStringify(t)) + .join(", ") + ); + } + + let current = 0; + + /** + * Walks the token list to construct a hierarchical AST structure. + * + * This function is responsible for processing each token and constructing + * the corresponding node in the AST. It handles elements, their properties, + * and any nested child elements, converting them into structured nodes. + * Each node is represented as an object containing type, tag, properties, + * children, and position information (line and column). + * + * Throws an error if unexpected tokens are encountered or if there are + * mismatched braces. + * + * @returns {Object} - The constructed AST node with its children. + * Each child represents either an element or text node. + * @throws {BlueprintError} - If unexpected tokens or structural issues are found. + */ + const walk = () => { + if (this.options.debug) { + console.log( + `\n[ASTBuilder] Walking tokens at position ${current}/${tokens.length}` + ); + console.log( + "[ASTBuilder] Current token:", + this.debugStringify(tokens[current]) + ); + } + + let token = tokens[current]; + + if (!token) { + if (this.options.debug) { + console.log( + "[ASTBuilder] Unexpected end of input while walking tokens" + ); + console.log( + "[ASTBuilder] Last processed token:", + this.debugStringify(tokens[current - 1]) + ); + } + throw new BlueprintError( + "Unexpected end of input", + tokens[tokens.length - 1]?.line || 1, + tokens[tokens.length - 1]?.column || 0 + ); + } + + if (token.type === "identifier") { + if (this.options.debug) { + console.log( + `\n[ASTBuilder] Processing identifier: "${token.value}" at line ${token.line}, column ${token.column}` + ); + } + + const elementType = token.value; + if (!ELEMENT_MAPPINGS[elementType]) { + if (this.options.debug) { + console.log( + `[ASTBuilder] Error: Unknown element type "${elementType}"` + ); + console.log( + "[ASTBuilder] Available element types:", + Object.keys(ELEMENT_MAPPINGS).join(", ") + ); + } + throw new BlueprintError( + `Unknown element type: ${elementType}`, + token.line, + token.column + ); + } + + const mapping = ELEMENT_MAPPINGS[elementType]; + const node = { + type: "element", + tag: elementType, + props: + elementType === "page" ? [] : [...(mapping.defaultProps || [])], + children: [], + line: token.line, + column: token.column, + }; + + if (this.options.debug) { + console.log(`[ASTBuilder] Created node for element "${elementType}"`); + console.log( + "[ASTBuilder] Initial node state:", + this.debugStringify(node) + ); + } + + current++; + + if ( + current < tokens.length && + tokens[current].type === "props" + ) { + const props = tokens[current].value.split(",").map((p) => p.trim()); + if (this.options.debug) { + console.log( + `[ASTBuilder] Processing ${props.length} properties for "${elementType}"` + ); + console.log("[ASTBuilder] Properties:", props); + } + + props.forEach((prop) => { + const [name, ...valueParts] = prop.split(":"); + const value = valueParts.join(":").trim(); + if (this.options.debug) { + console.log( + `[ASTBuilder] Processing property - name: "${name}", value: "${value}"` + ); + } + + if (value) { + if (elementType === "page") { + const processedProp = { + name, + value: value.replace(/^"|"$/g, ""), + }; + node.props.push(processedProp); + if (this.options.debug) { + console.log( + `[ASTBuilder] Added page property:`, + processedProp + ); + } + } else { + node.props.push(`${name}:${value}`); + if (this.options.debug) { + console.log( + `[ASTBuilder] Added property: "${name}:${value}"` + ); + } + } + } else { + node.props.push(name); + if (this.options.debug) { + console.log(`[ASTBuilder] Added flag property: "${name}"`); + } + } + }); + current++; + } + + if ( + current < tokens.length && + tokens[current].type === "brace" && + tokens[current].value === "{" + ) { + if (this.options.debug) { + console.log( + `\n[ASTBuilder] Processing child elements for "${elementType}"` + ); + } + current++; + + while ( + current < tokens.length && + !(tokens[current].type === "brace" && tokens[current].value === "}") + ) { + if (this.options.debug) { + console.log( + `[ASTBuilder] Processing child at position ${current}` + ); + } + const child = walk(); + child.parent = node; + node.children.push(child); + if (this.options.debug) { + console.log( + `[ASTBuilder] Added child to "${elementType}":`, + this.debugStringify(child) + ); + } + } + + if (current >= tokens.length) { + if (this.options.debug) { + console.log( + `[ASTBuilder] Error: Missing closing brace for "${elementType}"` + ); + } + throw new BlueprintError( + "Missing closing brace", + node.line, + node.column + ); + } + + current++; + } + + if (this.options.debug) { + console.log(`[ASTBuilder] Completed node for "${elementType}"`); + console.log( + "[ASTBuilder] Final node state:", + this.debugStringify(node) + ); + } + + return node; + } + + if (token.type === "text") { + if (this.options.debug) { + console.log( + `[ASTBuilder] Processing text node at line ${token.line}, column ${token.column}` + ); + console.log(`[ASTBuilder] Text content: "${token.value}"`); + } + current++; + return { + type: "text", + value: token.value, + line: token.line, + column: token.column, + }; + } + + if (this.options.debug) { + console.log(`[ASTBuilder] Error: Unexpected token type: ${token.type}`); + console.log("[ASTBuilder] Token details:", this.debugStringify(token)); + } + throw new BlueprintError( + `Unexpected token type: ${token.type}`, + token.line, + token.column + ); + }; + + const ast = { + type: "root", + children: [], + }; + + while (current < tokens.length) { + if (this.options.debug) { + console.log( + `\n[ASTBuilder] Processing root-level token at position ${current}` + ); + } + ast.children.push(walk()); + } + + if (this.options.debug) { + console.log("\n[ASTBuilder] AST construction complete"); + console.log(`[ASTBuilder] Total nodes: ${ast.children.length}`); + console.log( + "[ASTBuilder] Root children types:", + ast.children.map((c) => c.type).join(", ") + ); + } + + return ast; + } +} + +module.exports = ASTBuilder; diff --git a/lib/BlueprintBuilder.js b/lib/BlueprintBuilder.js new file mode 100644 index 0000000..6342d73 --- /dev/null +++ b/lib/BlueprintBuilder.js @@ -0,0 +1,144 @@ +const fs = require("fs"); +const path = require("path"); +const TokenParser = require("./TokenParser"); +const ASTBuilder = require("./ASTBuilder"); +const CSSGenerator = require("./CSSGenerator"); +const HTMLGenerator = require("./HTMLGenerator"); +const MetadataManager = require("./MetadataManager"); + +class BlueprintBuilder { + /** + * Create a new Blueprint builder instance. + * @param {Object} [options] - Options object + * @param {boolean} [options.minified=true] - Minify generated HTML and CSS + * @param {boolean} [options.debug=false] - Enable debug logging + */ + constructor(options = {}) { + this.options = { + minified: true, + debug: false, + ...options, + }; + + this.tokenParser = new TokenParser(this.options); + this.astBuilder = new ASTBuilder(this.options); + this.cssGenerator = new CSSGenerator(this.options); + this.htmlGenerator = new HTMLGenerator(this.options, this.cssGenerator); + this.metadataManager = new MetadataManager(this.options); + } + + + /** + * Builds a Blueprint file. + * @param {string} inputPath - Path to the Blueprint file to build + * @param {string} outputDir - Directory to write the generated HTML and CSS files + * @returns {Object} - Build result object with `success` and `errors` properties + */ + build(inputPath, outputDir) { + if (this.options.debug) { + console.log(`[DEBUG] Starting build for ${inputPath}`); + } + + try { + if (!inputPath.endsWith(".bp")) { + throw new Error("Input file must have .bp extension"); + } + + const input = fs.readFileSync(inputPath, "utf8"); + + const tokens = this.tokenParser.tokenize(input); + + const ast = this.astBuilder.buildAST(tokens); + + const pageNode = ast.children.find((node) => node.tag === "page"); + if (pageNode) { + this.metadataManager.processPageMetadata(pageNode); + } + + const html = this.htmlGenerator.generateHTML(ast); + const css = this.cssGenerator.generateCSS(); + + const baseName = path.basename(inputPath, ".bp"); + const headContent = this.metadataManager.generateHeadContent(baseName); + const finalHtml = this.generateFinalHtml(headContent, html); + + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + fs.writeFileSync(path.join(outputDir, `${baseName}.html`), finalHtml); + fs.writeFileSync(path.join(outputDir, `${baseName}.css`), css); + + if (this.options.debug) { + console.log("[DEBUG] Build completed successfully"); + } + + return { + success: true, + errors: [], + }; + } catch (error) { + if (this.options.debug) { + console.log("[DEBUG] Build failed with error:", error); + } + return { + success: false, + errors: [ + { + message: error.message, + type: error.name, + line: error.line, + column: error.column, + }, + ], + }; + } + } + +/** + * Generates the final HTML document as a string. + * + * @param {string} headContent - The HTML content to be placed within the tag. + * @param {string} bodyContent - The HTML content to be placed within the tag. + * @returns {string} - A complete HTML document containing the provided head and body content. + */ + + generateFinalHtml(headContent, bodyContent) { + return ` + + + + + ${headContent} + + + + ${bodyContent} + +`; + } +} + +module.exports = BlueprintBuilder; diff --git a/lib/BlueprintError.js b/lib/BlueprintError.js new file mode 100644 index 0000000..03acc00 --- /dev/null +++ b/lib/BlueprintError.js @@ -0,0 +1,10 @@ +class BlueprintError extends Error { + constructor(message, line = null, column = null) { + super(message); + this.name = "BlueprintError"; + this.line = line; + this.column = column; + } +} + +module.exports = BlueprintError; diff --git a/lib/CSSGenerator.js b/lib/CSSGenerator.js new file mode 100644 index 0000000..b950308 --- /dev/null +++ b/lib/CSSGenerator.js @@ -0,0 +1,402 @@ +const { STYLE_MAPPINGS } = require("./mappings"); + +class CSSGenerator { + /** + * Creates a new CSS generator instance. + * @param {Object} [options] - Options object + * @param {boolean} [options.minified=true] - Minify generated class names + * @param {boolean} [options.debug=false] - Enable debug logging + */ + constructor(options = {}) { + this.options = options; + this.cssRules = new Map(); + this.classCounter = 0; + if (this.options.debug) { + console.log( + "[CSSGenerator] Initialized with options:", + JSON.stringify(options, null, 2) + ); + } + } + + /** + * Generates a class name for the given element type, based on the counter + * and the minified option. If minified is true, the class name will be a + * single lowercase letter (a-z), or a single uppercase letter (A-Z) if + * the counter is between 26 and 51. Otherwise, it will be a complex + * class name (e.g. "zabcdefg") with a counter starting from 52. + * + * @param {string} elementType - The type of the element for which to + * generate a class name. + * @return {string} The generated class name. + */ + generateClassName(elementType) { + if (this.options.debug) { + console.log( + `\n[CSSGenerator] Generating class name for element type: "${elementType}"` + ); + console.log(`[CSSGenerator] Current class counter: ${this.classCounter}`); + } + + let className; + if (!this.options.minified) { + className = `blueprint-${elementType}-${this.classCounter++}`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Generated readable class name: "${className}"` + ); + } + return className; + } + + if (this.classCounter < 26) { + className = String.fromCharCode(97 + this.classCounter++); + if (this.options.debug) { + console.log( + `[CSSGenerator] Generated lowercase class name: "${className}" (counter: ${ + this.classCounter - 1 + })` + ); + } + return className; + } + + if (this.classCounter < 52) { + className = String.fromCharCode(65 + (this.classCounter++ - 26)); + if (this.options.debug) { + console.log( + `[CSSGenerator] Generated uppercase class name: "${className}" (counter: ${ + this.classCounter - 1 + })` + ); + } + return className; + } + + const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const base = chars.length; + let num = this.classCounter++ - 52; + let result = ""; + + do { + result = chars[num % base] + result; + num = Math.floor(num / base); + } while (num > 0); + + result = "z" + result; + + if (this.options.debug) { + console.log( + `[CSSGenerator] Generated complex class name: "${result}" (counter: ${ + this.classCounter - 1 + })` + ); + } + + return result; + } + + /** + * Converts a node to CSS properties, using the style mappings to process + * the node's properties. The generated CSS properties are returned as a + * Map, where each key is a CSS property name and each value is the value + * for that property. + * + * @param {Object} node - The node to convert + * @return {Object} - The generated CSS properties and nested rules + */ + nodeToCSSProperties(node) { + if (this.options.debug) { + console.log(`\n[CSSGenerator] Converting node to CSS properties`); + console.log(`[CSSGenerator] Node tag: "${node.tag}"`); + console.log("[CSSGenerator] Node properties:", node.props); + } + + const cssProps = new Map(); + const nestedRules = new Map(); + + node.props.forEach((prop) => { + if (typeof prop === "object") { + if (this.options.debug) { + console.log(`[CSSGenerator] Skipping object property:`, prop); + } + return; + } + + const [name, value] = prop.split(/[-:]/); + if (this.options.debug) { + console.log( + `\n[CSSGenerator] Processing property - name: "${name}", value: "${value}"` + ); + } + // This is for customization of css properties + + if (name === "width" && !isNaN(value)) { + cssProps.set("width", `${value}% !important`); + cssProps.set("max-width", "none !important"); + if (this.options.debug) { + console.log( + `[CSSGenerator] Set width: ${value}% !important and max-width: none !important` + ); + } + return; + } + + if (name === "height" && !isNaN(value)) { + cssProps.set("height", `${value}% !important`); + cssProps.set("max-height", "none !important"); + if (this.options.debug) { + console.log( + `[CSSGenerator] Set height: ${value}% !important and max-height: none !important` + ); + } + return; + } + + if (name === "padding" && !isNaN(value)) { + cssProps.set("padding", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set padding: ${value}px !important`); + } + return; + } + + if (name === "margin" && !isNaN(value)) { + cssProps.set("margin", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set margin: ${value}px !important`); + } + return; + } + + if (name === "marginTop" && !isNaN(value)) { + cssProps.set("margin-top", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set margin-top: ${value}px !important`); + } + return; + } + + if (name === "marginBottom" && !isNaN(value)) { + cssProps.set("margin-bottom", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set margin-bottom: ${value}px !important`); + } + return; + } + + if (name === "marginLeft" && !isNaN(value)) { + cssProps.set("margin-left", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set margin-left: ${value}px !important`); + } + return; + } + + if (name === "marginRight" && !isNaN(value)) { + cssProps.set("margin-right", `${value}px !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set margin-right: ${value}px !important`); + } + return; + } + + if (name === "color") { + cssProps.set("color", `${value} !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set color: ${value} !important`); + } + return; + } + + if (name === "backgroundColor") { + cssProps.set("background-color", `${value} !important`); + if (this.options.debug) { + console.log(`[CSSGenerator] Set background-color: ${value} !important`); + } + return; + } + + const style = STYLE_MAPPINGS[name]; + if (style) { + if (this.options.debug) { + console.log(`[CSSGenerator] Processing style mapping for: "${name}"`); + } + Object.entries(style).forEach(([key, baseValue]) => { + if (typeof baseValue === "object") { + if (key.startsWith(":") || key.startsWith(">")) { + nestedRules.set(key, baseValue); + if (this.options.debug) { + console.log( + `[CSSGenerator] Added nested rule: "${key}" =>`, + baseValue + ); + } + } else { + let finalValue = baseValue; + if (value && key === "gridTemplateColumns" && !isNaN(value)) { + finalValue = `repeat(${value}, 1fr)`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Set grid template columns: ${finalValue}` + ); + } + } + cssProps.set(key, finalValue); + if (this.options.debug) { + console.log( + `[CSSGenerator] Set CSS property: "${key}" = "${finalValue}"` + ); + } + } + } else { + let finalValue = baseValue; + if (value && key === "gridTemplateColumns" && !isNaN(value)) { + finalValue = `repeat(${value}, 1fr)`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Set grid template columns: ${finalValue}` + ); + } + } + cssProps.set(key, finalValue); + if (this.options.debug) { + console.log( + `[CSSGenerator] Set CSS property: "${key}" = "${finalValue}"` + ); + } + } + }); + } + }); + + if (this.options.debug) { + console.log("\n[CSSGenerator] CSS properties generation complete"); + console.log(`[CSSGenerator] Generated ${cssProps.size} CSS properties`); + console.log(`[CSSGenerator] Generated ${nestedRules.size} nested rules`); + } + + return { cssProps, nestedRules }; + } + +/** + * Generates the CSS code for the given style mappings. If minified is true, + * the generated CSS will be minified. Otherwise, it will be formatted with + * indentation and newlines. + * + * @return {string} The generated CSS code + */ + generateCSS() { + if (this.options.debug) { + console.log("\n[CSSGenerator] Starting CSS generation"); + console.log(`[CSSGenerator] Processing ${this.cssRules.size} rule sets`); + } + + /** + * Converts a camelCase string to kebab-case (lowercase with hyphens + * separating words) + * + * @param {string} str The string to convert + * @return {string} The converted string + */ + + const toKebabCase = (str) => + str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); + + let css = ""; + this.cssRules.forEach((props, selector) => { + if (props.cssProps.size > 0) { + if (this.options.debug) { + console.log( + `\n[CSSGenerator] Generating CSS for selector: "${selector}"` + ); + console.log( + `[CSSGenerator] Properties count: ${props.cssProps.size}` + ); + } + css += `${selector} {${this.options.minified ? "" : "\n"}`; + props.cssProps.forEach((value, prop) => { + const cssProperty = toKebabCase(prop); + css += `${ + this.options.minified ? "" : " " + }${cssProperty}: ${value};${this.options.minified ? "" : "\n"}`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Added property: ${cssProperty}: ${value}` + ); + } + }); + css += `}${this.options.minified ? "" : "\n"}`; + } + + if (props.nestedRules.size > 0) { + if (this.options.debug) { + console.log( + `\n[CSSGenerator] Processing ${props.nestedRules.size} nested rules for "${selector}"` + ); + } + props.nestedRules.forEach((rules, nestedSelector) => { + const fullSelector = nestedSelector.startsWith(">") + ? `${selector} ${nestedSelector}` + : `${selector}${nestedSelector}`; + + if (this.options.debug) { + console.log( + `[CSSGenerator] Generating nested selector: "${fullSelector}"` + ); + } + + css += `${fullSelector} {${this.options.minified ? "" : "\n"}`; + Object.entries(rules).forEach(([prop, value]) => { + if (typeof value === "object") { + const pseudoSelector = `${fullSelector}${prop}`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Generating pseudo-selector: "${pseudoSelector}"` + ); + } + css += `}${this.options.minified ? "" : "\n"}${pseudoSelector} {${ + this.options.minified ? "" : "\n" + }`; + Object.entries(value).forEach(([nestedProp, nestedValue]) => { + const cssProperty = toKebabCase(nestedProp); + css += `${ + this.options.minified ? "" : " " + }${cssProperty}: ${nestedValue};${ + this.options.minified ? "" : "\n" + }`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Added nested property: ${cssProperty}: ${nestedValue}` + ); + } + }); + } else { + const cssProperty = toKebabCase(prop); + css += `${ + this.options.minified ? "" : " " + }${cssProperty}: ${value};${this.options.minified ? "" : "\n"}`; + if (this.options.debug) { + console.log( + `[CSSGenerator] Added property: ${cssProperty}: ${value}` + ); + } + } + }); + css += `}${this.options.minified ? "" : "\n"}`; + }); + } + }); + + if (this.options.debug) { + console.log("\n[CSSGenerator] CSS generation complete"); + console.log( + `[CSSGenerator] Generated ${css.split("\n").length} lines of CSS` + ); + } + + return css; + } +} + +module.exports = CSSGenerator; diff --git a/lib/HTMLGenerator.js b/lib/HTMLGenerator.js new file mode 100644 index 0000000..1261b50 --- /dev/null +++ b/lib/HTMLGenerator.js @@ -0,0 +1,353 @@ +const { ELEMENT_MAPPINGS } = require("./mappings"); + +class HTMLGenerator { + /** + * Creates a new HTML generator instance. + * @param {Object} [options] - Options object + * @param {boolean} [options.minified=true] - Minify generated HTML + * @param {boolean} [options.debug=false] - Enable debug logging + * @param {CSSGenerator} cssGenerator - CSS generator instance + */ + constructor(options = {}, cssGenerator) { + this.options = options; + this.cssGenerator = cssGenerator; + if (this.options.debug) { + console.log( + "[HTMLGenerator] Initialized with options:", + JSON.stringify(options, null, 2) + ); + } + } + + /** + * Converts a node to a string for debugging purposes, avoiding circular + * references. + * @param {Object} node - Node to stringify + * @returns {string} String representation of the node + */ + debugStringify(node) { + const getCircularReplacer = () => { + const seen = new WeakSet(); + return (key, value) => { + if (key === "parent") return "[Circular:Parent]"; + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return "[Circular]"; + } + seen.add(value); + } + return value; + }; + }; + + try { + return JSON.stringify(node, getCircularReplacer(), 2); + } catch (err) { + return `[Unable to stringify: ${err.message}]`; + } + } + + /** + * Converts a node to a string of HTML. + * @param {Object} node - Node to generate HTML for + * @returns {string} Generated HTML + */ + generateHTML(node) { + if (this.options.debug) { + console.log(`\n[HTMLGenerator] Generating HTML for node`); + console.log(`[HTMLGenerator] Node type: "${node.type}"`); + console.log("[HTMLGenerator] Node details:", this.debugStringify(node)); + } + + if (node.type === "text") { + if (node.parent?.tag === "codeblock") { + if (this.options.debug) { + console.log("[HTMLGenerator] Rendering raw text for codeblock"); + console.log(`[HTMLGenerator] Raw text content: "${node.value}"`); + } + return node.value; + } + const escapedText = node.value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + if (this.options.debug) { + console.log("[HTMLGenerator] Generated escaped text"); + console.log(`[HTMLGenerator] Original: "${node.value}"`); + console.log(`[HTMLGenerator] Escaped: "${escapedText}"`); + } + return escapedText; + } + + let html = ""; + if (node.type === "element") { + if (node.tag === "page") { + if (this.options.debug) { + console.log("[HTMLGenerator] Skipping page node - metadata only"); + } + return ""; + } + + const mapping = ELEMENT_MAPPINGS[node.tag]; + let tag = mapping ? mapping.tag : "div"; + const className = this.cssGenerator.generateClassName(node.tag); + const { cssProps, nestedRules } = + this.cssGenerator.nodeToCSSProperties(node); + + if (this.options.debug) { + console.log(`\n[HTMLGenerator] Processing element node`); + console.log(`[HTMLGenerator] Tag: "${node.tag}" -> "${tag}"`); + console.log(`[HTMLGenerator] Generated class name: "${className}"`); + console.log( + "[HTMLGenerator] CSS properties:", + this.debugStringify(Object.fromEntries(cssProps)) + ); + console.log( + "[HTMLGenerator] Nested rules:", + this.debugStringify(Object.fromEntries(nestedRules)) + ); + } + + let attributes = ""; + if (tag === "input") { + if (node.tag === "checkbox") { + attributes = ' type="checkbox"'; + } else if (node.tag === "radio") { + attributes = ' type="radio"'; + } else if (node.tag === "switch") { + attributes = ' type="checkbox" role="switch"'; + } else if (node.tag === "slider") { + attributes = ' type="range"'; + } + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added input attributes: "${attributes}"` + ); + } + } + + if (node.tag === "media") { + const srcProp = node.props.find((p) => p.startsWith("src:")); + const typeProp = node.props.find((p) => p.startsWith("type:")); + + if (!srcProp) { + throw new BlueprintError("Media element requires src property", node.line, node.column); + } + + const src = srcProp.substring(srcProp.indexOf(":") + 1).trim(); + const type = typeProp ? typeProp.substring(typeProp.indexOf(":") + 1).trim() : "img"; + + if (type === "video") { + tag = "video"; + attributes = ` src="${src}" controls`; + } else { + tag = "img"; + attributes = ` src="${src}" alt="${node.children.map(child => this.generateHTML(child)).join("")}"`; + } + } + + if (node.tag === "link") { + const linkInfo = this.processLink(node); + attributes += ` href="${linkInfo.href}"`; + if ( + linkInfo.href.startsWith("http://") || + linkInfo.href.startsWith("https://") + ) { + attributes += ` target="_blank" rel="noopener noreferrer"`; + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added external link attributes for: ${linkInfo.href}` + ); + } + } else { + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added internal link attributes for: ${linkInfo.href}` + ); + } + } + } + + if ( + node.props.find((p) => typeof p === "string" && p.startsWith("data-")) + ) { + const dataProps = node.props.filter( + (p) => typeof p === "string" && p.startsWith("data-") + ); + attributes += " " + dataProps.map((p) => `${p}`).join(" "); + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added data attributes:`, + this.debugStringify(dataProps) + ); + } + } + + this.cssGenerator.cssRules.set(`.${className}`, { + cssProps, + nestedRules, + }); + if (this.options.debug) { + console.log( + `[HTMLGenerator] Registered CSS rules for class: .${className}` + ); + } + + if (node.tag === "button" || node.tag.startsWith("button-")) { + if (node.parent?.tag === "link") { + const linkInfo = this.processLink(node.parent); + if ( + linkInfo.href.startsWith("http://") || + linkInfo.href.startsWith("https://") + ) { + attributes += ` onclick="window.open('${linkInfo.href}', '_blank', 'noopener,noreferrer')"`; + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added external button click handler for: ${linkInfo.href}` + ); + } + } else { + attributes += ` onclick="window.location.href='${linkInfo.href}'"`; + if (this.options.debug) { + console.log( + `[HTMLGenerator] Added internal button click handler for: ${linkInfo.href}` + ); + } + } + } + html += `${ + this.options.minified ? "" : "\n" + }`; + } else if ( + node.tag === "link" && + node.children.length === 1 && + (node.children[0].tag === "button" || + node.children[0].tag?.startsWith("button-")) + ) { + if (this.options.debug) { + console.log( + "[HTMLGenerator] Processing button inside link - using button's HTML" + ); + } + node.children[0].parent = node; + html += this.generateHTML(node.children[0]); + } else { + html += `<${tag} class="${className}"${attributes}>${ + this.options.minified ? "" : "\n" + }`; + if (this.options.debug) { + console.log( + `[HTMLGenerator] Generated opening tag: <${tag}> with attributes:`, + this.debugStringify({ class: className, ...attributes }) + ); + } + node.children.forEach((child) => { + child.parent = node; + html += this.generateHTML(child); + }); + html += `${this.options.minified ? "" : "\n"}${ + this.options.minified ? "" : "\n" + }`; + if (this.options.debug) { + console.log(`[HTMLGenerator] Completed element: ${tag}`); + } + } + } else if (node.type === "root") { + if (this.options.debug) { + console.log( + `[HTMLGenerator] Processing root node with ${node.children.length} children` + ); + } + node.children.forEach((child, index) => { + if (this.options.debug) { + console.log( + `[HTMLGenerator] Processing root child ${index + 1}/${ + node.children.length + }` + ); + } + html += this.generateHTML(child); + }); + } + + if (this.options.debug) { + console.log("[HTMLGenerator] Generated HTML:", html); + } + return html; + } + + /** + * Processes a link node, extracting the href attribute and converting it + * to an internal link if it doesn't start with http:// or https://. + * + * If no href property is found, the default value of # is used. + * + * @param {Object} node - The link node to process + * @returns {Object} - An object containing the final href value + */ + processLink(node) { + if (this.options.debug) { + console.log("\n[HTMLGenerator] Processing link node"); + console.log( + "[HTMLGenerator] Link properties:", + this.debugStringify(node.props) + ); + } + + const hrefProp = node.props.find((p) => p.startsWith("href:")); + let href = "#"; + + if (hrefProp) { + let hrefTarget = hrefProp + .substring(hrefProp.indexOf(":") + 1) + .trim() + .replace(/^"|"$/g, ""); + if ( + !hrefTarget.startsWith("http://") && + !hrefTarget.startsWith("https://") + ) { + hrefTarget = "/" + hrefTarget; + if (this.options.debug) { + console.log( + `[HTMLGenerator] Converted to internal link: "${hrefTarget}"` + ); + } + } else { + if (this.options.debug) { + console.log( + `[HTMLGenerator] External link detected: "${hrefTarget}"` + ); + } + } + href = hrefTarget; + } else { + if (this.options.debug) { + console.log( + "[HTMLGenerator] No href property found, using default: '#'" + ); + } + } + + if (this.options.debug) { + console.log(`[HTMLGenerator] Final href value: "${href}"`); + } + return { href }; + } +} + +module.exports = HTMLGenerator; diff --git a/lib/MetadataManager.js b/lib/MetadataManager.js new file mode 100644 index 0000000..130bf61 --- /dev/null +++ b/lib/MetadataManager.js @@ -0,0 +1,333 @@ +class MetadataManager { +/** + * Initializes a new instance of the MetadataManager class. + * + * @param {Object} options - Configuration options for the metadata manager. + * @param {boolean} [options.debug=false] - Enables debug logging if true. + * + * Sets up the pageMetadata object containing default title, faviconUrl, and an empty meta array. + * If debug mode is enabled, logs the initialization options and the initial metadata state. + */ + + constructor(options = {}) { + this.options = options; + this.pageMetadata = { + title: "", + faviconUrl: "", + meta: [], + }; + if (this.options.debug) { + console.log( + "[MetadataManager] Initialized with options:", + JSON.stringify(options, null, 2) + ); + console.log( + "[MetadataManager] Initial metadata state:", + JSON.stringify(this.pageMetadata, null, 2) + ); + } + } + + /** + * Converts a node to a string for debugging purposes, avoiding circular + * references. + * @param {Object} node - Node to stringify + * @returns {string} String representation of the node + */ + debugStringify(node) { + const getCircularReplacer = () => { + const seen = new WeakSet(); + return (key, value) => { + if (key === "parent") return "[Circular:Parent]"; + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return "[Circular]"; + } + seen.add(value); + } + return value; + }; + }; + + try { + return JSON.stringify(node, getCircularReplacer(), 2); + } catch (err) { + return `[Unable to stringify: ${err.message}]`; + } + } + + /** + * Processes the metadata of a given node object, updating the internal page metadata state. + * + * Iterates through the node's properties and children to extract metadata information such as + * title, favicon, description, keywords, and author. This information is used to populate + * the pageMetadata object. + * + * For each property or child, it handles known metadata fields directly and adds custom + * meta tags for any properties or children with a "meta-" prefix. + * + * @param {Object} node - The node containing properties and children to process for metadata. + */ + + processPageMetadata(node) { + if (this.options.debug) { + console.log("\n[MetadataManager] Processing page metadata"); + console.log("[MetadataManager] Node details:", this.debugStringify(node)); + } + + if (node.props) { + if (this.options.debug) { + console.log( + `\n[MetadataManager] Processing ${node.props.length} page properties` + ); + console.log( + "[MetadataManager] Properties:", + this.debugStringify(node.props) + ); + } + node.props.forEach((prop) => { + if (typeof prop === "object" && prop.name && prop.value) { + if (this.options.debug) { + console.log( + `\n[MetadataManager] Processing property:`, + this.debugStringify(prop) + ); + } + switch (prop.name) { + case "title": + this.pageMetadata.title = prop.value; + if (this.options.debug) { + console.log( + `[MetadataManager] Set page title: "${prop.value}"` + ); + } + break; + case "favicon": + this.pageMetadata.faviconUrl = prop.value; + if (this.options.debug) { + console.log( + `[MetadataManager] Set favicon URL: "${prop.value}"` + ); + } + break; + case "description": + this.pageMetadata.meta.push({ + name: "description", + content: prop.value, + }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added description meta tag: "${prop.value}"` + ); + } + break; + case "keywords": + this.pageMetadata.meta.push({ + name: "keywords", + content: prop.value, + }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added keywords meta tag: "${prop.value}"` + ); + } + break; + case "author": + this.pageMetadata.meta.push({ + name: "author", + content: prop.value, + }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added author meta tag: "${prop.value}"` + ); + } + break; + default: + if (prop.name.startsWith("meta-")) { + const metaName = prop.name.substring(5); + this.pageMetadata.meta.push({ + name: metaName, + content: prop.value, + }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added custom meta tag - ${metaName}: "${prop.value}"` + ); + } + } else if (this.options.debug) { + console.log( + `[MetadataManager] Skipping unknown property: "${prop.name}"` + ); + } + } + } + }); + } + + if (node.children) { + if (this.options.debug) { + console.log( + `\n[MetadataManager] Processing ${node.children.length} child nodes for metadata` + ); + } + node.children.forEach((child, index) => { + if (child.tag) { + if (this.options.debug) { + console.log( + `\n[MetadataManager] Processing child ${index + 1}/${ + node.children.length + }` + ); + console.log(`[MetadataManager] Child tag: "${child.tag}"`); + console.log( + "[MetadataManager] Child details:", + this.debugStringify(child) + ); + } + + let content = ""; +/** + * Recursively extracts the text content from a node tree. + * + * This function traverses the node tree and concatenates the text content of + * all text nodes. For non-text nodes, it recursively calls itself on the + * children of that node. + * + * @param {Object} node - The node for which to extract the text content + * @return {string} The extracted text content + */ + const getTextContent = (node) => { + if (node.type === "text") return node.value; + if (node.children) { + return node.children.map(getTextContent).join(""); + } + return ""; + }; + content = getTextContent(child); + + if (this.options.debug) { + console.log(`[MetadataManager] Extracted content: "${content}"`); + } + + switch (child.tag) { + case "title": + this.pageMetadata.title = content; + if (this.options.debug) { + console.log( + `[MetadataManager] Set page title from child: "${content}"` + ); + } + break; + case "description": + this.pageMetadata.meta.push({ name: "description", content }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added description meta tag from child: "${content}"` + ); + } + break; + case "keywords": + this.pageMetadata.meta.push({ name: "keywords", content }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added keywords meta tag from child: "${content}"` + ); + } + break; + case "author": + this.pageMetadata.meta.push({ name: "author", content }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added author meta tag from child: "${content}"` + ); + } + break; + default: + if (child.tag.startsWith("meta-")) { + const metaName = child.tag.substring(5); + this.pageMetadata.meta.push({ name: metaName, content }); + if (this.options.debug) { + console.log( + `[MetadataManager] Added custom meta tag from child - ${metaName}: "${content}"` + ); + } + } else if (this.options.debug) { + console.log( + `[MetadataManager] Skipping unknown child tag: "${child.tag}"` + ); + } + } + } + }); + } + + if (this.options.debug) { + console.log("\n[MetadataManager] Metadata processing complete"); + console.log( + "[MetadataManager] Final metadata state:", + this.debugStringify(this.pageMetadata) + ); + } + } + + /** + * Generates the HTML head content for the page, based on the metadata + * previously collected. The generated content includes the page title, + * favicon link, meta tags, and stylesheet link. + * + * @param {string} baseName - The base name of the page (used for the + * stylesheet link) + * @return {string} The generated HTML head content + */ + generateHeadContent(baseName) { + if (this.options.debug) { + console.log("\n[MetadataManager] Generating head content"); + console.log(`[MetadataManager] Base name: "${baseName}"`); + } + + let content = ""; + + const title = this.pageMetadata.title || baseName; + content += ` ${title}\n`; + if (this.options.debug) { + console.log(`[MetadataManager] Added title tag: "${title}"`); + } + + if (this.pageMetadata.faviconUrl) { + content += ` \n`; + if (this.options.debug) { + console.log( + `[MetadataManager] Added favicon link: "${this.pageMetadata.faviconUrl}"` + ); + } + } + + if (this.options.debug) { + console.log( + `[MetadataManager] Processing ${this.pageMetadata.meta.length} meta tags` + ); + } + this.pageMetadata.meta.forEach((meta, index) => { + content += ` \n`; + if (this.options.debug) { + console.log( + `[MetadataManager] Added meta tag ${index + 1}: ${meta.name} = "${ + meta.content + }"` + ); + } + }); + + content += ` \n`; + if (this.options.debug) { + console.log(`[MetadataManager] Added stylesheet link: "${baseName}.css"`); + console.log("\n[MetadataManager] Head content generation complete"); + console.log("[MetadataManager] Generated content:", content); + } + + return content; + } +} + +module.exports = MetadataManager; diff --git a/lib/TokenParser.js b/lib/TokenParser.js new file mode 100644 index 0000000..62f6776 --- /dev/null +++ b/lib/TokenParser.js @@ -0,0 +1,370 @@ +const BlueprintError = require("./BlueprintError"); + +class TokenParser { + + /** + * Creates a new TokenParser instance. + * @param {Object} [options] - Options object + * @param {boolean} [options.debug=false] - Enable debug logging + */ + constructor(options = {}) { + this.options = options; + if (this.options.debug) { + console.log( + "[TokenParser] Initialized with options:", + JSON.stringify(options, null, 2) + ); + } + } + + /** + * Tokenizes the input string into an array of tokens. + * Tokens can be of the following types: + * - `identifier`: A sequence of letters, numbers, underscores, and hyphens. + * Represents a CSS selector or a property name. + * - `props`: A sequence of characters enclosed in parentheses. + * Represents a list of CSS properties. + * - `text`: A sequence of characters enclosed in quotes. + * Represents a string of text. + * - `brace`: A single character, either `{` or `}`. + * Represents a brace in the input. + * + * @param {string} input - Input string to tokenize + * @returns {Array} - Array of tokens + * @throws {BlueprintError} - If the input contains invalid syntax + */ + tokenize(input) { + if (this.options.debug) { + console.log("\n[TokenParser] Starting tokenization"); + console.log(`[TokenParser] Input length: ${input.length} characters`); + console.log(`[TokenParser] First 100 chars: ${input.slice(0, 100)}...`); + } + + const tokens = []; + let current = 0; + let line = 1; + let column = 1; + const startTime = Date.now(); + const TIMEOUT_MS = 5000; + + while (current < input.length) { + let char = input[current]; + + if (Date.now() - startTime > TIMEOUT_MS) { + if (this.options.debug) { + console.log( + `[TokenParser] Tokenization timeout at position ${current}, line ${line}, column ${column}` + ); + } + throw new BlueprintError( + "Parsing timeout - check for unclosed brackets or quotes", + line, + column + ); + } + + if (char === "\n") { + if (this.options.debug) { + console.log( + `[TokenParser] Line break at position ${current}, moving to line ${ + line + 1 + }` + ); + } + line++; + column = 1; + current++; + continue; + } + + if (/\s/.test(char)) { + column++; + current++; + continue; + } + + if (char === "/" && input[current + 1] === "/") { + if (this.options.debug) { + console.log( + `[TokenParser] Comment found at line ${line}, column ${column}` + ); + const commentEnd = input.indexOf("\n", current); + const comment = input.slice( + current, + commentEnd !== -1 ? commentEnd : undefined + ); + console.log(`[TokenParser] Comment content: ${comment}`); + } + while (current < input.length && input[current] !== "\n") { + current++; + column++; + } + continue; + } + + if (/[a-zA-Z]/.test(char)) { + let value = ""; + const startColumn = column; + const startPos = current; + + while (current < input.length && /[a-zA-Z0-9_-]/.test(char)) { + value += char; + current++; + column++; + char = input[current]; + } + + if (this.options.debug) { + console.log( + `[TokenParser] Identifier found at line ${line}, column ${startColumn}` + ); + console.log(`[TokenParser] Identifier value: "${value}"`); + console.log( + `[TokenParser] Context: ...${input.slice( + Math.max(0, startPos - 10), + startPos + )}[${value}]${input.slice(current, current + 10)}...` + ); + } + + tokens.push({ + type: "identifier", + value, + line, + column: startColumn, + }); + continue; + } + + if (char === "(") { + if (this.options.debug) { + console.log(`[DEBUG] Starting property list at position ${current}`); + } + + const startColumn = column; + let value = ""; + let depth = 1; + let propLine = line; + let propColumn = column; + current++; + column++; + const propStartPos = current; + + while (current < input.length && depth > 0) { + if (current - propStartPos > 1000) { + if (this.options.debug) { + console.log("[DEBUG] Property list too long or unclosed"); + } + throw new BlueprintError( + "Property list too long or unclosed parenthesis", + propLine, + propColumn + ); + } + + char = input[current]; + + if (char === "(") depth++; + if (char === ")") depth--; + + if (depth === 0) break; + + value += char; + if (char === "\n") { + line++; + column = 1; + } else { + column++; + } + current++; + } + + if (depth > 0) { + if (this.options.debug) { + console.log("[DEBUG] Unclosed parenthesis detected"); + } + throw new BlueprintError( + "Unclosed parenthesis in property list", + propLine, + propColumn + ); + } + + tokens.push({ + type: "props", + value: value.trim(), + line, + column: startColumn, + }); + + current++; + column++; + continue; + } + + if (char === '"' || char === "'") { + if (this.options.debug) { + console.log(`[DEBUG] Starting string at position ${current}`); + } + + const startColumn = column; + const startLine = line; + const quote = char; + let value = ""; + const stringStartPos = current; + + current++; + column++; + + while (current < input.length) { + if (current - stringStartPos > 1000) { + if (this.options.debug) { + console.log("[DEBUG] String too long or unclosed"); + } + throw new BlueprintError( + "String too long or unclosed quote", + startLine, + startColumn + ); + } + + char = input[current]; + + if (char === "\n") { + line++; + column = 1; + value += char; + } else if (char === quote && input[current - 1] !== "\\") { + break; + } else { + value += char; + column++; + } + + current++; + } + + tokens.push({ + type: "text", + value, + line: startLine, + column: startColumn, + }); + + current++; + column++; + continue; + } + + if (char === "{" || char === "}") { + if (this.options.debug) { + console.log(`[DEBUG] Found brace: ${char} at position ${current}`); + } + + tokens.push({ + type: "brace", + value: char, + line, + column, + }); + current++; + column++; + continue; + } + + if (this.options.debug) { + console.log( + `[DEBUG] Unexpected character at position ${current}: "${char}"` + ); + } + throw new BlueprintError(`Unexpected character: ${char}`, line, column); + } + + if (this.options.debug) { + console.log("\n[TokenParser] Tokenization complete"); + console.log(`[TokenParser] Total tokens generated: ${tokens.length}`); + console.log( + "[TokenParser] Token summary:", + tokens.map((t) => `${t.type}:${t.value}`).join(", ") + ); + } + + this.validateBraces(tokens); + return tokens; + } + + /** + * Validates that all braces in the token stream are properly matched. + * This function walks the token stream, counting the number of open and + * close braces. If it encounters an unmatched brace, it throws an error. + * If it encounters an extra closing brace, it throws an error. + * @throws {BlueprintError} - If there is a brace mismatch + */ + validateBraces(tokens) { + let braceCount = 0; + let lastOpenBrace = { line: 1, column: 1 }; + const braceStack = []; + + if (this.options.debug) { + console.log("\n[TokenParser] Starting brace validation"); + } + + for (const token of tokens) { + if (token.type === "brace") { + if (token.value === "{") { + braceCount++; + braceStack.push({ line: token.line, column: token.column }); + lastOpenBrace = { line: token.line, column: token.column }; + if (this.options.debug) { + console.log( + `[TokenParser] Opening brace at line ${token.line}, column ${token.column}, depth: ${braceCount}` + ); + } + } else if (token.value === "}") { + braceCount--; + const matchingOpen = braceStack.pop(); + if (this.options.debug) { + console.log( + `[TokenParser] Closing brace at line ${token.line}, column ${token.column}, depth: ${braceCount}` + ); + if (matchingOpen) { + console.log( + `[TokenParser] Matches opening brace at line ${matchingOpen.line}, column ${matchingOpen.column}` + ); + } + } + } + } + } + + if (braceCount !== 0) { + if (this.options.debug) { + console.log( + `[TokenParser] Brace mismatch detected: ${ + braceCount > 0 ? "unclosed" : "extra" + } braces` + ); + console.log(`[TokenParser] Brace stack:`, braceStack); + } + if (braceCount > 0) { + throw new BlueprintError( + "Unclosed brace", + lastOpenBrace.line, + lastOpenBrace.column + ); + } else { + throw new BlueprintError( + "Extra closing brace", + tokens[tokens.length - 1].line, + tokens[tokens.length - 1].column + ); + } + } + + if (this.options.debug) { + console.log("[TokenParser] Brace validation complete - all braces match"); + } + } +} + +module.exports = TokenParser; diff --git a/lib/build.js b/lib/build.js new file mode 100644 index 0000000..62b510d --- /dev/null +++ b/lib/build.js @@ -0,0 +1,77 @@ +const BlueprintBuilder = require("./BlueprintBuilder"); +const fs = require("fs"); +const path = require("path"); + +const args = process.argv.slice(2); +const options = { + minified: !args.includes("--readable"), + srcDir: "./src", + outDir: "./dist", + debug: args.includes("--debug"), +}; + +const builder = new BlueprintBuilder(options); + +function ensureDirectoryExistence(filePath) { + const dirname = path.dirname(filePath); + if (fs.existsSync(dirname)) { + return true; + } + ensureDirectoryExistence(dirname); + fs.mkdirSync(dirname); +} + +function getAllFiles(dirPath, arrayOfFiles) { + const files = fs.readdirSync(dirPath); + + arrayOfFiles = arrayOfFiles || []; + + files.forEach((file) => { + if (fs.statSync(path.join(dirPath, file)).isDirectory()) { + arrayOfFiles = getAllFiles(path.join(dirPath, file), arrayOfFiles); + } else if (file.endsWith(".bp")) { + arrayOfFiles.push(path.join(dirPath, file)); + } + }); + + return arrayOfFiles; +} + +const files = getAllFiles(options.srcDir); + +let success = true; +const errors = []; + +console.log("Building Blueprint files..."); +const startTime = Date.now(); + +for (const file of files) { + const relativePath = path.relative(options.srcDir, file); + const outputPath = path.join( + options.outDir, + relativePath.replace(/\.bp$/, ".html") + ); + ensureDirectoryExistence(outputPath); + + console.log(`Building ${file}...`); + const result = builder.build(file, path.dirname(outputPath)); + if (!result.success) { + success = false; + errors.push({ file, errors: result.errors }); + } +} + +const totalTime = Date.now() - startTime; + +if (success) { + console.log(`All files built successfully in ${totalTime}ms!`); +} else { + console.error("Build failed with errors:"); + errors.forEach(({ file, errors }) => { + console.error(`\nFile: ${file}`); + errors.forEach((err) => { + console.error(` ${err.message} (${err.line}:${err.column})`); + }); + }); + process.exit(1); +} diff --git a/lib/dev-server.js b/lib/dev-server.js new file mode 100644 index 0000000..1470615 --- /dev/null +++ b/lib/dev-server.js @@ -0,0 +1,15 @@ +const BlueprintServer = require("./server"); + +const args = process.argv.slice(2); +const options = { + port: args.includes("--port") + ? parseInt(args[args.indexOf("--port") + 1]) + : 3000, + liveReload: args.includes("--live"), + minified: !args.includes("--readable"), + srcDir: "./src", + outDir: "./dist", +}; + +const server = new BlueprintServer(options); +server.start(); diff --git a/lib/mappings.js b/lib/mappings.js new file mode 100644 index 0000000..b47f83d --- /dev/null +++ b/lib/mappings.js @@ -0,0 +1,648 @@ +const STYLE_MAPPINGS = { + centered: { + display: "flex", + justifyContent: "center", + alignItems: "center", + textAlign: "center", + padding: "2rem", + width: "100%", + }, + spaced: { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + gap: "1.5rem", + width: "100%", + }, + responsive: { + flexWrap: "wrap", + gap: "2rem", + }, + horizontal: { + display: "flex", + flexDirection: "row", + gap: "1.5rem", + alignItems: "center", + width: "100%", + }, + vertical: { + display: "flex", + flexDirection: "column", + gap: "1.5rem", + width: "100%", + }, + grid: { + display: "grid", + gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", + gap: "2rem", + width: "100%", + padding: "2rem 0", + }, + wide: { + width: "100%", + maxWidth: "1200px", + margin: "0 auto", + padding: "0 2rem", + }, + alternate: { + backgroundColor: "#0d1117", + padding: "5rem 0", + width: "100%", + }, + sticky: { + position: "fixed", + top: "0", + left: "0", + right: "0", + zIndex: "1000", + backgroundColor: "rgba(13, 17, 23, 0.95)", + backdropFilter: "blur(12px)", + borderBottom: "1px solid rgba(48, 54, 61, 0.6)", + }, + + huge: { + fontSize: "clamp(2.5rem, 5vw, 4rem)", + fontWeight: "800", + lineHeight: "1.1", + letterSpacing: "-0.02em", + color: "#ffffff", + marginBottom: "1.5rem", + textAlign: "center", + }, + large: { + fontSize: "clamp(1.5rem, 3vw, 2rem)", + lineHeight: "1.3", + color: "#ffffff", + fontWeight: "600", + marginBottom: "1rem", + }, + small: { + fontSize: "0.875rem", + lineHeight: "1.5", + color: "#8b949e", + }, + bold: { + fontWeight: "600", + color: "#ffffff", + }, + subtle: { + color: "#8b949e", + lineHeight: "1.6", + marginBottom: "0.5rem", + }, + + light: { + backgroundColor: "transparent", + color: "#8b949e", + padding: "0.875rem 1.75rem", + borderRadius: "12px", + border: "1px solid rgba(48, 54, 61, 0.6)", + cursor: "pointer", + fontWeight: "500", + fontSize: "0.95rem", + transition: "all 0.2s ease", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + textDecoration: "none", + ":hover": { + color: "#e6edf3", + backgroundColor: "rgba(255, 255, 255, 0.1)", + borderColor: "#6b7280", + }, + }, + + raised: { + backgroundColor: "#111827", + borderRadius: "16px", + border: "1px solid rgba(48, 54, 61, 0.6)", + padding: "2rem", + transition: "all 0.2s ease", + ":hover": { + transform: "translateY(-2px)", + boxShadow: "0 8px 16px rgba(0,0,0,0.2)", + borderColor: "#3b82f6", + }, + }, + prominent: { + backgroundColor: "#3b82f6", + color: "#ffffff", + padding: "0.875rem 1.75rem", + borderRadius: "12px", + border: "none", + cursor: "pointer", + fontWeight: "500", + fontSize: "0.95rem", + transition: "all 0.2s ease", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + textDecoration: "none", + ":hover": { + backgroundColor: "#2563eb", + transform: "translateY(-1px)", + boxShadow: "0 4px 12px rgba(59, 130, 246, 0.3)", + }, + }, + secondary: { + backgroundColor: "#1f2937", + color: "#e6edf3", + padding: "0.875rem 1.75rem", + borderRadius: "12px", + border: "1px solid rgba(48, 54, 61, 0.6)", + cursor: "pointer", + fontWeight: "500", + fontSize: "0.95rem", + transition: "all 0.2s ease", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + textDecoration: "none", + ":hover": { + backgroundColor: "#374151", + borderColor: "#6b7280", + transform: "translateY(-1px)", + }, + }, + compact: { + padding: "0.75rem", + borderRadius: "12px", + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + color: "#e6edf3", + cursor: "pointer", + transition: "all 0.2s ease", + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + ":hover": { + backgroundColor: "#1f2937", + borderColor: "#3b82f6", + transform: "translateY(-1px)", + }, + }, + + navbar: { + backgroundColor: "rgba(13, 17, 23, 0.95)", + backdropFilter: "blur(12px)", + padding: "1rem 2rem", + width: "100%", + borderBottom: "1px solid rgba(48, 54, 61, 0.6)", + position: "fixed", + top: 0, + left: 0, + right: 0, + zIndex: 1000, + "> *": { + maxWidth: "1200px", + margin: "0 auto", + display: "flex", + alignItems: "center", + justifyContent: "space-between", + }, + }, + section: { + padding: "5rem 0", + backgroundColor: "#0d1117", + marginTop: "5rem", + "> *": { + maxWidth: "1200px", + margin: "0 auto", + }, + }, + card: { + display: "flex", + flexDirection: "column", + gap: "1.5rem", + height: "100%", + backgroundColor: "#111827", + borderRadius: "16px", + border: "1px solid rgba(48, 54, 61, 0.6)", + padding: "2rem", + transition: "all 0.2s ease", + marginBottom: "1rem", + "> title": { + fontSize: "1.25rem", + fontWeight: "600", + color: "#ffffff", + marginBottom: "0.5rem", + }, + "> text": { + color: "#8b949e", + lineHeight: "1.6", + }, + cursor: "default", + }, + links: { + display: "flex", + gap: "2rem", + alignItems: "center", + "> *": { + color: "#8b949e", + textDecoration: "none", + transition: "all 0.2s ease", + fontSize: "0.95rem", + padding: "0.5rem 0.75rem", + borderRadius: "8px", + cursor: "pointer", + ":hover": { + color: "#e6edf3", + backgroundColor: "rgba(255, 255, 255, 0.1)", + }, + }, + }, + + input: { + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + borderRadius: "12px", + padding: "0.875rem 1.25rem", + color: "#e6edf3", + width: "100%", + transition: "all 0.2s ease", + outline: "none", + fontSize: "0.95rem", + ":focus": { + borderColor: "#3b82f6", + boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.15)", + }, + "::placeholder": { + color: "#8b949e", + }, + }, + textarea: { + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + borderRadius: "12px", + padding: "0.875rem 1.25rem", + color: "#e6edf3", + width: "100%", + minHeight: "120px", + resize: "vertical", + transition: "all 0.2s ease", + outline: "none", + fontSize: "0.95rem", + ":focus": { + borderColor: "#3b82f6", + boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.15)", + }, + }, + select: { + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + borderRadius: "12px", + padding: "0.875rem 2.5rem 0.875rem 1.25rem", + color: "#e6edf3", + width: "100%", + cursor: "pointer", + appearance: "none", + fontSize: "0.95rem", + backgroundImage: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%238b949e' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E\")", + backgroundRepeat: "no-repeat", + backgroundPosition: "right 1rem center", + backgroundSize: "1.5em 1.5em", + transition: "all 0.2s ease", + ":focus": { + borderColor: "#3b82f6", + boxShadow: "0 0 0 3px rgba(59, 130, 246, 0.15)", + }, + }, + checkbox: { + appearance: "none", + width: "1.25rem", + height: "1.25rem", + borderRadius: "6px", + border: "1px solid rgba(48, 54, 61, 0.6)", + backgroundColor: "#111827", + cursor: "pointer", + transition: "all 0.2s ease", + position: "relative", + marginRight: "0.75rem", + ":checked": { + backgroundColor: "#3b82f6", + borderColor: "#3b82f6", + "::after": { + content: '"✓"', + position: "absolute", + color: "white", + fontSize: "0.85rem", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + }, + }, + ":hover": { + borderColor: "#3b82f6", + }, + }, + radio: { + appearance: "none", + width: "1.25rem", + height: "1.25rem", + borderRadius: "50%", + border: "1px solid rgba(48, 54, 61, 0.6)", + backgroundColor: "#111827", + cursor: "pointer", + transition: "all 0.2s ease", + marginRight: "0.75rem", + ":checked": { + borderColor: "#3b82f6", + borderWidth: "4px", + backgroundColor: "#ffffff", + }, + ":hover": { + borderColor: "#3b82f6", + }, + }, + progress: { + appearance: "none", + width: "100%", + height: "0.75rem", + borderRadius: "999px", + overflow: "hidden", + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + "::-webkit-progress-bar": { + backgroundColor: "#111827", + }, + "::-webkit-progress-value": { + backgroundColor: "#3b82f6", + transition: "width 0.3s ease", + }, + "::-moz-progress-bar": { + backgroundColor: "#3b82f6", + transition: "width 0.3s ease", + }, + }, + slider: { + appearance: "none", + width: "100%", + height: "0.5rem", + borderRadius: "999px", + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + cursor: "pointer", + "::-webkit-slider-thumb": { + appearance: "none", + width: "1.25rem", + height: "1.25rem", + borderRadius: "50%", + backgroundColor: "#3b82f6", + border: "2px solid #ffffff", + cursor: "pointer", + transition: "all 0.2s ease", + ":hover": { + transform: "scale(1.1)", + }, + }, + }, + switch: { + appearance: "none", + position: "relative", + width: "3.5rem", + height: "1.75rem", + backgroundColor: "#111827", + border: "1px solid rgba(48, 54, 61, 0.6)", + borderRadius: "999px", + cursor: "pointer", + transition: "all 0.2s ease", + marginRight: "0.75rem", + ":checked": { + backgroundColor: "#3b82f6", + borderColor: "#3b82f6", + "::after": { + transform: "translateX(1.75rem)", + }, + }, + "::after": { + content: '""', + position: "absolute", + top: "0.2rem", + left: "0.2rem", + width: "1.25rem", + height: "1.25rem", + borderRadius: "50%", + backgroundColor: "#ffffff", + transition: "transform 0.2s ease", + }, + }, + badge: { + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + padding: "0.375rem 0.875rem", + borderRadius: "999px", + fontSize: "0.875rem", + fontWeight: "500", + backgroundColor: "#111827", + color: "#e6edf3", + border: "1px solid rgba(48, 54, 61, 0.6)", + minWidth: "4rem", + transition: "all 0.2s ease", + }, + alert: { + padding: "1rem 1.5rem", + borderRadius: "12px", + border: "1px solid rgba(48, 54, 61, 0.6)", + backgroundColor: "#111827", + color: "#e6edf3", + display: "flex", + alignItems: "center", + gap: "0.75rem", + fontSize: "0.95rem", + }, + tooltip: { + position: "relative", + display: "inline-block", + ":hover::after": { + content: "attr(data-tooltip)", + position: "absolute", + bottom: "120%", + left: "50%", + transform: "translateX(-50%)", + padding: "0.5rem 1rem", + borderRadius: "8px", + backgroundColor: "#111827", + color: "#e6edf3", + fontSize: "0.875rem", + whiteSpace: "nowrap", + zIndex: "1000", + boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1)", + border: "1px solid rgba(48, 54, 61, 0.6)", + }, + }, + link: { + color: "#e6edf3", + textDecoration: "none", + transition: "all 0.2s ease", + display: "inline-flex", + alignItems: "center", + gap: "0.5rem", + ":hover": { + color: "#3b82f6", + }, + }, + media: { + display: "block", + maxWidth: "100%", + height: "auto", + borderRadius: "8px", + transition: "all 0.2s ease", + ":hover": { + transform: "scale(1.01)", + }, + }, +}; + +const ELEMENT_MAPPINGS = { + page: { + tag: "meta", + defaultProps: [], + }, + section: { + tag: "section", + defaultProps: ["wide"], + }, + title: { + tag: "h1", + defaultProps: ["bold"], + }, + subtitle: { + tag: "h2", + defaultProps: ["bold", "large"], + }, + text: { + tag: "p", + defaultProps: [], + }, + button: { + tag: "button", + defaultProps: ["prominent"], + }, + "button-secondary": { + tag: "button", + defaultProps: ["secondary"], + }, + "button-light": { + tag: "button", + defaultProps: ["light"], + }, + "button-compact": { + tag: "button", + defaultProps: ["compact"], + }, + link: { + tag: "a", + defaultProps: ["link"], + }, + card: { + tag: "div", + defaultProps: ["raised", "card"], + }, + grid: { + tag: "div", + defaultProps: ["grid", "responsive"], + }, + horizontal: { + tag: "div", + defaultProps: ["horizontal", "spaced"], + }, + vertical: { + tag: "div", + defaultProps: ["vertical"], + }, + list: { + tag: "ul", + defaultProps: ["bullet"], + }, + cell: { + tag: "td", + defaultProps: [], + }, + row: { + tag: "tr", + defaultProps: [], + }, + table: { + tag: "table", + defaultProps: ["table"], + }, + codeblock: { + tag: "pre", + defaultProps: ["code"], + }, + navbar: { + tag: "nav", + defaultProps: ["navbar", "sticky"], + }, + links: { + tag: "div", + defaultProps: ["links"], + }, + input: { + tag: "input", + defaultProps: ["input"], + }, + textarea: { + tag: "textarea", + defaultProps: ["textarea"], + }, + checkbox: { + tag: "input", + defaultProps: ["checkbox"], + }, + radio: { + tag: "input", + defaultProps: ["radio"], + }, + select: { + tag: "select", + defaultProps: ["select"], + }, + progress: { + tag: "progress", + defaultProps: ["progress"], + }, + slider: { + tag: "input", + defaultProps: ["slider"], + }, + switch: { + tag: "input", + defaultProps: ["switch"], + }, + badge: { + tag: "span", + defaultProps: ["badge"], + }, + alert: { + tag: "div", + defaultProps: ["alert"], + }, + tooltip: { + tag: "span", + defaultProps: ["tooltip"], + }, + description: { + tag: "meta", + defaultProps: [], + }, + keywords: { + tag: "meta", + defaultProps: [], + }, + author: { + tag: "meta", + defaultProps: [], + }, + media: { + tag: "media", + defaultProps: ["media"], + }, +}; + +module.exports = { + STYLE_MAPPINGS, + ELEMENT_MAPPINGS, +}; diff --git a/lib/server.js b/lib/server.js new file mode 100644 index 0000000..6c2552e --- /dev/null +++ b/lib/server.js @@ -0,0 +1,473 @@ +const express = require("express"); +const expressWs = require("express-ws"); +const chokidar = require("chokidar"); +const path = require("path"); +const fs = require("fs"); +const BlueprintBuilder = require("./BlueprintBuilder"); + +class BlueprintServer { + constructor(options = {}) { + this.app = express(); + this.wsInstance = expressWs(this.app); + this.options = { + port: 3000, + srcDir: "./src", + outDir: "./dist", + liveReload: false, + minified: true, + ...options, + }; + this.clients = new Map(); + this.filesWithErrors = new Set(); + this.setupServer(); + if (this.options.liveReload) { + const watcher = chokidar.watch([], { + ignored: /(^|[\/\\])\../, + persistent: true, + ignoreInitial: true, + }); + + setTimeout(() => { + watcher.add(this.options.srcDir); + this.setupWatcher(watcher); + }, 1000); + } + } + + log(tag, message, color) { + const colorCodes = { + blue: "\x1b[34m", + green: "\x1b[32m", + red: "\x1b[31m", + orange: "\x1b[33m", + lightGray: "\x1b[90m", + reset: "\x1b[0m", + bgBlue: "\x1b[44m", + }; + console.log( + `${colorCodes.bgBlue} BP ${colorCodes.reset} ${ + colorCodes[color] || "" + }${message}${colorCodes.reset}` + ); + } + + async buildAll() { + this.log("INFO", "Building all Blueprint files...", "lightGray"); + if (fs.existsSync(this.options.outDir)) { + fs.rmSync(this.options.outDir, { recursive: true }); + } + fs.mkdirSync(this.options.outDir, { recursive: true }); + + const files = this.getAllFiles(this.options.srcDir); + let success = true; + const errors = []; + const startTime = Date.now(); + for (const file of files) { + const relativePath = path.relative(this.options.srcDir, file); + const outputPath = path.join( + this.options.outDir, + relativePath.replace(/\.bp$/, ".html") + ); + this.ensureDirectoryExistence(outputPath); + + const builder = new BlueprintBuilder({ minified: this.options.minified }); + const result = builder.build(file, path.dirname(outputPath)); + if (!result.success) { + success = false; + errors.push({ file, errors: result.errors }); + } + } + const totalTime = Date.now() - startTime; + if (success) { + this.log( + "SUCCESS", + `All files built successfully in ${totalTime}ms!`, + "green" + ); + } else { + this.log("ERROR", "Build failed with errors:", "red"); + errors.forEach(({ file, errors }) => { + this.log("ERROR", `File: ${file}`, "red"); + errors.forEach((err) => { + this.log( + "ERROR", + `${err.type} at line ${err.line}, column ${err.column}: ${err.message}`, + "red" + ); + }); + }); + process.exit(1); + } + } + + ensureDirectoryExistence(filePath) { + const dirname = path.dirname(filePath); + if (fs.existsSync(dirname)) { + return true; + } + this.ensureDirectoryExistence(dirname); + fs.mkdirSync(dirname); + } + + getAllFiles(dirPath, arrayOfFiles) { + const files = fs.readdirSync(dirPath); + + arrayOfFiles = arrayOfFiles || []; + + files.forEach((file) => { + if (fs.statSync(path.join(dirPath, file)).isDirectory()) { + arrayOfFiles = this.getAllFiles(path.join(dirPath, file), arrayOfFiles); + } else if (file.endsWith(".bp")) { + arrayOfFiles.push(path.join(dirPath, file)); + } + }); + + return arrayOfFiles; + } + + setupServer() { + this.app.use((req, res, next) => { + const isHtmlRequest = + req.path.endsWith(".html") || !path.extname(req.path); + + if (this.options.liveReload && isHtmlRequest) { + const htmlPath = req.path.endsWith(".html") + ? path.join(this.options.outDir, req.path) + : path.join(this.options.outDir, req.path + ".html"); + + fs.readFile(htmlPath, "utf8", (err, data) => { + if (err) return next(); + let html = data; + const script = ` + + `; + html = html.replace("", script + ""); + res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + res.setHeader("Pragma", "no-cache"); + res.setHeader("Expires", "0"); + return res.send(html); + }); + } else { + next(); + } + }); + + this.app.use(express.static(this.options.outDir)); + + this.app.get("*", (req, res, next) => { + if (path.extname(req.path)) return next(); + + const htmlPath = path.join(this.options.outDir, req.path + ".html"); + if (fs.existsSync(htmlPath)) { + res.sendFile(htmlPath); + } else if (req.path === "/") { + const pages = fs + .readdirSync(this.options.outDir) + .filter((f) => f.endsWith(".html")) + .map((f) => f.replace(".html", "")); + res.send(` + + + Blueprint Pages + + + +

Blueprint Pages

+
    + ${pages + .map((page) => `
  • ${page}
  • `) + .join("")} +
+ + + `); + } else { + next(); + } + }); + + if (this.options.liveReload) { + this.app.ws("/live-reload", (ws, req) => { + ws.on("message", (msg) => { + try { + const data = JSON.parse(msg); + if (data.type === "register" && data.page) { + this.clients.set(ws, data.page); + } + } catch (error) {} + }); + + ws.on("close", () => { + this.clients.delete(ws); + }); + + ws.on("error", (error) => { + this.log("ERROR", "WebSocket error:", "red"); + this.clients.delete(ws); + }); + }); + } + } + + setupWatcher(watcher) { + watcher.on("change", async (filepath) => { + if (filepath.endsWith(".bp")) { + this.log("INFO", `File ${filepath} has been changed`, "blue"); + try { + const builder = new BlueprintBuilder({ + minified: this.options.minified, + debug: this.options.debug, + }); + const relativePath = path.relative(this.options.srcDir, filepath); + const outputPath = path.join( + this.options.outDir, + relativePath.replace(/\.bp$/, ".html") + ); + this.ensureDirectoryExistence(outputPath); + const result = builder.build(filepath, path.dirname(outputPath)); + + if (result.success) { + this.log("SUCCESS", "Rebuilt successfully", "green"); + + this.filesWithErrors.delete(filepath); + + const htmlFile = relativePath.replace(/\.bp$/, ".html"); + const htmlPath = path.join(this.options.outDir, htmlFile); + + try { + const newContent = fs.readFileSync(htmlPath, "utf8"); + + for (const [client, page] of this.clients.entries()) { + if ( + page === htmlFile.replace(/\\/g, "/") && + client.readyState === 1 + ) { + try { + client.send( + JSON.stringify({ + type: "reload", + content: newContent, + }) + ); + } catch (error) { + this.log("ERROR", "Error sending content:", "red"); + this.clients.delete(client); + } + } + } + } catch (error) { + this.log("ERROR", "Error reading new content:", "red"); + } + } else { + this.filesWithErrors.add(filepath); + this.log("ERROR", `Build failed: ${result.errors.map(e => e.message).join(", ")}`, "red"); + this.log("INFO", "Waiting for next file change...", "orange"); + + for (const [client, page] of this.clients.entries()) { + const htmlFile = relativePath.replace(/\.bp$/, ".html"); + if ( + page === htmlFile.replace(/\\/g, "/") && + client.readyState === 1 + ) { + try { + client.send( + JSON.stringify({ + type: "buildError", + errors: result.errors, + }) + ); + } catch (error) { + this.log("ERROR", "Error sending error notification:", "red"); + this.clients.delete(client); + } + } + } + } + } catch (error) { + this.log("ERROR", "Unexpected error during build:", "red"); + this.filesWithErrors.add(filepath); + } + } + }); + + watcher.on("add", async (filepath) => { + if (filepath.endsWith(".bp")) { + this.log("INFO", `New file detected: ${filepath}`, "lightGray"); + try { + const builder = new BlueprintBuilder({ + minified: this.options.minified, + debug: this.options.debug, + }); + const relativePath = path.relative(this.options.srcDir, filepath); + const outputPath = path.join( + this.options.outDir, + relativePath.replace(/\.bp$/, ".html") + ); + this.ensureDirectoryExistence(outputPath); + const result = builder.build(filepath, path.dirname(outputPath)); + if (result.success) { + this.log("SUCCESS", "Built new file successfully", "green"); + this.filesWithErrors.delete(filepath); + } else { + this.filesWithErrors.add(filepath); + this.log("ERROR", "Build failed for new file", "red"); + } + } catch (error) { + this.log("ERROR", "Unexpected error building new file:", "red"); + this.filesWithErrors.add(filepath); + } + } + }); + + watcher.on("unlink", async (filepath) => { + if (filepath.endsWith(".bp")) { + this.log("INFO", `File ${filepath} removed`, "orange"); + const relativePath = path.relative(this.options.srcDir, filepath); + const htmlPath = path.join( + this.options.outDir, + relativePath.replace(/\.bp$/, ".html") + ); + const cssPath = path.join( + this.options.outDir, + relativePath.replace(/\.bp$/, ".css") + ); + if (fs.existsSync(htmlPath)) { + fs.unlinkSync(htmlPath); + } + if (fs.existsSync(cssPath)) { + fs.unlinkSync(cssPath); + } + const dirPath = path.dirname(htmlPath); + if (fs.existsSync(dirPath) && fs.readdirSync(dirPath).length === 0) { + fs.rmdirSync(dirPath); + } + } + }); + } + + async start() { + await this.buildAll(); + this.app.listen(this.options.port, () => { + this.log( + "INFO", + `Blueprint dev server running at http://localhost:${this.options.port}`, + "green" + ); + this.log( + "INFO", + `Mode: ${this.options.minified ? "Minified" : "Human Readable"}`, + "lightGray" + ); + if (this.options.liveReload) { + this.log( + "INFO", + "Live reload enabled - watching for changes...", + "lightGray" + ); + } + }); + } +} + +module.exports = BlueprintServer; diff --git a/package.json b/package.json new file mode 100644 index 0000000..98e9ac1 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "blueprint", + "version": "1.0.0", + "description": "A modern UI component compiler with live reload support", + "main": "lib/BlueprintBuilder.js", + "scripts": { + "build": "node lib/build.js --debug && echo \"Built successfully! You can now deploy the dist folder.\" && exit 0", + "dev": "node lib/dev-server.js --live" + }, + "dependencies": { + "axios": "^1.7.9", + "chokidar": "^3.5.3", + "express": "^4.18.2", + "express-ws": "^5.0.2", + "ws": "^8.18.0" + }, + "devDependencies": { + "node-fetch": "^3.3.2" + }, + "keywords": [ + "ui", + "compiler", + "live-reload", + "development" + ], + "author": "", + "license": "MIT" +} diff --git a/src/index.bp b/src/index.bp new file mode 100644 index 0000000..4c5cd79 --- /dev/null +++ b/src/index.bp @@ -0,0 +1,15 @@ + page(favicon:"/favicon.ico") { + title { "Blueprint - Modern Web UI Language" } + description { "It works!" } + keywords { "blueprint, language, web, ui, modern" } + author { "Epilogue Team" } +} + + +section(wide, centered) { + vertical(centered,wide) { + title(huge) { "It works!" } + text(subtle, large) { "Start using Blueprint at src/" } + text(small) { "Find examples at examples/" } + } +}