pulse-js-framework 1.4.9 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/analyze.js +8 -7
- package/cli/build.js +14 -13
- package/cli/dev.js +28 -7
- package/cli/format.js +13 -12
- package/cli/index.js +20 -1
- package/cli/lint.js +8 -7
- package/cli/release.js +493 -0
- package/compiler/parser.js +41 -20
- package/compiler/transformer/constants.js +54 -0
- package/compiler/transformer/export.js +33 -0
- package/compiler/transformer/expressions.js +273 -0
- package/compiler/transformer/imports.js +101 -0
- package/compiler/transformer/index.js +319 -0
- package/compiler/transformer/router.js +95 -0
- package/compiler/transformer/state.js +118 -0
- package/compiler/transformer/store.js +97 -0
- package/compiler/transformer/style.js +130 -0
- package/compiler/transformer/view.js +428 -0
- package/compiler/transformer.js +17 -1310
- package/core/errors.js +300 -0
- package/package.json +8 -5
- package/runtime/dom.js +61 -10
- package/runtime/lru-cache.js +145 -0
- package/runtime/native.js +6 -1
- package/runtime/pulse.js +46 -2
- package/runtime/router.js +4 -1
- package/runtime/store.js +35 -1
- package/runtime/utils.js +348 -0
- package/types/index.d.ts +19 -0
- package/types/lru-cache.d.ts +118 -0
- package/types/utils.d.ts +255 -0
package/cli/analyze.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { readFileSync, statSync, existsSync } from 'fs';
|
|
7
7
|
import { join, dirname, basename, relative } from 'path';
|
|
8
8
|
import { findPulseFiles, parseArgs, formatBytes, relativePath, resolveImportPath } from './utils/file-utils.js';
|
|
9
|
+
import { log } from './logger.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Analyze the bundle/project
|
|
@@ -472,28 +473,28 @@ export async function runAnalyze(args) {
|
|
|
472
473
|
|
|
473
474
|
// Check if src directory exists
|
|
474
475
|
if (!existsSync(join(root, 'src'))) {
|
|
475
|
-
|
|
476
|
-
|
|
476
|
+
log.error('Error: No src/ directory found.');
|
|
477
|
+
log.info('Run this command from your Pulse project root.');
|
|
477
478
|
process.exit(1);
|
|
478
479
|
}
|
|
479
480
|
|
|
480
|
-
|
|
481
|
+
log.info('Analyzing bundle...\n');
|
|
481
482
|
|
|
482
483
|
try {
|
|
483
484
|
const analysis = await analyzeBundle(root);
|
|
484
485
|
|
|
485
486
|
if (json) {
|
|
486
|
-
|
|
487
|
+
log.info(JSON.stringify(analysis, null, 2));
|
|
487
488
|
} else {
|
|
488
|
-
|
|
489
|
+
log.info(formatConsoleOutput(analysis, verbose));
|
|
489
490
|
}
|
|
490
491
|
|
|
491
492
|
// Exit with error if dead code found
|
|
492
493
|
if (analysis.deadCode.length > 0 && !json) {
|
|
493
|
-
|
|
494
|
+
log.warn(`\nWarning: ${analysis.deadCode.length} potentially unused file(s) found.`);
|
|
494
495
|
}
|
|
495
496
|
} catch (error) {
|
|
496
|
-
|
|
497
|
+
log.error('Analysis failed:', error.message);
|
|
497
498
|
process.exit(1);
|
|
498
499
|
}
|
|
499
500
|
}
|
package/cli/build.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync, copyFileSync } from 'fs';
|
|
8
8
|
import { join, extname, relative, dirname } from 'path';
|
|
9
9
|
import { compile } from '../compiler/index.js';
|
|
10
|
+
import { log } from './logger.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Build project for production
|
|
@@ -19,7 +20,7 @@ export async function buildProject(args) {
|
|
|
19
20
|
try {
|
|
20
21
|
const viteConfig = join(root, 'vite.config.js');
|
|
21
22
|
if (existsSync(viteConfig)) {
|
|
22
|
-
|
|
23
|
+
log.info('Vite config detected, using Vite build...');
|
|
23
24
|
const { build } = await import('vite');
|
|
24
25
|
await build({ root });
|
|
25
26
|
return;
|
|
@@ -28,7 +29,7 @@ export async function buildProject(args) {
|
|
|
28
29
|
// Vite not available, use built-in build
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
log.info('Building with Pulse compiler...');
|
|
32
33
|
|
|
33
34
|
// Create output directory
|
|
34
35
|
if (!existsSync(outDir)) {
|
|
@@ -67,7 +68,7 @@ export async function buildProject(args) {
|
|
|
67
68
|
// Bundle runtime
|
|
68
69
|
bundleRuntime(outDir);
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
log.success(`
|
|
71
72
|
Build complete!
|
|
72
73
|
|
|
73
74
|
Output directory: ${relative(root, outDir)}
|
|
@@ -104,11 +105,11 @@ function processDirectory(srcDir, outDir) {
|
|
|
104
105
|
if (result.success) {
|
|
105
106
|
const outPath = join(outDir, file.replace('.pulse', '.js'));
|
|
106
107
|
writeFileSync(outPath, result.code);
|
|
107
|
-
|
|
108
|
+
log.info(` Compiled: ${file}`);
|
|
108
109
|
} else {
|
|
109
|
-
|
|
110
|
+
log.error(` Error compiling ${file}:`);
|
|
110
111
|
for (const error of result.errors) {
|
|
111
|
-
|
|
112
|
+
log.error(` ${error.message}`);
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
} else if (file.endsWith('.js') || file.endsWith('.mjs')) {
|
|
@@ -129,7 +130,7 @@ function processDirectory(srcDir, outDir) {
|
|
|
129
130
|
|
|
130
131
|
const outPath = join(outDir, file);
|
|
131
132
|
writeFileSync(outPath, content);
|
|
132
|
-
|
|
133
|
+
log.info(` Processed & minified: ${file}`);
|
|
133
134
|
} else {
|
|
134
135
|
// Copy other files
|
|
135
136
|
const outPath = join(outDir, file);
|
|
@@ -155,9 +156,9 @@ ${readRuntimeFile('store.js')}
|
|
|
155
156
|
|
|
156
157
|
if (shouldMinify) {
|
|
157
158
|
runtimeCode = minifyJS(runtimeCode);
|
|
158
|
-
|
|
159
|
+
log.info(' Bundled & minified: runtime.js');
|
|
159
160
|
} else {
|
|
160
|
-
|
|
161
|
+
log.info(' Bundled: runtime.js');
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
writeFileSync(join(outDir, 'assets', 'runtime.js'), runtimeCode);
|
|
@@ -178,7 +179,7 @@ function readRuntimeFile(filename) {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
|
|
182
|
+
log.warn(` Warning: Could not find runtime file: ${filename}`);
|
|
182
183
|
return '';
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -263,7 +264,7 @@ export async function previewBuild(args) {
|
|
|
263
264
|
const distDir = join(root, 'dist');
|
|
264
265
|
|
|
265
266
|
if (!existsSync(distDir)) {
|
|
266
|
-
|
|
267
|
+
log.error('No dist folder found. Run "pulse build" first.');
|
|
267
268
|
process.exit(1);
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -271,7 +272,7 @@ export async function previewBuild(args) {
|
|
|
271
272
|
try {
|
|
272
273
|
const viteConfig = join(root, 'vite.config.js');
|
|
273
274
|
if (existsSync(viteConfig)) {
|
|
274
|
-
|
|
275
|
+
log.info('Using Vite preview...');
|
|
275
276
|
const { preview } = await import('vite');
|
|
276
277
|
const server = await preview({
|
|
277
278
|
root,
|
|
@@ -327,7 +328,7 @@ export async function previewBuild(args) {
|
|
|
327
328
|
});
|
|
328
329
|
|
|
329
330
|
server.listen(port, () => {
|
|
330
|
-
|
|
331
|
+
log.success(`
|
|
331
332
|
Pulse Preview Server running at:
|
|
332
333
|
|
|
333
334
|
Local: http://localhost:${port}/
|
package/cli/dev.js
CHANGED
|
@@ -8,6 +8,7 @@ import { createServer } from 'http';
|
|
|
8
8
|
import { readFileSync, existsSync, statSync, watch } from 'fs';
|
|
9
9
|
import { join, extname, resolve } from 'path';
|
|
10
10
|
import { compile } from '../compiler/index.js';
|
|
11
|
+
import { log } from './logger.js';
|
|
11
12
|
|
|
12
13
|
const MIME_TYPES = {
|
|
13
14
|
'.html': 'text/html',
|
|
@@ -31,14 +32,28 @@ const clients = new Set();
|
|
|
31
32
|
* Start the development server
|
|
32
33
|
*/
|
|
33
34
|
export async function startDevServer(args) {
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
// Parse args: can be [port], [dir], or [dir, port]
|
|
36
|
+
let port = 3000;
|
|
37
|
+
let root = process.cwd();
|
|
38
|
+
|
|
39
|
+
if (args.length >= 1) {
|
|
40
|
+
if (/^\d+$/.test(args[0])) {
|
|
41
|
+
// First arg is a port number
|
|
42
|
+
port = parseInt(args[0]);
|
|
43
|
+
} else {
|
|
44
|
+
// First arg is a directory
|
|
45
|
+
root = resolve(process.cwd(), args[0]);
|
|
46
|
+
if (args[1] && /^\d+$/.test(args[1])) {
|
|
47
|
+
port = parseInt(args[1]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
36
51
|
|
|
37
52
|
// Check if vite is available, use it if so
|
|
38
53
|
try {
|
|
39
54
|
const viteConfig = join(root, 'vite.config.js');
|
|
40
55
|
if (existsSync(viteConfig)) {
|
|
41
|
-
|
|
56
|
+
log.info('Vite config detected, using Vite...');
|
|
42
57
|
const { createServer: createViteServer } = await import('vite');
|
|
43
58
|
const server = await createViteServer({
|
|
44
59
|
root,
|
|
@@ -79,7 +94,10 @@ export async function startDevServer(args) {
|
|
|
79
94
|
try {
|
|
80
95
|
const source = readFileSync(filePath, 'utf-8');
|
|
81
96
|
const result = compile(source, {
|
|
82
|
-
runtime: '/runtime/index.js'
|
|
97
|
+
runtime: '/runtime/index.js',
|
|
98
|
+
sourceMap: true,
|
|
99
|
+
inlineSourceMap: true,
|
|
100
|
+
sourceFileName: pathname
|
|
83
101
|
});
|
|
84
102
|
|
|
85
103
|
if (result.success) {
|
|
@@ -112,7 +130,10 @@ export async function startDevServer(args) {
|
|
|
112
130
|
try {
|
|
113
131
|
const source = readFileSync(pulseFilePath, 'utf-8');
|
|
114
132
|
const result = compile(source, {
|
|
115
|
-
runtime: '/runtime/index.js'
|
|
133
|
+
runtime: '/runtime/index.js',
|
|
134
|
+
sourceMap: true,
|
|
135
|
+
inlineSourceMap: true,
|
|
136
|
+
sourceFileName: pulseFilePath.replace(root, '')
|
|
116
137
|
});
|
|
117
138
|
|
|
118
139
|
if (result.success) {
|
|
@@ -181,7 +202,7 @@ export async function startDevServer(args) {
|
|
|
181
202
|
watchFiles(root);
|
|
182
203
|
|
|
183
204
|
server.listen(port, () => {
|
|
184
|
-
|
|
205
|
+
log.success(`
|
|
185
206
|
Pulse Dev Server running at:
|
|
186
207
|
|
|
187
208
|
Local: http://localhost:${port}/
|
|
@@ -200,7 +221,7 @@ function watchFiles(root) {
|
|
|
200
221
|
if (existsSync(srcDir)) {
|
|
201
222
|
watch(srcDir, { recursive: true }, (eventType, filename) => {
|
|
202
223
|
if (filename && filename.endsWith('.pulse')) {
|
|
203
|
-
|
|
224
|
+
log.debug(`File changed: ${filename}`);
|
|
204
225
|
// Notify HMR clients (simplified)
|
|
205
226
|
notifyClients({ type: 'update', path: `/src/${filename}` });
|
|
206
227
|
}
|
package/cli/format.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { readFileSync, writeFileSync } from 'fs';
|
|
7
7
|
import { findPulseFiles, parseArgs, relativePath } from './utils/file-utils.js';
|
|
8
|
+
import { log } from './logger.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Default format options
|
|
@@ -645,11 +646,11 @@ export async function runFormat(args) {
|
|
|
645
646
|
const files = findPulseFiles(patterns);
|
|
646
647
|
|
|
647
648
|
if (files.length === 0) {
|
|
648
|
-
|
|
649
|
+
log.info('No .pulse files found to format.');
|
|
649
650
|
return;
|
|
650
651
|
}
|
|
651
652
|
|
|
652
|
-
|
|
653
|
+
log.info(`${check ? 'Checking' : 'Formatting'} ${files.length} file(s)...\n`);
|
|
653
654
|
|
|
654
655
|
let changedCount = 0;
|
|
655
656
|
let errorCount = 0;
|
|
@@ -659,7 +660,7 @@ export async function runFormat(args) {
|
|
|
659
660
|
const relPath = relativePath(file);
|
|
660
661
|
|
|
661
662
|
if (result.error) {
|
|
662
|
-
|
|
663
|
+
log.error(` ${relPath} - ERROR: ${result.error}`);
|
|
663
664
|
errorCount++;
|
|
664
665
|
continue;
|
|
665
666
|
}
|
|
@@ -668,37 +669,37 @@ export async function runFormat(args) {
|
|
|
668
669
|
changedCount++;
|
|
669
670
|
|
|
670
671
|
if (check) {
|
|
671
|
-
|
|
672
|
+
log.warn(` ${relPath} - needs formatting`);
|
|
672
673
|
} else if (write) {
|
|
673
674
|
writeFileSync(file, result.formatted);
|
|
674
|
-
|
|
675
|
+
log.info(` ${relPath} - formatted`);
|
|
675
676
|
}
|
|
676
677
|
} else {
|
|
677
678
|
if (!check) {
|
|
678
|
-
|
|
679
|
+
log.info(` ${relPath} - unchanged`);
|
|
679
680
|
}
|
|
680
681
|
}
|
|
681
682
|
}
|
|
682
683
|
|
|
683
684
|
// Summary
|
|
684
|
-
|
|
685
|
+
log.info('\n' + '─'.repeat(60));
|
|
685
686
|
|
|
686
687
|
if (errorCount > 0) {
|
|
687
|
-
|
|
688
|
+
log.error(`✗ ${errorCount} file(s) had errors`);
|
|
688
689
|
}
|
|
689
690
|
|
|
690
691
|
if (check) {
|
|
691
692
|
if (changedCount > 0) {
|
|
692
|
-
|
|
693
|
+
log.error(`✗ ${changedCount} file(s) need formatting`);
|
|
693
694
|
process.exit(1);
|
|
694
695
|
} else {
|
|
695
|
-
|
|
696
|
+
log.success(`✓ All ${files.length} file(s) are properly formatted`);
|
|
696
697
|
}
|
|
697
698
|
} else {
|
|
698
699
|
if (changedCount > 0) {
|
|
699
|
-
|
|
700
|
+
log.success(`✓ ${changedCount} file(s) formatted`);
|
|
700
701
|
} else {
|
|
701
|
-
|
|
702
|
+
log.success(`✓ All ${files.length} file(s) were already formatted`);
|
|
702
703
|
}
|
|
703
704
|
}
|
|
704
705
|
}
|
package/cli/index.js
CHANGED
|
@@ -28,7 +28,8 @@ const commands = {
|
|
|
28
28
|
mobile: runMobile,
|
|
29
29
|
lint: runLint,
|
|
30
30
|
format: runFormat,
|
|
31
|
-
analyze: runAnalyze
|
|
31
|
+
analyze: runAnalyze,
|
|
32
|
+
release: runReleaseCmd
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
/**
|
|
@@ -66,6 +67,7 @@ Commands:
|
|
|
66
67
|
lint [files] Validate .pulse files for errors and style
|
|
67
68
|
format [files] Format .pulse files consistently
|
|
68
69
|
analyze Analyze bundle size and dependencies
|
|
70
|
+
release <type> Create a new release (patch, minor, major)
|
|
69
71
|
version Show version number
|
|
70
72
|
help Show this help message
|
|
71
73
|
|
|
@@ -80,6 +82,12 @@ Analyze Options:
|
|
|
80
82
|
--json Output analysis as JSON
|
|
81
83
|
--verbose Show detailed metrics
|
|
82
84
|
|
|
85
|
+
Release Options:
|
|
86
|
+
--dry-run Show what would be done without making changes
|
|
87
|
+
--no-push Create commit and tag but don't push
|
|
88
|
+
--title <text> Release title for changelog
|
|
89
|
+
--skip-prompt Use empty changelog (for automation)
|
|
90
|
+
|
|
83
91
|
Examples:
|
|
84
92
|
pulse create my-app
|
|
85
93
|
pulse dev
|
|
@@ -96,6 +104,9 @@ Examples:
|
|
|
96
104
|
pulse format src/App.pulse
|
|
97
105
|
pulse analyze
|
|
98
106
|
pulse analyze --json
|
|
107
|
+
pulse release patch
|
|
108
|
+
pulse release minor --title "New Features"
|
|
109
|
+
pulse release major --dry-run
|
|
99
110
|
|
|
100
111
|
Documentation: https://github.com/vincenthirtz/pulse-js-framework
|
|
101
112
|
`);
|
|
@@ -359,6 +370,14 @@ async function runAnalyze(args) {
|
|
|
359
370
|
await runAnalyze(args);
|
|
360
371
|
}
|
|
361
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Run release command
|
|
375
|
+
*/
|
|
376
|
+
async function runReleaseCmd(args) {
|
|
377
|
+
const { runRelease } = await import('./release.js');
|
|
378
|
+
await runRelease(args);
|
|
379
|
+
}
|
|
380
|
+
|
|
362
381
|
/**
|
|
363
382
|
* Compile a single .pulse file
|
|
364
383
|
*/
|
package/cli/lint.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { readFileSync, writeFileSync } from 'fs';
|
|
7
7
|
import { findPulseFiles, parseArgs, relativePath } from './utils/file-utils.js';
|
|
8
|
+
import { log } from './logger.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Lint rules configuration
|
|
@@ -710,11 +711,11 @@ export async function runLint(args) {
|
|
|
710
711
|
const files = findPulseFiles(patterns);
|
|
711
712
|
|
|
712
713
|
if (files.length === 0) {
|
|
713
|
-
|
|
714
|
+
log.info('No .pulse files found to lint.');
|
|
714
715
|
return;
|
|
715
716
|
}
|
|
716
717
|
|
|
717
|
-
|
|
718
|
+
log.info(`Linting ${files.length} file(s)...\n`);
|
|
718
719
|
|
|
719
720
|
let totalErrors = 0;
|
|
720
721
|
let totalWarnings = 0;
|
|
@@ -725,10 +726,10 @@ export async function runLint(args) {
|
|
|
725
726
|
const relPath = relativePath(file);
|
|
726
727
|
|
|
727
728
|
if (result.diagnostics.length > 0) {
|
|
728
|
-
|
|
729
|
+
log.info(`\n${relPath}`);
|
|
729
730
|
|
|
730
731
|
for (const diag of result.diagnostics) {
|
|
731
|
-
|
|
732
|
+
log.info(formatDiagnostic(diag));
|
|
732
733
|
|
|
733
734
|
switch (diag.severity) {
|
|
734
735
|
case 'error': totalErrors++; break;
|
|
@@ -740,16 +741,16 @@ export async function runLint(args) {
|
|
|
740
741
|
}
|
|
741
742
|
|
|
742
743
|
// Summary
|
|
743
|
-
|
|
744
|
+
log.info('\n' + '─'.repeat(60));
|
|
744
745
|
const parts = [];
|
|
745
746
|
if (totalErrors > 0) parts.push(`${totalErrors} error(s)`);
|
|
746
747
|
if (totalWarnings > 0) parts.push(`${totalWarnings} warning(s)`);
|
|
747
748
|
if (totalInfo > 0) parts.push(`${totalInfo} info`);
|
|
748
749
|
|
|
749
750
|
if (parts.length === 0) {
|
|
750
|
-
|
|
751
|
+
log.success(`✓ ${files.length} file(s) passed`);
|
|
751
752
|
} else {
|
|
752
|
-
|
|
753
|
+
log.error(`✗ ${parts.join(', ')} in ${files.length} file(s)`);
|
|
753
754
|
}
|
|
754
755
|
|
|
755
756
|
// Exit with error code if errors found
|