juxscript 1.1.0 → 1.1.3

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.
@@ -0,0 +1,46 @@
1
+ import esbuild from 'esbuild';
2
+
3
+ /**
4
+ * TypeScript Shim - Strips type annotations using esbuild
5
+ * This is rock-solid and handles ALL TypeScript syntax correctly
6
+ */
7
+
8
+ /**
9
+ * Strip TypeScript type annotations from code using esbuild
10
+ *
11
+ * @param {string} code - TypeScript source code
12
+ * @returns {string} - JavaScript code with types removed
13
+ */
14
+ export function stripTypes(code) {
15
+ try {
16
+ // ✅ Use esbuild to transform TypeScript → JavaScript
17
+ const result = esbuild.transformSync(code, {
18
+ loader: 'ts',
19
+ format: 'esm',
20
+ target: 'es2020'
21
+ });
22
+
23
+ return result.code;
24
+ } catch (err) {
25
+ console.error('❌ Failed to strip TypeScript:', err.message);
26
+ // Return original code if transformation fails
27
+ return code;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Check if a file is TypeScript based on extension
33
+ */
34
+ export function isTypeScript(filePath) {
35
+ return filePath.endsWith('.ts') || filePath.endsWith('.tsx');
36
+ }
37
+
38
+ /**
39
+ * Load and parse a file, automatically stripping types if it's TypeScript
40
+ */
41
+ export function loadAndStripTypes(filePath, fileContent) {
42
+ if (isTypeScript(filePath)) {
43
+ return stripTypes(fileContent);
44
+ }
45
+ return fileContent;
46
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * File validation utilities for Jux compiler
3
+ * Validates file types and content security
4
+ */
5
+ export class FileValidator {
6
+ constructor() {
7
+ this.cssExtensions = /\.(css|scss|sass|less)$/i;
8
+ this.jsExtensions = /\.(js|mjs|ts|tsx|jsx)$/i;
9
+ this.imageExtensions = /\.(png|jpg|jpeg|gif|svg|webp|ico|bmp)$/i;
10
+ }
11
+
12
+ /**
13
+ * Check if file is a CSS file
14
+ */
15
+ isCSSFile(filepath) {
16
+ return this.cssExtensions.test(filepath);
17
+ }
18
+
19
+ /**
20
+ * Check if file is a JavaScript file
21
+ */
22
+ isJavaScriptFile(filepath) {
23
+ return this.jsExtensions.test(filepath);
24
+ }
25
+
26
+ /**
27
+ * Check if file is an image file
28
+ */
29
+ isImageFile(filepath) {
30
+ return this.imageExtensions.test(filepath);
31
+ }
32
+
33
+ /**
34
+ * Validate CSS content for security issues
35
+ * Detects <script> tags that could be injected
36
+ */
37
+ validateStyleContent(content, source = 'unknown') {
38
+ if (/<script/i.test(content)) {
39
+ throw new Error(
40
+ `🚨 Security Error: <script> tag detected in ${source}\n` +
41
+ `CSS content must not contain script tags.`
42
+ );
43
+ }
44
+
45
+ if (/<\/script/i.test(content)) {
46
+ throw new Error(
47
+ `🚨 Security Error: </script> tag detected in ${source}\n` +
48
+ `CSS content must not contain script tags.`
49
+ );
50
+ }
51
+
52
+ return content;
53
+ }
54
+
55
+ /**
56
+ * Determine import type based on file extension
57
+ * Returns: 'css' | 'js' | 'image' | 'unknown'
58
+ */
59
+ validateImportPath(importPath) {
60
+ // Handle URLs
61
+ if (importPath.startsWith('http://') || importPath.startsWith('https://')) {
62
+ // Try to infer from URL
63
+ if (this.isCSSFile(importPath)) return { type: 'css', path: importPath };
64
+ if (this.isJavaScriptFile(importPath)) return { type: 'js', path: importPath };
65
+ if (this.isImageFile(importPath)) return { type: 'image', path: importPath };
66
+
67
+ // Default to unknown for CDN URLs without clear extensions
68
+ return { type: 'unknown', path: importPath };
69
+ }
70
+
71
+ // Local files
72
+ if (this.isCSSFile(importPath)) {
73
+ return { type: 'css', path: importPath };
74
+ }
75
+
76
+ if (this.isJavaScriptFile(importPath)) {
77
+ return { type: 'js', path: importPath };
78
+ }
79
+
80
+ if (this.isImageFile(importPath)) {
81
+ return { type: 'image', path: importPath };
82
+ }
83
+
84
+ return { type: 'unknown', path: importPath };
85
+ }
86
+
87
+ /**
88
+ * Validate array of imports and categorize them
89
+ * Returns categorized imports with warnings
90
+ */
91
+ categorizeImports(imports) {
92
+ const categorized = {
93
+ css: [],
94
+ js: [],
95
+ images: [],
96
+ unknown: []
97
+ };
98
+
99
+ const warnings = [];
100
+
101
+ for (const importPath of imports) {
102
+ const result = this.validateImportPath(importPath);
103
+
104
+ if (result.type === 'unknown') {
105
+ warnings.push(
106
+ `⚠️ Unknown import type: ${importPath}\n` +
107
+ ` Supported: .css/.scss/.sass, .js/.ts, .png/.jpg/.svg`
108
+ );
109
+ }
110
+
111
+ categorized[result.type === 'unknown' ? 'unknown' : result.type].push(result.path);
112
+ }
113
+
114
+ return { categorized, warnings };
115
+ }
116
+
117
+ /**
118
+ * Check if inline style content is empty or whitespace-only
119
+ */
120
+ isEmptyStyle(styleContent) {
121
+ return !styleContent || styleContent.trim().length === 0;
122
+ }
123
+ }
@@ -0,0 +1,59 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Watch a directory for changes and trigger callbacks
6
+ */
7
+ export function createWatcher(srcDir, options = {}) {
8
+ const {
9
+ onChange = () => { },
10
+ onReady = () => { },
11
+ debounceMs = 100,
12
+ extensions = ['.jux', '.js', '.css']
13
+ } = options;
14
+
15
+ const absoluteSrcDir = path.resolve(srcDir);
16
+ let debounceTimer = null;
17
+ let pendingChanges = new Set();
18
+
19
+ console.log(`👀 Watching: ${absoluteSrcDir}`);
20
+
21
+ // Debounced change handler
22
+ const handleChange = (eventType, filename) => {
23
+ if (!filename) return;
24
+
25
+ // Filter by extension
26
+ const ext = path.extname(filename);
27
+ if (!extensions.includes(ext)) return;
28
+
29
+ pendingChanges.add(filename);
30
+
31
+ // Debounce rapid changes
32
+ if (debounceTimer) clearTimeout(debounceTimer);
33
+ debounceTimer = setTimeout(() => {
34
+ const changes = [...pendingChanges];
35
+ pendingChanges.clear();
36
+
37
+ console.log(`📝 Changed: ${changes.join(', ')}`);
38
+ onChange(changes);
39
+ }, debounceMs);
40
+ };
41
+
42
+ // Start watching
43
+ const watcher = fs.watch(absoluteSrcDir, { recursive: true }, handleChange);
44
+
45
+ watcher.on('error', (err) => {
46
+ console.error('❌ Watcher error:', err);
47
+ });
48
+
49
+ onReady();
50
+
51
+ // Return control object
52
+ return {
53
+ close: () => {
54
+ if (debounceTimer) clearTimeout(debounceTimer);
55
+ watcher.close();
56
+ console.log('👋 Watcher closed');
57
+ }
58
+ };
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.1.00",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "index.js",
@@ -19,8 +19,9 @@
19
19
  "./package.json": "./package.json"
20
20
  },
21
21
  "files": [
22
- "lib",
23
22
  "bin",
23
+ "lib",
24
+ "machinery",
24
25
  "index.js",
25
26
  "index.d.ts",
26
27
  "juxconfig.example.js",