juxscript 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/bin/cli.js +121 -72
  2. package/lib/components/alert.ts +212 -165
  3. package/lib/components/badge.ts +93 -103
  4. package/lib/components/base/BaseComponent.ts +397 -0
  5. package/lib/components/base/FormInput.ts +322 -0
  6. package/lib/components/button.ts +63 -122
  7. package/lib/components/card.ts +109 -155
  8. package/lib/components/charts/areachart.ts +315 -0
  9. package/lib/components/charts/barchart.ts +421 -0
  10. package/lib/components/charts/doughnutchart.ts +263 -0
  11. package/lib/components/charts/lib/BaseChart.ts +402 -0
  12. package/lib/components/charts/lib/chart-types.ts +159 -0
  13. package/lib/components/charts/lib/chart-utils.ts +160 -0
  14. package/lib/components/charts/lib/chart.ts +707 -0
  15. package/lib/components/checkbox.ts +264 -127
  16. package/lib/components/code.ts +75 -108
  17. package/lib/components/container.ts +113 -130
  18. package/lib/components/data.ts +37 -5
  19. package/lib/components/datepicker.ts +195 -147
  20. package/lib/components/dialog.ts +187 -157
  21. package/lib/components/divider.ts +85 -191
  22. package/lib/components/docs-data.json +544 -2027
  23. package/lib/components/dropdown.ts +178 -136
  24. package/lib/components/element.ts +227 -171
  25. package/lib/components/fileupload.ts +285 -228
  26. package/lib/components/guard.ts +92 -0
  27. package/lib/components/heading.ts +46 -69
  28. package/lib/components/helpers.ts +13 -6
  29. package/lib/components/hero.ts +107 -95
  30. package/lib/components/icon.ts +160 -0
  31. package/lib/components/icons.ts +175 -0
  32. package/lib/components/include.ts +153 -5
  33. package/lib/components/input.ts +174 -374
  34. package/lib/components/kpicard.ts +16 -16
  35. package/lib/components/list.ts +378 -240
  36. package/lib/components/loading.ts +142 -211
  37. package/lib/components/menu.ts +103 -97
  38. package/lib/components/modal.ts +138 -144
  39. package/lib/components/nav.ts +169 -90
  40. package/lib/components/paragraph.ts +49 -150
  41. package/lib/components/progress.ts +118 -200
  42. package/lib/components/radio.ts +297 -149
  43. package/lib/components/script.ts +19 -87
  44. package/lib/components/select.ts +184 -186
  45. package/lib/components/sidebar.ts +152 -140
  46. package/lib/components/style.ts +19 -82
  47. package/lib/components/switch.ts +258 -188
  48. package/lib/components/table.ts +1117 -170
  49. package/lib/components/tabs.ts +162 -145
  50. package/lib/components/theme-toggle.ts +108 -169
  51. package/lib/components/tooltip.ts +86 -157
  52. package/lib/components/write.ts +108 -127
  53. package/lib/jux.ts +86 -41
  54. package/machinery/build.js +466 -0
  55. package/machinery/compiler.js +354 -105
  56. package/machinery/server.js +23 -100
  57. package/machinery/watcher.js +153 -130
  58. package/package.json +1 -2
  59. package/presets/base.css +1166 -0
  60. package/presets/notion.css +2 -1975
  61. package/lib/adapters/base-adapter.js +0 -35
  62. package/lib/adapters/index.js +0 -33
  63. package/lib/adapters/mysql-adapter.js +0 -65
  64. package/lib/adapters/postgres-adapter.js +0 -70
  65. package/lib/adapters/sqlite-adapter.js +0 -56
  66. package/lib/components/areachart.ts +0 -1246
  67. package/lib/components/areachartsmooth.ts +0 -1380
  68. package/lib/components/barchart.ts +0 -1250
  69. package/lib/components/chart.ts +0 -127
  70. package/lib/components/doughnutchart.ts +0 -1191
  71. package/lib/components/footer.ts +0 -165
  72. package/lib/components/header.ts +0 -187
  73. package/lib/components/layout.ts +0 -239
  74. package/lib/components/main.ts +0 -137
  75. package/lib/layouts/default.jux +0 -8
  76. package/lib/layouts/figma.jux +0 -0
  77. /package/lib/{themes → components/charts/lib}/charts.js +0 -0
