vuetty 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,3 +1,15 @@
1
+ <p align="center">
2
+ <a href="https://tterrasson.github.io/vuetty/" target="_blank" rel="noopener noreferrer">
3
+ <img src="docs/public/images/logo.webp" alt="Vuetty Logo" width="300" />
4
+ </a>
5
+ </p>
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/vuetty">
8
+ <img src="https://img.shields.io/npm/v/vuetty?logo=npm&style=plastic" alt="npm package">
9
+ </a>
10
+ </p>
11
+ <br/>
12
+
1
13
  # Vuetty
2
14
 
3
15
  A Vue.js custom renderer for building Terminal User Interfaces (TUIs). Vuetty brings Vue's reactive system and component model to the terminal, allowing you to build interactive command-line applications using familiar Vue.js syntax.
@@ -5,14 +5,13 @@
5
5
  */
6
6
  import { plugin } from 'bun';
7
7
  import { compileSFC } from './compiler-core.js';
8
- import { readFileSync } from 'node:fs';
9
8
 
10
9
  plugin({
11
10
  name: 'vuetty-bun-loader',
12
11
 
13
12
  setup(build) {
14
13
  build.onLoad({ filter: /\.vue$/ }, async ({ path }) => {
15
- const source = readFileSync(path, 'utf-8');
14
+ const source = await Bun.file(path).text();
16
15
  const { code, errors } = compileSFC(source, path);
17
16
 
18
17
  if (errors.length > 0) {
@@ -0,0 +1,117 @@
1
+ // src/build/compiler-core.js
2
+ /**
3
+ * Runtime-agnostic Vue SFC compilation core
4
+ * Extracted from vue-sfc-plugin.js to be shared across all runtime adapters
5
+ */
6
+ import { parse, compileScript } from '@vue/compiler-sfc';
7
+
8
+ /**
9
+ * Compile a Vue Single File Component to JavaScript
10
+ * @param {string} source - The .vue file source code
11
+ * @param {string} filepath - The file path (used for error reporting and ID)
12
+ * @param {object} options - Compilation options
13
+ * @returns {{ code: string, errors: Array, map?: object }} Compilation result
14
+ */
15
+ export function compileSFC(source, filepath, options = {}) {
16
+ try {
17
+ // Step 1: Parse SFC into descriptor (template, script, style blocks)
18
+ const { descriptor, errors: parseErrors } = parse(source, {
19
+ filename: filepath,
20
+ });
21
+
22
+ if (parseErrors.length) {
23
+ return {
24
+ code: '',
25
+ errors: parseErrors.map(e => ({
26
+ message: `SFC Parse Error: ${e.message}`,
27
+ location: e.loc ? {
28
+ file: filepath,
29
+ line: e.loc.start.line,
30
+ column: e.loc.start.column,
31
+ } : undefined,
32
+ })),
33
+ };
34
+ }
35
+
36
+ // Step 2: Compile script block with inline template
37
+ // For <script setup>, using inlineTemplate: true automatically handles:
38
+ // - Template compilation
39
+ // - Component resolution (imported components are available)
40
+ // - Reactive state exposure to template
41
+ let scriptCode = '';
42
+
43
+ if (descriptor.script || descriptor.scriptSetup) {
44
+ try {
45
+ const compiled = compileScript(descriptor, {
46
+ id: filepath,
47
+ // IMPORTANT: Inline template compilation with script
48
+ // This ensures imported components and setup vars are accessible
49
+ inlineTemplate: true,
50
+ templateOptions: {
51
+ compilerOptions: {
52
+ // Removed isCustomElement - let Vue always resolve as components
53
+ // This ensures component setup() always runs and inputManager injection works
54
+ whitespace: 'preserve',
55
+ comments: false,
56
+ hoistStatic: true,
57
+ ...options.compilerOptions,
58
+ },
59
+ },
60
+ });
61
+
62
+ scriptCode = compiled.content;
63
+
64
+ // Return compiled code
65
+ return {
66
+ code: scriptCode,
67
+ errors: [],
68
+ map: compiled.map,
69
+ };
70
+
71
+ } catch (error) {
72
+ return {
73
+ code: '',
74
+ errors: [{
75
+ message: `Script/Template Compilation Error: ${error.message}`,
76
+ location: error.loc ? {
77
+ file: filepath,
78
+ line: error.loc.start.line,
79
+ column: error.loc.start.column,
80
+ } : undefined,
81
+ }],
82
+ };
83
+ }
84
+ }
85
+
86
+ // If no script block, return empty
87
+ return {
88
+ code: '',
89
+ errors: [{
90
+ message: 'SFC has no script or scriptSetup block',
91
+ location: { file: filepath },
92
+ }],
93
+ };
94
+
95
+ } catch (error) {
96
+ return {
97
+ code: '',
98
+ errors: [{
99
+ message: `Unexpected SFC Compilation Error: ${error.message}`,
100
+ location: { file: filepath },
101
+ }],
102
+ };
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Format compilation errors for display
108
+ * @param {Array} errors - Array of error objects
109
+ * @param {string} filepath - The file path
110
+ * @returns {Array} Formatted errors
111
+ */
112
+ export function formatErrors(errors, filepath) {
113
+ return errors.map(e => ({
114
+ text: e.message || 'Unknown error',
115
+ location: e.location || { file: filepath },
116
+ }));
117
+ }