one
Version:
One is a new React Framework that makes Vite serve both native and web.
180 lines • 7.35 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf,
__hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: !0
});
},
__copyProps = (to, from, except, desc) => {
if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: !0
}) : target, mod)),
__toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
value: !0
}), mod);
var sourceInspectorPlugin_exports = {};
__export(sourceInspectorPlugin_exports, {
sourceInspectorPlugin: () => sourceInspectorPlugin
});
module.exports = __toCommonJS(sourceInspectorPlugin_exports);
var import_node_path = __toESM(require("node:path"), 1),
import_oxc_parser = require("oxc-parser"),
import_vite = require("vite");
async function findJsxElements(code, filename) {
const result = await (0, import_oxc_parser.parse)(filename, code);
if (result.errors.length > 0) return [];
const locations = [];
function getJsxName(node) {
if (!node) return null;
if (node.type === "JSXIdentifier") return node.name;
if (node.type === "JSXMemberExpression") {
const obj = getJsxName(node.object);
return obj ? `${obj}.${node.property?.name}` : null;
}
return null;
}
function getLocation(offset) {
const lines = code.slice(0, offset).split(`
`);
return {
line: lines.length,
column: lines[lines.length - 1].length + 1
};
}
function walk(node) {
if (!(!node || typeof node != "object")) {
if (node.type === "JSXOpeningElement" && node.name) {
const tagName = getJsxName(node.name);
if (tagName && tagName !== "Fragment" && !tagName.endsWith(".Fragment") && !node.attributes?.some(attr => attr.type === "JSXAttribute" && attr.name?.name === "data-one-source")) {
const nameEnd = node.name.end,
loc = getLocation(node.start);
locations.push({
insertOffset: nameEnd,
line: loc.line,
column: loc.column
});
}
}
for (const key of Object.keys(node)) {
if (key === "parent") continue;
const value = node[key];
if (Array.isArray(value)) for (const child of value) walk(child);else value && typeof value == "object" && walk(value);
}
}
}
return walk(result.program), locations.sort((a, b) => b.insertOffset - a.insertOffset);
}
async function injectSourceToJsx(code, id) {
const [filePath] = id.split("?");
if (!filePath) return;
const location = filePath.replace((0, import_vite.normalizePath)(process.cwd()), "");
if (!code.includes("<") || !code.includes(">")) return;
const jsxLocations = await findJsxElements(code, filePath);
if (jsxLocations.length === 0) return;
let result = code;
for (const jsx of jsxLocations) {
const sourceAttr = ` data-one-source="${location}:${jsx.line}:${jsx.column}"`;
result = result.slice(0, jsx.insertOffset) + sourceAttr + result.slice(jsx.insertOffset);
}
return {
code: result,
map: null
};
}
async function openInEditor(filePath, line, column) {
try {
const launch = (await import("launch-editor")).default,
location = `${import_node_path.default.join(process.cwd(), filePath)}${line ? `:${line}` : ""}${column ? `:${column}` : ""}`;
launch(location, void 0, (filename, errorMessage) => {
errorMessage && console.warn(`[one:source-inspector] Failed to open ${filename} in editor:`, errorMessage);
});
} catch (err) {
console.warn("[one:source-inspector] Failed to launch editor:", err);
}
}
const vscodeClients = /* @__PURE__ */new Set();
function sourceInspectorPlugin() {
const cache = /* @__PURE__ */new Map();
return [
// Transform plugin - injects data-one-source attributes
{
name: "one:source-inspector-transform",
enforce: "pre",
apply: "serve",
async transform(code, id) {
const envName = this.environment?.name;
if (envName === "ios" || envName === "android" || id.includes("node_modules") || id.includes("?raw") || id.includes("dist") || id.includes("build") || !id.endsWith(".jsx") && !id.endsWith(".tsx")) return;
if (cache.has(code)) return cache.get(code);
const out = await injectSourceToJsx(code, id);
return cache.set(code, out), cache.size > 100 && cache.clear(), out;
}
},
// Note: Inspector UI script is now injected via DevHead.tsx for SSR compatibility
// Server plugin - handles open-source requests and cursor WebSocket
{
name: "one:source-inspector-server",
apply: "serve",
configureServer(server) {
let wss = null;
import("ws").then(({
WebSocketServer
}) => {
wss = new WebSocketServer({
noServer: !0
}), server.httpServer?.on("upgrade", (req, socket, head) => {
req.url === "/__one/cursor" && wss.handleUpgrade(req, socket, head, ws => {
vscodeClients.add(ws), ws.on("message", data => {
try {
const message = JSON.parse(data.toString());
message.type === "cursor-position" ? server.hot.send("one:cursor-highlight", {
file: message.file,
line: message.line,
column: message.column
}) : message.type === "cursor-clear" && server.hot.send("one:cursor-highlight", {
clear: !0
});
} catch {}
}), ws.on("close", () => {
vscodeClients.delete(ws), server.hot.send("one:cursor-highlight", {
clear: !0
});
});
});
});
}), server.middlewares.use(async (req, res, next) => {
if (!req.url?.startsWith("/__one/open-source")) return next();
try {
const source = new URL(req.url, "http://localhost").searchParams.get("source");
if (!source) {
res.statusCode = 400, res.end("Missing source parameter");
return;
}
const parts = source.split(":"),
column = parts.pop(),
line = parts.pop(),
filePath = parts.join(":");
await openInEditor(filePath, line, column), res.statusCode = 200, res.end("OK");
} catch (err) {
console.error("[one:source-inspector] Error:", err), res.statusCode = 500, res.end("Internal server error");
}
});
}
}];
}