pulse-js-framework 1.7.23 → 1.7.24
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/release.js +173 -25
- package/loader/vite-plugin.js +62 -17
- package/package.json +1 -1
package/cli/release.js
CHANGED
|
@@ -508,6 +508,46 @@ function buildCommitMessage(newVersion, title, changes) {
|
|
|
508
508
|
return message;
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
/**
|
|
512
|
+
* Verify that a git tag exists locally
|
|
513
|
+
*/
|
|
514
|
+
function verifyTagExists(version) {
|
|
515
|
+
try {
|
|
516
|
+
const tags = execSync('git tag -l', { cwd: root, encoding: 'utf-8' });
|
|
517
|
+
return tags.split('\n').includes(`v${version}`);
|
|
518
|
+
} catch {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Verify that a git tag exists on remote
|
|
525
|
+
*/
|
|
526
|
+
function verifyTagOnRemote(version) {
|
|
527
|
+
try {
|
|
528
|
+
const remoteTags = execSync('git ls-remote --tags origin', { cwd: root, encoding: 'utf-8' });
|
|
529
|
+
return remoteTags.includes(`refs/tags/v${version}`);
|
|
530
|
+
} catch {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Execute a git command with error handling
|
|
537
|
+
*/
|
|
538
|
+
function execGitCommand(command, description) {
|
|
539
|
+
log.info(` Running: ${description}...`);
|
|
540
|
+
try {
|
|
541
|
+
execSync(command, { cwd: root, stdio: 'inherit' });
|
|
542
|
+
return { success: true };
|
|
543
|
+
} catch (error) {
|
|
544
|
+
log.error(` Failed: ${description}`);
|
|
545
|
+
log.error(` Command: ${command}`);
|
|
546
|
+
log.error(` Error: ${error.message}`);
|
|
547
|
+
return { success: false, error };
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
511
551
|
/**
|
|
512
552
|
* Execute git commands
|
|
513
553
|
*/
|
|
@@ -521,33 +561,142 @@ function gitCommitTagPush(newVersion, title, changes, dryRun = false) {
|
|
|
521
561
|
log.info(` [dry-run] git tag -a v${newVersion} -m "Release v${newVersion}"`);
|
|
522
562
|
log.info(' [dry-run] git push');
|
|
523
563
|
log.info(' [dry-run] git push --tags');
|
|
524
|
-
return;
|
|
564
|
+
return { success: true };
|
|
525
565
|
}
|
|
526
566
|
|
|
527
567
|
// git add
|
|
528
|
-
|
|
529
|
-
|
|
568
|
+
let result = execGitCommand('git add -A', 'git add -A');
|
|
569
|
+
if (!result.success) {
|
|
570
|
+
return { success: false, stage: 'add', error: result.error };
|
|
571
|
+
}
|
|
530
572
|
|
|
531
573
|
// git commit using temp file for cross-platform compatibility
|
|
532
|
-
log.info(' Running: git commit...');
|
|
533
574
|
const tempFile = join(tmpdir(), `pulse-release-${Date.now()}.txt`);
|
|
534
575
|
writeFileSync(tempFile, commitMessage, 'utf-8');
|
|
535
576
|
try {
|
|
536
|
-
|
|
577
|
+
result = execGitCommand(`git commit -F "${tempFile}"`, 'git commit');
|
|
578
|
+
if (!result.success) {
|
|
579
|
+
return { success: false, stage: 'commit', error: result.error };
|
|
580
|
+
}
|
|
537
581
|
} finally {
|
|
538
|
-
|
|
582
|
+
try {
|
|
583
|
+
unlinkSync(tempFile);
|
|
584
|
+
} catch {
|
|
585
|
+
// Ignore cleanup errors
|
|
586
|
+
}
|
|
539
587
|
}
|
|
540
588
|
|
|
541
589
|
// git tag
|
|
542
|
-
|
|
543
|
-
|
|
590
|
+
result = execGitCommand(
|
|
591
|
+
`git tag -a v${newVersion} -m "Release v${newVersion}"`,
|
|
592
|
+
`git tag v${newVersion}`
|
|
593
|
+
);
|
|
594
|
+
if (!result.success) {
|
|
595
|
+
log.error('');
|
|
596
|
+
log.error('Tag creation failed. The commit was created but not tagged.');
|
|
597
|
+
log.error('You can manually create the tag with:');
|
|
598
|
+
log.error(` git tag -a v${newVersion} -m "Release v${newVersion}"`);
|
|
599
|
+
return { success: false, stage: 'tag', error: result.error };
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Verify tag was created
|
|
603
|
+
if (!verifyTagExists(newVersion)) {
|
|
604
|
+
log.error('');
|
|
605
|
+
log.error('Tag creation appeared to succeed but tag not found locally.');
|
|
606
|
+
log.error('You can manually create the tag with:');
|
|
607
|
+
log.error(` git tag -a v${newVersion} -m "Release v${newVersion}"`);
|
|
608
|
+
return { success: false, stage: 'tag-verify', error: new Error('Tag not found after creation') };
|
|
609
|
+
}
|
|
610
|
+
log.info(` Verified: tag v${newVersion} exists locally`);
|
|
544
611
|
|
|
545
612
|
// git push
|
|
546
|
-
|
|
547
|
-
|
|
613
|
+
result = execGitCommand('git push', 'git push');
|
|
614
|
+
if (!result.success) {
|
|
615
|
+
log.error('');
|
|
616
|
+
log.error('Push failed. Commit and tag were created locally.');
|
|
617
|
+
log.error('You can manually push with:');
|
|
618
|
+
log.error(' git push && git push --tags');
|
|
619
|
+
return { success: false, stage: 'push', error: result.error };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// git push --tags
|
|
623
|
+
result = execGitCommand('git push --tags', 'git push --tags');
|
|
624
|
+
if (!result.success) {
|
|
625
|
+
log.error('');
|
|
626
|
+
log.error('Tag push failed. The tag exists locally but not on remote.');
|
|
627
|
+
log.error('You can manually push tags with:');
|
|
628
|
+
log.error(' git push --tags');
|
|
629
|
+
return { success: false, stage: 'push-tags', error: result.error };
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Verify tag was pushed to remote
|
|
633
|
+
if (!verifyTagOnRemote(newVersion)) {
|
|
634
|
+
log.warn('');
|
|
635
|
+
log.warn('Tag push appeared to succeed but tag not found on remote.');
|
|
636
|
+
log.warn('You may need to manually verify or push with:');
|
|
637
|
+
log.warn(' git push --tags');
|
|
638
|
+
} else {
|
|
639
|
+
log.info(` Verified: tag v${newVersion} exists on remote`);
|
|
640
|
+
}
|
|
548
641
|
|
|
549
|
-
|
|
550
|
-
|
|
642
|
+
return { success: true };
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Execute git commands without pushing (--no-push mode)
|
|
647
|
+
*/
|
|
648
|
+
function gitCommitTagNoPush(newVersion, title, changes) {
|
|
649
|
+
const commitMessage = buildCommitMessage(newVersion, title, changes);
|
|
650
|
+
|
|
651
|
+
// git add
|
|
652
|
+
let result = execGitCommand('git add -A', 'git add -A');
|
|
653
|
+
if (!result.success) {
|
|
654
|
+
return { success: false, stage: 'add', error: result.error };
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// git commit using temp file for cross-platform compatibility
|
|
658
|
+
const tempFile = join(tmpdir(), `pulse-release-${Date.now()}.txt`);
|
|
659
|
+
writeFileSync(tempFile, commitMessage, 'utf-8');
|
|
660
|
+
try {
|
|
661
|
+
result = execGitCommand(`git commit -F "${tempFile}"`, 'git commit');
|
|
662
|
+
if (!result.success) {
|
|
663
|
+
return { success: false, stage: 'commit', error: result.error };
|
|
664
|
+
}
|
|
665
|
+
} finally {
|
|
666
|
+
try {
|
|
667
|
+
unlinkSync(tempFile);
|
|
668
|
+
} catch {
|
|
669
|
+
// Ignore cleanup errors
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// git tag
|
|
674
|
+
result = execGitCommand(
|
|
675
|
+
`git tag -a v${newVersion} -m "Release v${newVersion}"`,
|
|
676
|
+
`git tag v${newVersion}`
|
|
677
|
+
);
|
|
678
|
+
if (!result.success) {
|
|
679
|
+
log.error('');
|
|
680
|
+
log.error('Tag creation failed. The commit was created but not tagged.');
|
|
681
|
+
log.error('You can manually create the tag with:');
|
|
682
|
+
log.error(` git tag -a v${newVersion} -m "Release v${newVersion}"`);
|
|
683
|
+
return { success: false, stage: 'tag', error: result.error };
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Verify tag was created
|
|
687
|
+
if (!verifyTagExists(newVersion)) {
|
|
688
|
+
log.error('');
|
|
689
|
+
log.error('Tag creation appeared to succeed but tag not found locally.');
|
|
690
|
+
log.error('You can manually create the tag with:');
|
|
691
|
+
log.error(` git tag -a v${newVersion} -m "Release v${newVersion}"`);
|
|
692
|
+
return { success: false, stage: 'tag-verify', error: new Error('Tag not found after creation') };
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
log.info(` Verified: tag v${newVersion} exists locally`);
|
|
696
|
+
log.info(' Created commit and tag (--no-push specified)');
|
|
697
|
+
log.info(' To push later, run: git push && git push --tags');
|
|
698
|
+
|
|
699
|
+
return { success: true };
|
|
551
700
|
}
|
|
552
701
|
|
|
553
702
|
/**
|
|
@@ -811,25 +960,24 @@ export async function runRelease(args) {
|
|
|
811
960
|
log.info('');
|
|
812
961
|
log.info('Git operations...');
|
|
813
962
|
|
|
963
|
+
let gitResult = { success: true };
|
|
964
|
+
|
|
814
965
|
if (!dryRun) {
|
|
815
966
|
if (noPush) {
|
|
816
967
|
// Only commit and tag, no push
|
|
817
|
-
|
|
818
|
-
execSync('git add -A', { cwd: root, stdio: 'inherit' });
|
|
819
|
-
const tempFile = join(tmpdir(), `pulse-release-${Date.now()}.txt`);
|
|
820
|
-
writeFileSync(tempFile, commitMessage, 'utf-8');
|
|
821
|
-
try {
|
|
822
|
-
execSync(`git commit -F "${tempFile}"`, { cwd: root, stdio: 'inherit' });
|
|
823
|
-
} finally {
|
|
824
|
-
unlinkSync(tempFile);
|
|
825
|
-
}
|
|
826
|
-
execSync(`git tag -a v${newVersion} -m "Release v${newVersion}"`, { cwd: root, stdio: 'inherit' });
|
|
827
|
-
log.info(' Created commit and tag (--no-push specified)');
|
|
968
|
+
gitResult = gitCommitTagNoPush(newVersion, title, changes);
|
|
828
969
|
} else {
|
|
829
|
-
gitCommitTagPush(newVersion, title, changes, false);
|
|
970
|
+
gitResult = gitCommitTagPush(newVersion, title, changes, false);
|
|
830
971
|
}
|
|
831
972
|
} else {
|
|
832
|
-
gitCommitTagPush(newVersion, title, changes, true);
|
|
973
|
+
gitResult = gitCommitTagPush(newVersion, title, changes, true);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (!gitResult.success) {
|
|
977
|
+
log.error('');
|
|
978
|
+
log.error(`Release failed at stage: ${gitResult.stage}`);
|
|
979
|
+
log.error('Please fix the issue and retry, or complete the release manually.');
|
|
980
|
+
process.exit(1);
|
|
833
981
|
}
|
|
834
982
|
|
|
835
983
|
log.info('');
|
package/loader/vite-plugin.js
CHANGED
|
@@ -2,32 +2,42 @@
|
|
|
2
2
|
* Pulse Vite Plugin
|
|
3
3
|
*
|
|
4
4
|
* Enables .pulse file support in Vite projects
|
|
5
|
+
* Extracts CSS to virtual .css modules so Vite's CSS pipeline handles them
|
|
6
|
+
* (prevents JS minifier from corrupting CSS in template literals)
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
import { compile } from '../compiler/index.js';
|
|
8
10
|
import { existsSync } from 'fs';
|
|
9
11
|
import { resolve, dirname } from 'path';
|
|
10
12
|
|
|
13
|
+
// Virtual module ID for extracted CSS (uses .css extension so Vite treats it as CSS)
|
|
14
|
+
const VIRTUAL_CSS_SUFFIX = '.pulse.css';
|
|
15
|
+
|
|
11
16
|
/**
|
|
12
17
|
* Create Pulse Vite plugin
|
|
13
18
|
*/
|
|
14
19
|
export default function pulsePlugin(options = {}) {
|
|
15
20
|
const {
|
|
16
|
-
include = /\.pulse$/,
|
|
17
21
|
exclude = /node_modules/,
|
|
18
22
|
sourceMap = true
|
|
19
23
|
} = options;
|
|
20
24
|
|
|
25
|
+
// Store extracted CSS for each .pulse module
|
|
26
|
+
const cssMap = new Map();
|
|
27
|
+
|
|
21
28
|
return {
|
|
22
29
|
name: 'vite-plugin-pulse',
|
|
23
30
|
enforce: 'pre',
|
|
24
31
|
|
|
25
32
|
/**
|
|
26
|
-
* Resolve .pulse files and
|
|
27
|
-
* The compiler transforms .pulse imports to .js, so we need to
|
|
28
|
-
* resolve them back to .pulse for Vite to process them
|
|
33
|
+
* Resolve .pulse files and virtual CSS modules
|
|
29
34
|
*/
|
|
30
35
|
resolveId(id, importer) {
|
|
36
|
+
// Handle virtual CSS module resolution
|
|
37
|
+
if (id.endsWith(VIRTUAL_CSS_SUFFIX)) {
|
|
38
|
+
return '\0' + id;
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
// Direct .pulse imports - resolve to absolute path
|
|
32
42
|
if (id.endsWith('.pulse') && importer) {
|
|
33
43
|
const importerDir = dirname(importer);
|
|
@@ -38,7 +48,6 @@ export default function pulsePlugin(options = {}) {
|
|
|
38
48
|
}
|
|
39
49
|
|
|
40
50
|
// Check if a .js import has a corresponding .pulse file
|
|
41
|
-
// This handles the compiler's transformation of .pulse -> .js imports
|
|
42
51
|
if (id.endsWith('.js') && importer) {
|
|
43
52
|
const pulseId = id.replace(/\.js$/, '.pulse');
|
|
44
53
|
const importerDir = dirname(importer);
|
|
@@ -52,8 +61,22 @@ export default function pulsePlugin(options = {}) {
|
|
|
52
61
|
return null;
|
|
53
62
|
},
|
|
54
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Load virtual CSS modules
|
|
66
|
+
*/
|
|
67
|
+
load(id) {
|
|
68
|
+
// Virtual modules start with \0
|
|
69
|
+
if (id.startsWith('\0') && id.endsWith(VIRTUAL_CSS_SUFFIX)) {
|
|
70
|
+
const pulseId = id.slice(1, -VIRTUAL_CSS_SUFFIX.length + '.pulse'.length);
|
|
71
|
+
const css = cssMap.get(pulseId);
|
|
72
|
+
return css || '';
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
},
|
|
76
|
+
|
|
55
77
|
/**
|
|
56
78
|
* Transform .pulse files to JavaScript
|
|
79
|
+
* CSS is extracted to a virtual .css module that Vite processes separately
|
|
57
80
|
*/
|
|
58
81
|
transform(code, id) {
|
|
59
82
|
if (!id.endsWith('.pulse')) {
|
|
@@ -79,8 +102,27 @@ export default function pulsePlugin(options = {}) {
|
|
|
79
102
|
return null;
|
|
80
103
|
}
|
|
81
104
|
|
|
105
|
+
let outputCode = result.code;
|
|
106
|
+
|
|
107
|
+
// Extract CSS from compiled output and move to virtual CSS module
|
|
108
|
+
const stylesMatch = outputCode.match(/const styles = `([\s\S]*?)`;/);
|
|
109
|
+
if (stylesMatch) {
|
|
110
|
+
const css = stylesMatch[1];
|
|
111
|
+
const virtualCssId = id + '.css';
|
|
112
|
+
|
|
113
|
+
// Store CSS for the virtual module loader
|
|
114
|
+
cssMap.set(id, css);
|
|
115
|
+
|
|
116
|
+
// Replace inline style injection with CSS import
|
|
117
|
+
// Vite will process this through its CSS pipeline (not JS minifier)
|
|
118
|
+
outputCode = outputCode.replace(
|
|
119
|
+
/\/\/ Styles\nconst styles = `[\s\S]*?`;\n\/\/ Inject styles\nconst styleEl = document\.createElement\("style"\);\nstyleEl\.textContent = styles;\ndocument\.head\.appendChild\(styleEl\);/,
|
|
120
|
+
`// Styles extracted to virtual CSS module\nimport "${virtualCssId}";`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
82
124
|
return {
|
|
83
|
-
code:
|
|
125
|
+
code: outputCode,
|
|
84
126
|
map: result.map || null
|
|
85
127
|
};
|
|
86
128
|
} catch (error) {
|
|
@@ -92,7 +134,7 @@ export default function pulsePlugin(options = {}) {
|
|
|
92
134
|
/**
|
|
93
135
|
* Handle hot module replacement
|
|
94
136
|
*/
|
|
95
|
-
handleHotUpdate({ file, server
|
|
137
|
+
handleHotUpdate({ file, server }) {
|
|
96
138
|
if (file.endsWith('.pulse')) {
|
|
97
139
|
console.log(`[Pulse] HMR update: ${file}`);
|
|
98
140
|
|
|
@@ -102,8 +144,14 @@ export default function pulsePlugin(options = {}) {
|
|
|
102
144
|
server.moduleGraph.invalidateModule(module);
|
|
103
145
|
}
|
|
104
146
|
|
|
147
|
+
// Also invalidate the associated virtual CSS module
|
|
148
|
+
const virtualCssId = '\0' + file + '.css';
|
|
149
|
+
const cssModule = server.moduleGraph.getModuleById(virtualCssId);
|
|
150
|
+
if (cssModule) {
|
|
151
|
+
server.moduleGraph.invalidateModule(cssModule);
|
|
152
|
+
}
|
|
153
|
+
|
|
105
154
|
// Send HMR update instead of full reload
|
|
106
|
-
// The module will handle its own state preservation via hmrRuntime
|
|
107
155
|
server.ws.send({
|
|
108
156
|
type: 'update',
|
|
109
157
|
updates: [{
|
|
@@ -123,7 +171,7 @@ export default function pulsePlugin(options = {}) {
|
|
|
123
171
|
* Configure dev server
|
|
124
172
|
*/
|
|
125
173
|
configureServer(server) {
|
|
126
|
-
server.middlewares.use((
|
|
174
|
+
server.middlewares.use((_req, _res, next) => {
|
|
127
175
|
// Add any custom middleware here
|
|
128
176
|
next();
|
|
129
177
|
});
|
|
@@ -133,11 +181,8 @@ export default function pulsePlugin(options = {}) {
|
|
|
133
181
|
* Build hooks
|
|
134
182
|
*/
|
|
135
183
|
buildStart() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
buildEnd() {
|
|
140
|
-
console.log('[Pulse] Build completed');
|
|
184
|
+
// Clear CSS map on new build
|
|
185
|
+
cssMap.clear();
|
|
141
186
|
}
|
|
142
187
|
};
|
|
143
188
|
}
|
|
@@ -191,9 +236,9 @@ export const utils = {
|
|
|
191
236
|
},
|
|
192
237
|
|
|
193
238
|
/**
|
|
194
|
-
*
|
|
239
|
+
* Get the virtual CSS module ID for a Pulse file
|
|
195
240
|
*/
|
|
196
|
-
|
|
197
|
-
return
|
|
241
|
+
getVirtualCssId(id) {
|
|
242
|
+
return id + '.css';
|
|
198
243
|
}
|
|
199
244
|
};
|