@@ -0,0 +1,160 @@
1
+ import { BaseComponent } from './base/BaseComponent.js';
2
+ import { renderIcon, renderEmoji } from './icons.js';
3
+
4
+ // Event definitions
5
+ const TRIGGER_EVENTS = [] as const;
6
+ const CALLBACK_EVENTS = [] as const;
7
+
8
+ export interface IconOptions {
9
+ value: string;
10
+ size?: string;
11
+ color?: string;
12
+ useEmoji?: boolean;
13
+ style?: string;
14
+ class?: string;
15
+ }
16
+
17
+ type IconState = {
18
+ value: string;
19
+ size: string;
20
+ color: string;
21
+ useEmoji: boolean;
22
+ style: string;
23
+ class: string;
24
+ };
25
+
26
+ export class Icon extends BaseComponent<IconState> {
27
+ constructor(id: string, options: IconOptions) {
28
+ super(id, {
29
+ value: options.value,
30
+ size: options.size ?? '24px',
31
+ color: options.color ?? '',
32
+ useEmoji: options.useEmoji ?? false,
33
+ style: options.style ?? '',
34
+ class: options.class ?? ''
35
+ });
36
+ }
37
+
38
+ protected getTriggerEvents(): readonly string[] {
39
+ return TRIGGER_EVENTS;
40
+ }
41
+
42
+ protected getCallbackEvents(): readonly string[] {
43
+ return CALLBACK_EVENTS;
44
+ }
45
+
46
+ /* ═════════════════════════════════════════════════════════════════
47
+ * FLUENT API
48
+ * ═════════════════════════════════════════════════════════════════ */
49
+
50
+ // ✅ Inherited from BaseComponent
51
+
52
+ value(value: string): this {
53
+ this.state.value = value;
54
+ return this;
55
+ }
56
+
57
+ size(value: string): this {
58
+ this.state.size = value;
59
+ return this;
60
+ }
61
+
62
+ color(value: string): this {
63
+ this.state.color = value;
64
+ return this;
65
+ }
66
+
67
+ useEmoji(value: boolean): this {
68
+ this.state.useEmoji = value;
69
+ return this;
70
+ }
71
+
72
+ /* ═════════════════════════════════════════════════════════════════
73
+ * RENDER
74
+ * ═════════════════════════════════════════════════════════════════ */
75
+
76
+ render(targetId?: string): this {
77
+ const container = this._setupContainer(targetId);
78
+
79
+ const { value, size, color, useEmoji, style, class: className } = this.state;
80
+
81
+ const wrapper = document.createElement('span');
82
+ wrapper.className = 'jux-icon';
83
+ wrapper.id = this._id;
84
+ if (className) wrapper.className += ` ${className}`;
85
+ if (style) wrapper.setAttribute('style', style);
86
+
87
+ const iconElement = useEmoji ? renderEmoji(value) : renderIcon(value);
88
+ iconElement.style.width = size;
89
+ iconElement.style.height = size;
90
+ if (color) iconElement.style.color = color;
91
+
92
+ wrapper.appendChild(iconElement);
93
+
94
+ this._wireStandardEvents(wrapper);
95
+
96
+ // Wire sync bindings
97
+ this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
98
+ if (property === 'value') {
99
+ const transform = toComponent || ((v: any) => String(v));
100
+
101
+ stateObj.subscribe((val: any) => {
102
+ const transformed = transform(val);
103
+ this.state.value = transformed;
104
+
105
+ wrapper.innerHTML = '';
106
+ const newIcon = this.state.useEmoji ? renderEmoji(transformed) : renderIcon(transformed);
107
+ newIcon.style.width = this.state.size;
108
+ newIcon.style.height = this.state.size;
109
+ if (this.state.color) newIcon.style.color = this.state.color;
110
+ wrapper.appendChild(newIcon);
111
+
112
+ requestAnimationFrame(() => {
113
+ if ((window as any).lucide) {
114
+ (window as any).lucide.createIcons();
115
+ }
116
+ });
117
+ });
118
+ }
119
+ else if (property === 'size') {
120
+ const transform = toComponent || ((v: any) => String(v));
121
+
122
+ stateObj.subscribe((val: any) => {
123
+ const transformed = transform(val);
124
+ const icon = wrapper.querySelector('img, svg, span');
125
+ if (icon instanceof HTMLElement) {
126
+ icon.style.width = transformed;
127
+ icon.style.height = transformed;
128
+ }
129
+ this.state.size = transformed;
130
+ });
131
+ }
132
+ else if (property === 'color') {
133
+ const transform = toComponent || ((v: any) => String(v));
134
+
135
+ stateObj.subscribe((val: any) => {
136
+ const transformed = transform(val);
137
+ const icon = wrapper.querySelector('img, svg, span');
138
+ if (icon instanceof HTMLElement) {
139
+ icon.style.color = transformed;
140
+ }
141
+ this.state.color = transformed;
142
+ });
143
+ }
144
+ });
145
+
146
+ container.appendChild(wrapper);
147
+
148
+ requestAnimationFrame(() => {
149
+ if ((window as any).lucide) {
150
+ (window as any).lucide.createIcons();
151
+ }
152
+ });
153
+
154
+ return this;
155
+ }
156
+ }
157
+
158
+ export function icon(id: string, options: IconOptions): Icon {
159
+ return new Icon(id, options);
160
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Icon utilities for components
3
+ * Handles emoji-to-Lucide mapping, direct icon names, and image paths
4
+ */
5
+
6
+ const EMOJI_TO_LUCIDE: Record<string, string> = {
7
+ "✔️": "check-circle",
8
+ "✓": "check",
9
+ "❌": "x-circle",
10
+ "✗": "x",
11
+ "🔥": "flame",
12
+ "🚀": "rocket",
13
+ "⚙️": "settings",
14
+ "🏠": "home",
15
+ "👤": "user",
16
+ "💡": "lightbulb",
17
+ "🌈": "rainbow",
18
+ "🧪": "flask-conical",
19
+ "✉️": "mail",
20
+ "📞": "phone",
21
+ "🔍": "search",
22
+ "❤️": "heart",
23
+ "⭐": "star",
24
+ "⚠️": "alert-triangle",
25
+ "ℹ️": "info",
26
+ "❓": "help-circle",
27
+ "👁️": "eye",
28
+ "👁️‍🗨️": "eye-off",
29
+ "☰": "menu",
30
+ "🕐": "clock",
31
+ "📅": "calendar",
32
+ "⬇️": "chevron-down",
33
+ "⬆️": "chevron-up",
34
+ "⬅️": "chevron-left",
35
+ "➡️": "chevron-right",
36
+ "📈": "arrow-up",
37
+ "📉": "arrow-down",
38
+ "⬇": "download",
39
+ "📤": "upload",
40
+ "📄": "file-text",
41
+ "🗑️": "trash-2",
42
+ "✏️": "edit",
43
+ "📋": "clipboard",
44
+ "🔗": "link",
45
+ "↗️": "external-link",
46
+ "☀️": "sun",
47
+ "🌙": "moon",
48
+ "📊": "bar-chart-3",
49
+ "📁": "folder",
50
+ "💰": "coins",
51
+ "📧": "mail",
52
+ "✅": "square-check",
53
+ "🗓️": "calendar-days",
54
+ "💬": "message-circle",
55
+ "🌐": "globe",
56
+ "🔬": "microscope",
57
+ "💊": "pill",
58
+ "🔒": "lock",
59
+ "⚖️": "scale",
60
+ "🔌": "plug",
61
+ "🔐": "lock-keyhole",
62
+ "🏥": "cross",
63
+ "👥": "users",
64
+ "💚": "heart",
65
+ "💸": "banknote",
66
+ "🧾": "receipt",
67
+ "➕": "plus",
68
+ "➖": "minus",
69
+ "💾": "save",
70
+ "🩺": "stethoscope"
71
+ };
72
+
73
+ const LUCIDE_CDN_URL = "https://unpkg.com/lucide@latest";
74
+
75
+ /**
76
+ * Render an icon from emoji, icon name, or image path
77
+ * @param value - Emoji (🚀), icon name (rocket), or image path (/icon.png)
78
+ * @returns HTMLElement containing the icon
79
+ *
80
+ * Usage:
81
+ * const icon = renderIcon('🚀'); // Lucide rocket icon
82
+ * const icon = renderIcon('rocket'); // Lucide rocket icon
83
+ * const icon = renderIcon('/icon.png'); // Image element
84
+ */
85
+ export function renderIcon(value: string): HTMLElement {
86
+ // Check if it's an image path (contains / or . or starts with http)
87
+ if (value.includes('/') || value.includes('.') || value.startsWith('http')) {
88
+ return createImageIcon(value);
89
+ }
90
+
91
+ // Check if it's an emoji that maps to Lucide
92
+ const lucideName = EMOJI_TO_LUCIDE[value];
93
+ if (lucideName) {
94
+ const element = createVectorIcon(lucideName);
95
+ ensureLucideLoaded();
96
+ return element;
97
+ }
98
+
99
+ // Check if it's a direct Lucide icon name (lowercase with hyphens)
100
+ if (/^[a-z][a-z0-9-]*$/.test(value)) {
101
+ const element = createVectorIcon(value);
102
+ ensureLucideLoaded();
103
+ return element;
104
+ }
105
+
106
+ // Fallback: render as emoji
107
+ return createEmojiFallback(value);
108
+ }
109
+
110
+ /**
111
+ * Render raw emoji without conversion
112
+ * @param emoji - The emoji character
113
+ * @returns HTMLElement containing just the emoji
114
+ */
115
+ export function renderEmoji(emoji: string): HTMLElement {
116
+ return createEmojiFallback(emoji);
117
+ }
118
+
119
+ /**
120
+ * Ensures Lucide is loaded and icons are rendered
121
+ */
122
+ function ensureLucideLoaded(): void {
123
+ if ((window as any).lucide) {
124
+ // Already loaded, render immediately
125
+ (window as any).lucide.createIcons();
126
+ return;
127
+ }
128
+
129
+ // Not loaded yet, inject script
130
+ if (!document.querySelector(`script[src="${LUCIDE_CDN_URL}"]`)) {
131
+ const script = document.createElement('script');
132
+ script.src = LUCIDE_CDN_URL;
133
+ script.onload = () => {
134
+ if ((window as any).lucide) {
135
+ (window as any).lucide.createIcons();
136
+ }
137
+ };
138
+ document.head.appendChild(script);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Create Lucide icon element
144
+ */
145
+ function createVectorIcon(name: string): HTMLElement {
146
+ const iconEl = document.createElement('i');
147
+ iconEl.setAttribute('data-lucide', name);
148
+ iconEl.style.width = '24px';
149
+ iconEl.style.height = '24px';
150
+ iconEl.style.display = 'inline-block';
151
+ return iconEl;
152
+ }
153
+
154
+ /**
155
+ * Create image icon element
156
+ */
157
+ function createImageIcon(src: string): HTMLImageElement {
158
+ const img = document.createElement('img');
159
+ img.src = src;
160
+ img.style.width = '24px';
161
+ img.style.height = '24px';
162
+ img.style.display = 'inline-block';
163
+ img.style.objectFit = 'contain';
164
+ return img;
165
+ }
166
+
167
+ /**
168
+ * Render native emoji or text
169
+ */
170
+ function createEmojiFallback(emoji: string): HTMLSpanElement {
171
+ const span = document.createElement('span');
172
+ span.textContent = emoji;
173
+ span.style.display = 'inline-block';
174
+ return span;
175
+ }
@@ -5,7 +5,7 @@ import { ErrorHandler } from './error-handler.js';
5
5
  * Auto-detects resource type from URL and provides simple, fluent API
6
6
  */
7
7
 
8
- type IncludeType = 'stylesheet' | 'script' | 'image' | 'font' | 'preload' | 'prefetch' | 'module';
8
+ type IncludeType = 'stylesheet' | 'script' | 'image' | 'font' | 'preload' | 'prefetch' | 'module' | 'json';
9
9
  type IncludeLocation = 'head' | 'body-start' | 'body-end';
10
10
 
11
11
  interface IncludeOptions {
@@ -22,6 +22,7 @@ export class Include {
22
22
  private type: IncludeType;
23
23
  private options: IncludeOptions = {};
24
24
  private element: HTMLElement | null = null;
25
+ private explicitType: boolean = false; // NEW: Track if type was explicitly set
25
26
 
26
27
  constructor(urlOrFile: string) {
27
28
  this.url = urlOrFile;
@@ -33,10 +34,25 @@ export class Include {
33
34
  * ------------------------- */
34
35
 
35
36
  private detectType(url: string): IncludeType {
37
+ // Check for common script patterns in URLs (CDN, etc.)
38
+ if (url.includes('tailwindcss') ||
39
+ url.includes('jsdelivr.net/npm') ||
40
+ url.includes('unpkg.com') ||
41
+ url.includes('cdn.') ||
42
+ url.match(/\.(js|mjs)($|\?)/)) {
43
+ return 'script';
44
+ }
45
+
36
46
  if (url.endsWith('.css')) return 'stylesheet';
37
- if (url.endsWith('.js') || url.endsWith('.mjs')) return 'script';
47
+ if (url.endsWith('.json')) return 'json';
38
48
  if (url.match(/\.(png|jpg|jpeg|gif|svg|webp)$/i)) return 'image';
39
49
  if (url.match(/\.(woff|woff2|ttf|otf|eot)$/i)) return 'font';
50
+
51
+ // Default to script for extensionless URLs from CDN domains
52
+ if (!url.includes('.') || url.match(/^https?:\/\/cdn/)) {
53
+ return 'script';
54
+ }
55
+
40
56
  return 'preload';
41
57
  }
42
58
 
@@ -44,41 +60,144 @@ export class Include {
44
60
  * Fluent Type Setters
45
61
  * ------------------------- */
46
62
 
63
+ /**
64
+ * Force treat as CSS stylesheet
65
+ * Use when URL doesn't have .css extension
66
+ */
47
67
  withCss(): this {
48
68
  this.type = 'stylesheet';
69
+ this.explicitType = true; // Mark as explicit
49
70
  return this;
50
71
  }
51
72
 
73
+ /**
74
+ * Force treat as JavaScript
75
+ * Use when URL doesn't have .js extension (CDN scripts, etc.)
76
+ *
77
+ * @example
78
+ * jux.include('https://cdn.tailwindcss.com').withJs().render();
79
+ * jux.include('https://unpkg.com/alpine').withJs({ defer: true }).render();
80
+ */
52
81
  withJs(options?: { async?: boolean; defer?: boolean }): this {
53
82
  this.type = 'script';
83
+ this.explicitType = true; // Mark as explicit
54
84
  if (options?.async) this.options.async = true;
55
85
  if (options?.defer) this.options.defer = true;
56
86
  return this;
57
87
  }
58
88
 
89
+ /**
90
+ * Force treat as ES module
91
+ * Use for module scripts
92
+ */
59
93
  withModule(): this {
60
94
  this.type = 'module';
95
+ this.explicitType = true; // Mark as explicit
61
96
  return this;
62
97
  }
63
98
 
64
99
  withImage(): this {
65
100
  this.type = 'image';
101
+ this.explicitType = true;
66
102
  return this;
67
103
  }
68
104
 
69
105
  withFont(): this {
70
106
  this.type = 'font';
107
+ this.explicitType = true;
71
108
  return this;
72
109
  }
73
110
 
74
111
  withPreload(as?: string): this {
75
112
  this.type = 'preload';
113
+ this.explicitType = true;
76
114
  if (as) this.options.as = as;
77
115
  return this;
78
116
  }
79
117
 
80
118
  withPrefetch(): this {
81
119
  this.type = 'prefetch';
120
+ this.explicitType = true;
121
+ return this;
122
+ }
123
+
124
+ withJson(): this {
125
+ this.type = 'json';
126
+ this.explicitType = true;
127
+ return this;
128
+ }
129
+
130
+ /* -------------------------
131
+ * Convenience aliases for common patterns
132
+ * ------------------------- */
133
+
134
+ /**
135
+ * Shorthand for .withJs()
136
+ * @example jux.include(url).asScript()
137
+ */
138
+ asScript(options?: { async?: boolean; defer?: boolean }): this {
139
+ return this.withJs(options);
140
+ }
141
+
142
+ /**
143
+ * Shorthand for .withCss()
144
+ * @example jux.include(url).asStylesheet()
145
+ */
146
+ asStylesheet(): this {
147
+ return this.withCss();
148
+ }
149
+
150
+ /* -------------------------
151
+ * JSON Fetching
152
+ * ------------------------- */
153
+
154
+ /**
155
+ * Fetch and parse JSON file
156
+ * Returns a Promise that resolves to the parsed JSON data
157
+ *
158
+ * Usage:
159
+ * const config = await jux.include('config.json').asJson();
160
+ * const data = await jux.include('/api/data').asJson();
161
+ */
162
+ async asJson<T = any>(): Promise<T> {
163
+ try {
164
+ const response = await fetch(this.url);
165
+
166
+ if (!response.ok) {
167
+ throw new Error(`HTTP error! status: ${response.status}`);
168
+ }
169
+
170
+ const data = await response.json();
171
+ console.log(`✓ JSON loaded: ${this.url}`);
172
+ return data;
173
+ } catch (error: any) {
174
+ ErrorHandler.captureError({
175
+ component: 'Include',
176
+ method: 'asJson',
177
+ message: error.message,
178
+ stack: error.stack,
179
+ timestamp: new Date(),
180
+ context: {
181
+ url: this.url,
182
+ error: 'json_fetch_failed'
183
+ }
184
+ });
185
+ throw error;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Fetch JSON and execute callback with data
191
+ *
192
+ * Usage:
193
+ * jux.include('config.json').onJson(data => {
194
+ * console.log('Config:', data);
195
+ * });
196
+ */
197
+ onJson<T = any>(callback: (data: T) => void): this {
198
+ this.asJson<T>().then(callback).catch(error => {
199
+ console.error('Failed to load JSON:', error);
200
+ });
82
201
  return this;
83
202
  }
84
203
 
@@ -128,6 +247,12 @@ export class Include {
128
247
  render(): this {
129
248
  if (typeof document === 'undefined') return this;
130
249
 
250
+ // Don't render JSON type (it's fetched via asJson() instead)
251
+ if (this.type === 'json') {
252
+ console.warn('Include: JSON files should be loaded with .asJson() instead of .render()');
253
+ return this;
254
+ }
255
+
131
256
  try {
132
257
  this.remove();
133
258
 
@@ -161,6 +286,10 @@ export class Include {
161
286
  }
162
287
 
163
288
  this.element = element;
289
+
290
+ // Log with type indicator
291
+ const typeIndicator = this.explicitType ? '(explicit)' : '(auto-detected)';
292
+ console.log(`✓ Include loaded as ${this.type} ${typeIndicator}: ${this.url}`);
164
293
  } catch (error: any) {
165
294
  ErrorHandler.captureError({
166
295
  component: 'Include',
@@ -172,6 +301,7 @@ export class Include {
172
301
  type: this.type,
173
302
  url: this.url,
174
303
  location: this.options.location,
304
+ explicitType: this.explicitType,
175
305
  error: 'runtime_exception'
176
306
  }
177
307
  });
@@ -279,14 +409,32 @@ export class Include {
279
409
  * Factory function - auto-detects type and renders immediately
280
410
  *
281
411
  * Usage:
412
+ * // Auto-detect (works for most cases)
282
413
  * jux.include('styles.css');
283
414
  * jux.include('script.js').async();
415
+ *
416
+ * // Explicit type (for extensionless URLs)
417
+ * jux.include('https://cdn.tailwindcss.com').withJs();
418
+ * jux.include('https://cdn.tailwindcss.com').asScript();
419
+ * jux.include('https://unpkg.com/htmx.org').withJs({ defer: true });
420
+ *
421
+ * // CDN with parameters
422
+ * jux.include('https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4').withJs();
423
+ *
424
+ * // Module
284
425
  * jux.include('app.mjs').withModule();
285
- * jux.include('custom.js').withJs({ async: true, defer: true });
286
- * jux.include('https://cdn.com/lib.js').inHead().defer();
426
+ *
427
+ * // For JSON:
428
+ * const data = await jux.include('config.json').asJson();
429
+ * jux.include('data.json').onJson(data => console.log(data));
287
430
  */
288
431
  export function include(urlOrFile: string): Include {
289
432
  const imp = new Include(urlOrFile);
290
- imp.render();
433
+
434
+ // Don't auto-render JSON files
435
+ if (imp['type'] !== 'json') {
436
+ imp.render();
437
+ }
438
+
291
439
  return imp;
292
440
  }