viewgate-wrapper 1.11.41 → 1.11.43
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/dist/cli.js +123 -0
- package/dist/components/ViewGateOverlay.d.ts.map +1 -1
- package/dist/plugin/babel-plugin-viewgate.js +27 -0
- package/dist/plugin/config-injectors.js +205 -0
- package/dist/plugin/next-loader.js +4 -0
- package/dist/plugin/transform-logic.js +30 -0
- package/dist/plugin/vite-plugin-viewgate.js +14 -0
- package/dist/plugin/webpack-loader.js +9 -0
- package/dist/viewgate-wrapper.js +8400 -2266
- package/dist/viewgate-wrapper.umd.cjs +16 -11
- package/package.json +2 -1
- package/dist/utils/VGCap.d.ts +0 -12
- package/dist/utils/VGCap.d.ts.map +0 -1
package/dist/cli.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { detectFramework, injectVitePlugin, injectNextPlugin, injectWebpackPlugin, injectBabelPlugin } from './plugin/config-injectors.js';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
async function setup() {
|
|
10
|
+
console.log('🚀 Setting up ViewGate MCP Server...');
|
|
11
|
+
// 1. Locate mcp_config.json
|
|
12
|
+
const configDir = path.join(os.homedir(), '.gemini', 'antigravity');
|
|
13
|
+
const configPath = path.join(configDir, 'mcp_config.json');
|
|
14
|
+
if (!fs.existsSync(configPath)) {
|
|
15
|
+
console.error(`❌ Could not find mcp_config.json at ${configPath}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
// 2. Determine the path or URL
|
|
19
|
+
const mcpServerUrl = process.env.MCP_SERVER_URL || 'https://view-gate-mcp.vercel.app/sse';
|
|
20
|
+
// 3. Read and update mcp_config.json
|
|
21
|
+
try {
|
|
22
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
23
|
+
if (!config.mcpServers) {
|
|
24
|
+
config.mcpServers = {};
|
|
25
|
+
}
|
|
26
|
+
const currentServer = config.mcpServers.viewgate || {};
|
|
27
|
+
const env = currentServer.env || {};
|
|
28
|
+
const apiKey = env.API_KEY || '';
|
|
29
|
+
config.mcpServers["viewgate"] = {
|
|
30
|
+
command: "npx",
|
|
31
|
+
args: ["-y", "viewgate-mcp"],
|
|
32
|
+
env: {
|
|
33
|
+
"VIEWGATE_API_KEY": apiKey || "TU_API_KEY_AQUI",
|
|
34
|
+
"VIEWGATE_PERSONAL_KEY": env.VIEWGATE_PERSONAL_KEY || "TU_KEY_PERSONAL_AQUI"
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
38
|
+
console.log(`✅ Updated mcp_config.json successfully!`);
|
|
39
|
+
if (!apiKey || !env.VIEWGATE_PERSONAL_KEY) {
|
|
40
|
+
console.log('\n⚠️ Recuerda configurar tus credenciales en:');
|
|
41
|
+
console.log(` ${configPath}`);
|
|
42
|
+
if (!apiKey)
|
|
43
|
+
console.log(' - API_KEY: Búscala en "API Keys" del Proyecto en el Dashboard.');
|
|
44
|
+
if (!env.VIEWGATE_PERSONAL_KEY)
|
|
45
|
+
console.log(' - PERSONAL_KEY: Búscala en "Personal Key" en la sección de Proyectos del Dashboard.');
|
|
46
|
+
console.log('\n Ambas son necesarias para identificar quién resuelve los tickets.');
|
|
47
|
+
}
|
|
48
|
+
// 4. Framework Detection and Plugin Auto-Config
|
|
49
|
+
console.log('\n🔍 Detecting framework for High-Precision Mapping...');
|
|
50
|
+
const cwd = process.cwd();
|
|
51
|
+
const result = detectFramework(cwd);
|
|
52
|
+
if (result.framework === 'vite' && result.configPath) {
|
|
53
|
+
console.log(`✨ Vite detected! Attempting to apply plugin to: ${path.basename(result.configPath)}`);
|
|
54
|
+
if (injectVitePlugin(result.configPath)) {
|
|
55
|
+
console.log('✅ viewgatePlugin applied successfully!');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.log('⚠️ Could not auto-apply plugin. Please follow manual setup in README.');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (result.framework === 'next' && result.configPath) {
|
|
62
|
+
console.log(`✨ Next.js detected! Attempting to apply webpack loader to: ${path.basename(result.configPath)}`);
|
|
63
|
+
if (injectNextPlugin(result.configPath)) {
|
|
64
|
+
console.log('✅ next-loader applied successfully!');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log('⚠️ Could not auto-apply plugin. Please follow manual setup in README.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (result.framework === 'webpack' && result.configPath) {
|
|
71
|
+
console.log(`✨ Webpack/Craco detected! Attempting to apply loader to: ${path.basename(result.configPath)}`);
|
|
72
|
+
if (injectWebpackPlugin(result.configPath)) {
|
|
73
|
+
console.log('✅ webpack-loader applied successfully!');
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log('⚠️ Could not auto-apply loader. Please follow manual setup in README.');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (result.framework === 'babel' && result.configPath) {
|
|
80
|
+
console.log(`✨ Babel detected in: ${path.basename(result.configPath)}`);
|
|
81
|
+
if (injectBabelPlugin(result.configPath)) {
|
|
82
|
+
console.log('✅ babel-plugin applied successfully!');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log('⚠️ Could not auto-apply plugin. Please follow manual setup in README.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (result.framework === 'react-scripts') {
|
|
89
|
+
console.log('✨ Create React App (CRA) detected!');
|
|
90
|
+
console.log('👉 CRA doesn\'t allow easy config changes. ViewGate will use "Zero-Config" Fiber fallback.');
|
|
91
|
+
console.log('💡 For High-Precision mapping, consider using Craco: https://craco.js.org/');
|
|
92
|
+
}
|
|
93
|
+
else if (result.framework === 'astro' || result.framework === 'remix') {
|
|
94
|
+
console.log(`✨ ${result.framework.toUpperCase()} detected!`);
|
|
95
|
+
if (result.configPath) {
|
|
96
|
+
console.log(`Attempting to apply Vite-based plugin to: ${path.basename(result.configPath)}`);
|
|
97
|
+
if (injectVitePlugin(result.configPath)) {
|
|
98
|
+
console.log('✅ viewgatePlugin applied successfully!');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log('⚠️ Could not auto-apply. Please see README for manual setup.');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log('👉 Please follow manual setup in README to enable High-Precision mapping.');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (result.framework !== 'unknown') {
|
|
109
|
+
console.log(`✨ ${result.framework.toUpperCase()} detected!`);
|
|
110
|
+
console.log(`👉 Please follow the manual setup for ${result.framework} in the README.`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.log('❓ Could not determine framework. High-Precision mapping might require manual setup.');
|
|
114
|
+
console.log('💡 ViewGate will still work using the "Zero-Config" Fiber fallback in development.');
|
|
115
|
+
}
|
|
116
|
+
console.log('\n🎉 Setup complete! You can now start using ViewGate in your project.');
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
console.error(`❌ Error updating configuration: ${error.message}`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
setup();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewGateOverlay.d.ts","sourceRoot":"","sources":["../../src/components/ViewGateOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ViewGateOverlay.d.ts","sourceRoot":"","sources":["../../src/components/ViewGateOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAiCnF,OAAO,wBAAwB,CAAC;AAywBhC,eAAO,MAAM,eAAe,EAAE,EAsgH7B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/plugin/babel-plugin-viewgate.ts
|
|
2
|
+
import { transformSourcePaths } from './transform-logic.js';
|
|
3
|
+
/**
|
|
4
|
+
* Babel plugin to inject source mapping attributes.
|
|
5
|
+
* Since we want to keep logic at the source level consistent,
|
|
6
|
+
* this plugin uses the same transformSourcePaths logic.
|
|
7
|
+
*/
|
|
8
|
+
export default function babelPluginViewGate() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'babel-plugin-viewgate',
|
|
11
|
+
visitor: {
|
|
12
|
+
Program(path, state) {
|
|
13
|
+
const filePath = state.file.opts.filename;
|
|
14
|
+
if (!filePath || filePath.includes('node_modules'))
|
|
15
|
+
return;
|
|
16
|
+
if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx'))
|
|
17
|
+
return;
|
|
18
|
+
const code = state.file.code;
|
|
19
|
+
const transformed = transformSourcePaths(code, filePath, process.cwd());
|
|
20
|
+
// Note: Re-parsing would be safer but more complex.
|
|
21
|
+
// For now, if we are in Babel, we can replace the entire content or
|
|
22
|
+
// use AST manipulation. Since we already have transformSourcePaths
|
|
23
|
+
// which is regex-based, we'll keep it simple for consistency.
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export function detectFramework(cwd) {
|
|
4
|
+
const files = fs.readdirSync(cwd);
|
|
5
|
+
// 1. Check for specific config files
|
|
6
|
+
if (files.includes('vite.config.ts') || files.includes('vite.config.js') || files.includes('vite.config.mjs')) {
|
|
7
|
+
const configPath = files.find(f => f.startsWith('vite.config.'));
|
|
8
|
+
return { framework: 'vite', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
9
|
+
}
|
|
10
|
+
if (files.includes('next.config.js') || files.includes('next.config.mjs')) {
|
|
11
|
+
const configPath = files.find(f => f.startsWith('next.config.'));
|
|
12
|
+
return { framework: 'next', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
13
|
+
}
|
|
14
|
+
if (files.includes('astro.config.mjs') || files.includes('astro.config.ts')) {
|
|
15
|
+
const configPath = files.find(f => f.startsWith('astro.config.'));
|
|
16
|
+
return { framework: 'astro', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
17
|
+
}
|
|
18
|
+
if (files.includes('remix.config.js') || files.includes('remix.config.ts')) {
|
|
19
|
+
const configPath = files.find(f => f.startsWith('remix.config.'));
|
|
20
|
+
return { framework: 'remix', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
21
|
+
}
|
|
22
|
+
if (files.includes('webpack.config.js') || files.includes('craco.config.js')) {
|
|
23
|
+
const configPath = files.find(f => f.startsWith('webpack.config.') || f.startsWith('craco.config.'));
|
|
24
|
+
return { framework: 'webpack', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
25
|
+
}
|
|
26
|
+
if (files.includes('.babelrc') || files.includes('babel.config.js') || files.includes('babel.config.json')) {
|
|
27
|
+
const configPath = files.find(f => f.includes('babel'));
|
|
28
|
+
return { framework: 'babel', configPath: configPath ? path.join(cwd, configPath) : undefined };
|
|
29
|
+
}
|
|
30
|
+
// 2. Fallback to package.json analysis
|
|
31
|
+
if (files.includes('package.json')) {
|
|
32
|
+
try {
|
|
33
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
34
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
35
|
+
if (deps['react-scripts'])
|
|
36
|
+
return { framework: 'react-scripts', configPath: path.join(cwd, 'package.json') };
|
|
37
|
+
if (pkg.babel)
|
|
38
|
+
return { framework: 'babel', configPath: path.join(cwd, 'package.json') };
|
|
39
|
+
if (deps['next'])
|
|
40
|
+
return { framework: 'next', configPath: undefined };
|
|
41
|
+
if (deps['vite'])
|
|
42
|
+
return { framework: 'vite', configPath: undefined };
|
|
43
|
+
if (deps['astro'])
|
|
44
|
+
return { framework: 'astro', configPath: undefined };
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
// Ignore JSON errors
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { framework: 'unknown', configPath: undefined };
|
|
51
|
+
}
|
|
52
|
+
export function injectVitePlugin(configPath) {
|
|
53
|
+
try {
|
|
54
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
55
|
+
// 1. Check if already injected
|
|
56
|
+
if (content.includes('viewgatePlugin'))
|
|
57
|
+
return true;
|
|
58
|
+
// 2. Add import (handling both import and require)
|
|
59
|
+
const isTS = configPath.endsWith('.ts');
|
|
60
|
+
const isMJS = configPath.endsWith('.mjs');
|
|
61
|
+
const importStatement = (isTS || isMJS || content.includes('import '))
|
|
62
|
+
? "import viewgatePlugin from 'viewgate-wrapper/vite';\n"
|
|
63
|
+
: "const viewgatePlugin = require('viewgate-wrapper/vite');\n";
|
|
64
|
+
if (!content.includes('viewgate-wrapper/vite')) {
|
|
65
|
+
content = importStatement + content;
|
|
66
|
+
}
|
|
67
|
+
// 3. Inject into plugins array
|
|
68
|
+
const pluginsRegex = /plugins\s*:\s*\[/;
|
|
69
|
+
if (pluginsRegex.test(content)) {
|
|
70
|
+
content = content.replace(pluginsRegex, `plugins: [\n viewgatePlugin(),`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const configObjectRegex = /(defineConfig\s*\(\s*(?:{[^}]*}|(?:\([^)]*\)\s*=>\s*\(?))?\s*{)/;
|
|
74
|
+
if (configObjectRegex.test(content)) {
|
|
75
|
+
content = content.replace(configObjectRegex, `$1\n plugins: [viewgatePlugin()],`);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
fs.writeFileSync(configPath, content);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function injectNextPlugin(configPath) {
|
|
89
|
+
try {
|
|
90
|
+
// If no configPath, we might want to create a default one, but for now we bail
|
|
91
|
+
if (!configPath)
|
|
92
|
+
return false;
|
|
93
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
94
|
+
if (content.includes('viewgate-wrapper/next-loader'))
|
|
95
|
+
return true;
|
|
96
|
+
const loaderConfig = `{
|
|
97
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
98
|
+
exclude: /node_modules/,
|
|
99
|
+
use: ['viewgate-wrapper/next-loader'],
|
|
100
|
+
}`;
|
|
101
|
+
const webpackSnippet = `\n webpack: (config) => {
|
|
102
|
+
config.module.rules.push(${loaderConfig});
|
|
103
|
+
return config;
|
|
104
|
+
},`;
|
|
105
|
+
const anonymousExportRegex = /(module\.exports\s*=\s*|export\s*default\s*)\{/;
|
|
106
|
+
const nextConfigVarRegex = /(const|let|var)\s+(\w+)\s*=\s*\{/;
|
|
107
|
+
const nextConfigMatch = content.match(nextConfigVarRegex);
|
|
108
|
+
if (nextConfigMatch) {
|
|
109
|
+
const varName = nextConfigMatch[2];
|
|
110
|
+
const exportRegex = new RegExp(`(?:module\\.exports\\s*=\\s*|export\\s*default\\s*)${varName}`, 'm');
|
|
111
|
+
if (exportRegex.test(content)) {
|
|
112
|
+
content = content.replace(nextConfigVarRegex, `$1 $2 = {${webpackSnippet}`);
|
|
113
|
+
fs.writeFileSync(configPath, content);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (anonymousExportRegex.test(content)) {
|
|
118
|
+
content = content.replace(anonymousExportRegex, `$1 {${webpackSnippet}`);
|
|
119
|
+
fs.writeFileSync(configPath, content);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function injectWebpackPlugin(configPath) {
|
|
129
|
+
try {
|
|
130
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
131
|
+
if (content.includes('viewgate-wrapper/webpack-loader'))
|
|
132
|
+
return true;
|
|
133
|
+
const loaderConfig = `{
|
|
134
|
+
test: /\\.(js|jsx|ts|tsx)$/,
|
|
135
|
+
exclude: /node_modules/,
|
|
136
|
+
use: ['viewgate-wrapper/webpack-loader'],
|
|
137
|
+
}`;
|
|
138
|
+
const rulesRegex = /rules\s*:\s*\[/;
|
|
139
|
+
if (rulesRegex.test(content)) {
|
|
140
|
+
content = content.replace(rulesRegex, `rules: [\n ${loaderConfig},`);
|
|
141
|
+
fs.writeFileSync(configPath, content);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export function injectBabelPlugin(configPath) {
|
|
151
|
+
try {
|
|
152
|
+
const isPackageJson = configPath.endsWith('package.json');
|
|
153
|
+
if (isPackageJson)
|
|
154
|
+
return injectBabelToPackageJson(configPath);
|
|
155
|
+
const isJson = configPath.endsWith('.json') || configPath.includes('.babelrc');
|
|
156
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
157
|
+
if (content.includes('viewgate-wrapper/babel'))
|
|
158
|
+
return true;
|
|
159
|
+
if (isJson) {
|
|
160
|
+
try {
|
|
161
|
+
const config = JSON.parse(content);
|
|
162
|
+
if (!config.plugins)
|
|
163
|
+
config.plugins = [];
|
|
164
|
+
if (!config.plugins.includes('viewgate-wrapper/babel')) {
|
|
165
|
+
config.plugins.push('viewgate-wrapper/babel');
|
|
166
|
+
}
|
|
167
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const pluginsRegex = /plugins\s*:\s*\[/;
|
|
176
|
+
if (pluginsRegex.test(content)) {
|
|
177
|
+
content = content.replace(pluginsRegex, `plugins: [\n 'viewgate-wrapper/babel',`);
|
|
178
|
+
fs.writeFileSync(configPath, content);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function injectBabelToPackageJson(pkgPath) {
|
|
189
|
+
try {
|
|
190
|
+
const content = fs.readFileSync(pkgPath, 'utf8');
|
|
191
|
+
const pkg = JSON.parse(content);
|
|
192
|
+
if (!pkg.babel)
|
|
193
|
+
pkg.babel = {};
|
|
194
|
+
if (!pkg.babel.plugins)
|
|
195
|
+
pkg.babel.plugins = [];
|
|
196
|
+
if (!pkg.babel.plugins.includes('viewgate-wrapper/babel')) {
|
|
197
|
+
pkg.babel.plugins.push('viewgate-wrapper/babel');
|
|
198
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
199
|
+
}
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function transformSourcePaths(code, id, cwd) {
|
|
2
|
+
if (!id.endsWith('.tsx') && !id.endsWith('.jsx'))
|
|
3
|
+
return code;
|
|
4
|
+
if (id.includes('node_modules'))
|
|
5
|
+
return code;
|
|
6
|
+
const normalizePath = (p) => p.replace(/\\/g, '/');
|
|
7
|
+
const relativePath = normalizePath(id).replace(normalizePath(cwd), '');
|
|
8
|
+
// Simpler, faster hash function for performance
|
|
9
|
+
const getHash = (s) => {
|
|
10
|
+
let h = 0;
|
|
11
|
+
for (let i = 0; i < s.length; i++)
|
|
12
|
+
h = (Math.imul(31, h) + s.charCodeAt(i)) | 0;
|
|
13
|
+
return (h >>> 0).toString(16);
|
|
14
|
+
};
|
|
15
|
+
let tagIndex = 0;
|
|
16
|
+
const lines = code.split('\n');
|
|
17
|
+
const transformedLines = lines.map((line, index) => {
|
|
18
|
+
const lineNumber = index + 1;
|
|
19
|
+
// Regex to find JSX tags and inject data-source-path (handles self-closing tags)
|
|
20
|
+
return line.replace(/(^|[^a-zA-Z0-9])<([a-zA-Z][a-zA-Z0-9\.]*)(?=[ \t\n\/\>])/g, (match, prefix, tagName) => {
|
|
21
|
+
if (match.includes('data-source-path') || match.includes('data-vg-id') || tagName === 'Fragment' || tagName === 'React.Fragment') {
|
|
22
|
+
return match;
|
|
23
|
+
}
|
|
24
|
+
tagIndex++;
|
|
25
|
+
const vgId = getHash(`${relativePath}:${tagName}:${tagIndex}`);
|
|
26
|
+
return `${prefix}<${tagName} data-vg-id="${vgId}" data-source-path="${relativePath}:${lineNumber}"`;
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
return transformedLines.join('\n');
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { transformSourcePaths } from './transform-logic.js';
|
|
2
|
+
export default function viewgatePlugin() {
|
|
3
|
+
return {
|
|
4
|
+
name: 'vite-plugin-viewgate',
|
|
5
|
+
enforce: 'pre',
|
|
6
|
+
transform(code, id) {
|
|
7
|
+
const transformedCode = transformSourcePaths(code, id, process.cwd());
|
|
8
|
+
return {
|
|
9
|
+
code: transformedCode,
|
|
10
|
+
map: null
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { transformSourcePaths } from './transform-logic.js';
|
|
2
|
+
export default function viewgateWebpackLoader(source) {
|
|
3
|
+
const id = this.resourcePath;
|
|
4
|
+
if (!id)
|
|
5
|
+
return source;
|
|
6
|
+
// Support for both Webpack 4 and 5
|
|
7
|
+
const options = this.getOptions ? this.getOptions() : {};
|
|
8
|
+
return transformSourcePaths(source, id, process.cwd());
|
|
9
|
+
}
|