UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

341 lines (339 loc) 12.9 kB
import { spawn } from "child_process"; import { existsSync } from "fs"; import path from "path"; import { parse } from "oxc-parser"; import { normalizePath } from "vite"; function _type_of(obj) { "@swc/helpers - typeof"; return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; } var DOM_TAGS = new Set("a abbr address area article aside audio b base bdi bdo blockquote body br button canvas caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins kbd label legend li link main map mark menu meta meter nav noscript object ol optgroup option output p picture pre progress q rp rt ruby s samp script search section select slot small source span strong style sub summary sup table tbody td template textarea tfoot th thead time title tr track u ul var video wbr svg animate animateMotion animateTransform circle clipPath defs desc ellipse feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting feDisplacementMap feDistantLight feDropShadow feFlood feFuncA feFuncB feFuncG feFuncR feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting feSpotLight feTile feTurbulence filter foreignObject g image line linearGradient marker mask metadata mpath path pattern polygon polyline radialGradient rect set stop switch symbol text textPath tspan use view".split(" ")); function isHostTag(tagName) { var first = tagName.charCodeAt(0); return first >= 97 && first <= 122 && !tagName.includes("."); } async function findJsxElements(code, filename) { var result = await parse(filename, code); if (result.errors.length > 0) { return []; } var locations = []; function getJsxName(node) { if (!node) return null; if (node.type === "JSXIdentifier") return node.name; if (node.type === "JSXMemberExpression") { var _node_property; var obj = getJsxName(node.object); return obj ? `${obj}.${(_node_property = node.property) === null || _node_property === void 0 ? void 0 : _node_property.name}` : null; } return null; } function getLocation(offset) { var before = code.slice(0, offset); var lines = before.split("\n"); return { line: lines.length, column: lines[lines.length - 1].length + 1 }; } function walk(node) { if (!node || (typeof node === "undefined" ? "undefined" : _type_of(node)) !== "object") return; if (node.type === "JSXOpeningElement" && node.name) { var tagName = getJsxName(node.name); if (tagName && tagName !== "Fragment" && !tagName.endsWith(".Fragment") && (!isHostTag(tagName) || DOM_TAGS.has(tagName))) { var _node_attributes; var hasSourceAttr = (_node_attributes = node.attributes) === null || _node_attributes === void 0 ? void 0 : _node_attributes.some(function (attr) { var _attr_name; return attr.type === "JSXAttribute" && ((_attr_name = attr.name) === null || _attr_name === void 0 ? void 0 : _attr_name.name) === "data-one-source"; }); if (!hasSourceAttr) { var nameEnd = node.name.end; var loc = getLocation(node.start); locations.push({ insertOffset: nameEnd, line: loc.line, column: loc.column }); } } } var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0; try { for (var _iterator = Object.keys(node)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var key = _step.value; if (key === "parent") continue; var value = node[key]; if (Array.isArray(value)) { var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = void 0; try { for (var _iterator1 = value[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true) { var child = _step1.value; walk(child); } } catch (err) { _didIteratorError1 = true; _iteratorError1 = err; } finally { try { if (!_iteratorNormalCompletion1 && _iterator1.return != null) { _iterator1.return(); } } finally { if (_didIteratorError1) { throw _iteratorError1; } } } } else if (value && (typeof value === "undefined" ? "undefined" : _type_of(value)) === "object") { walk(value); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } walk(result.program); return locations.sort(function (a, b) { return b.insertOffset - a.insertOffset; }); } function getSourceInspectorPath(filePath) { var cwd = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : process.cwd(); var normalizedFilePath = normalizePath(filePath); var normalizedCwd = normalizePath(cwd); if (normalizedFilePath === normalizedCwd) { return "/"; } if (normalizedFilePath.startsWith(`${normalizedCwd}/`)) { return normalizedFilePath.slice(normalizedCwd.length); } return normalizedFilePath; } function resolveEditorFilePath(filePath) { var cwd = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : process.cwd(), fileExists = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : existsSync; var projectPath = normalizePath(path.join(cwd, filePath)); return fileExists(projectPath) ? projectPath : filePath; } async function injectSourceToJsx(code, id) { var [filePath] = id.split("?"); if (!filePath) return; var location = getSourceInspectorPath(filePath); if (!code.includes("<") || !code.includes(">")) { return; } var jsxLocations = await findJsxElements(code, filePath); if (jsxLocations.length === 0) { return; } var result = code; var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0; try { for (var _iterator = jsxLocations[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var jsx = _step.value; var sourceAttr = ` data-one-source="${location}:${jsx.line}:${jsx.column}"`; result = result.slice(0, jsx.insertOffset) + sourceAttr + result.slice(jsx.insertOffset); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return { code: result, map: null }; } var editorWarned = false; var editorArgs = { code: function (f, l, c) { return ["-g", `${f}:${l}:${c}`]; }, cursor: function (f, l, c) { return ["-g", `${f}:${l}:${c}`]; }, codium: function (f, l, c) { return ["-g", `${f}:${l}:${c}`]; }, vscodium: function (f, l, c) { return ["-g", `${f}:${l}:${c}`]; }, zed: function (f, l, c) { return [`${f}:${l}:${c}`]; }, subl: function (f, l, c) { return [`${f}:${l}:${c}`]; }, webstorm: function (f, l, c) { return ["--line", l, "--column", c, f]; }, idea: function (f, l, c) { return ["--line", l, "--column", c, f]; }, vim: function (f, l) { return [`+${l}`, f]; }, nvim: function (f, l) { return [`+${l}`, f]; }, emacs: function (f, l, c) { return [`+${l}:${c}`, f]; } }; function openInEditor(editor, filePath, line, column) { var resolved = editor || process.env.LAUNCH_EDITOR || process.env.EDITOR; if (!resolved) { if (!editorWarned) { editorWarned = true; console.warn(`[one] Set devtools.editor in your one config or LAUNCH_EDITOR env var to open files from the inspector (e.g. 'cursor', 'code', 'zed')`); } return; } var fullPath = resolveEditorFilePath(filePath); var l = line || "1"; var c = column || "1"; var buildArgs = editorArgs[resolved]; var args = buildArgs ? buildArgs(fullPath, l, c) : [fullPath]; var child = spawn(resolved, args, { stdio: "ignore", detached: true }); child.unref(); child.on("error", function (err) { console.warn(`[one:source-inspector] Failed to open editor '${resolved}': ${err.message}`); }); } var vscodeClients = /* @__PURE__ */new Set(); function sourceInspectorPlugin(opts) { var cache = /* @__PURE__ */new Map(); return [ // Transform plugin - injects data-one-source attributes { name: "one:source-inspector-transform", enforce: "pre", apply: "serve", transform: { // must run before clientTreeShakePlugin which also uses order: 'pre' // (within same order, plugin array position determines precedence) order: "pre", async handler(code, id) { var _this_environment; var envName = (_this_environment = this.environment) === null || _this_environment === void 0 ? void 0 : _this_environment.name; if (envName === "ios" || envName === "android") return; if (id.includes("node_modules") || id.includes("?raw") || id.includes("dist") || id.includes("build")) { return; } if (!id.endsWith(".jsx") && !id.endsWith(".tsx")) return; if (cache.has(code)) { return cache.get(code); } var out = await injectSourceToJsx(code, id); cache.set(code, out); if (cache.size > 100) { cache.clear(); } return 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) { var wss = null; import("ws").then(function (param) { var { WebSocketServer } = param; var _server_httpServer; wss = new WebSocketServer({ noServer: true }); (_server_httpServer = server.httpServer) === null || _server_httpServer === void 0 ? void 0 : _server_httpServer.on("upgrade", function (req, socket, head) { if (req.url !== "/__one/cursor") return; wss.handleUpgrade(req, socket, head, function (ws) { vscodeClients.add(ws); ws.on("message", function (data) { try { var message = JSON.parse(data.toString()); if (message.type === "cursor-position") { server.hot.send("one:cursor-highlight", { file: message.file, line: message.line, column: message.column }); } else if (message.type === "cursor-clear") { server.hot.send("one:cursor-highlight", { clear: true }); } } catch (unused) {} }); ws.on("close", function () { vscodeClients.delete(ws); server.hot.send("one:cursor-highlight", { clear: true }); }); }); }); }); server.middlewares.use(async function (req, res, next) { var _req_url; if (!((_req_url = req.url) === null || _req_url === void 0 ? void 0 : _req_url.startsWith("/__one/open-source"))) { return next(); } try { var url = new URL(req.url, "http://localhost"); var source = url.searchParams.get("source"); if (!source) { res.statusCode = 400; res.end("Missing source parameter"); return; } var parts = source.split(":"); var column = parts.pop(); var line = parts.pop(); var filePath = parts.join(":"); openInEditor(opts === null || opts === void 0 ? void 0 : opts.editor, 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"); } }); } }]; } export { getSourceInspectorPath, injectSourceToJsx, resolveEditorFilePath, sourceInspectorPlugin }; //# sourceMappingURL=sourceInspectorPlugin.native.js.map