bosia 0.5.12 → 0.5.13
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bosia",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A fast, batteries-included fullstack framework — SSR · Svelte 5 Runes · Bun · ElysiaJS. File-based routing inspired by SvelteKit. No Node.js, no Vite, no adapters.",
|
|
6
6
|
"keywords": [
|
|
@@ -66,18 +66,40 @@ function injectLocs(source: string, relPath: string): string {
|
|
|
66
66
|
if (!ast.fragment) return source;
|
|
67
67
|
|
|
68
68
|
const ms = new MagicString(source);
|
|
69
|
+
const safeAttr = relPath.replace(/"/g, """);
|
|
70
|
+
// HTML comment data cannot contain `--`; neutralise defensively. (Almost no
|
|
71
|
+
// real path contains it, but a stray `--foo` directory shouldn't break parsing.)
|
|
72
|
+
const safeComment = relPath.replace(/--/g, "__");
|
|
69
73
|
walk(ast.fragment, (node) => {
|
|
70
|
-
if (node.type
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
if (node.type === "RegularElement") {
|
|
75
|
+
const name = node.name ?? "";
|
|
76
|
+
if (!name) return;
|
|
77
|
+
if (name === "script" || name === "style") return;
|
|
78
|
+
if (/^[A-Z]/.test(name)) return;
|
|
79
|
+
if (name.includes(":")) return;
|
|
80
|
+
if (typeof node.start !== "number") return;
|
|
81
|
+
const insertAt = node.start + 1 + name.length;
|
|
82
|
+
const { line, col } = lineColFromOffset(source, node.start);
|
|
83
|
+
ms.appendLeft(insertAt, ` data-bosia-loc="${safeAttr}:${line}:${col}"`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Bracket component invocations with HTML comments so the runtime can
|
|
87
|
+
// walk DOM siblings to reconstruct the call-site chain (Page → Layout →
|
|
88
|
+
// Button). Without this the per-element `data-bosia-loc` only points at
|
|
89
|
+
// the component's *definition* file, which is misleading when the user
|
|
90
|
+
// (or an AI agent) wants to edit the page that rendered it. Comments
|
|
91
|
+
// survive into the rendered DOM because `preserveComments: dev` is set
|
|
92
|
+
// on the compile call below.
|
|
93
|
+
if (
|
|
94
|
+
node.type === "Component" ||
|
|
95
|
+
node.type === "SvelteComponent" ||
|
|
96
|
+
node.type === "SvelteSelf"
|
|
97
|
+
) {
|
|
98
|
+
if (typeof node.start !== "number" || typeof node.end !== "number") return;
|
|
99
|
+
const { line, col } = lineColFromOffset(source, node.start);
|
|
100
|
+
ms.appendLeft(node.start, `<!--bosia:o=${safeComment}:${line}:${col}-->`);
|
|
101
|
+
ms.appendRight(node.end, `<!--bosia:c-->`);
|
|
102
|
+
}
|
|
81
103
|
});
|
|
82
104
|
return ms.toString();
|
|
83
105
|
}
|
|
@@ -26,7 +26,7 @@ function ensureOutline(){
|
|
|
26
26
|
outline.style.cssText="position:fixed;pointer-events:none;border:2px solid #f73b27;background:rgba(247,59,39,.08);z-index:2147483646;border-radius:2px;transition:all .05s linear;display:none";
|
|
27
27
|
document.body.appendChild(outline);
|
|
28
28
|
tip=document.createElement("div");
|
|
29
|
-
tip.style.cssText="position:fixed;pointer-events:none;background:#111;color:#fff;font:11px/1.4 ui-monospace,monospace;padding:3px 6px;border-radius:3px;z-index:2147483647;display:none;white-space:nowrap";
|
|
29
|
+
tip.style.cssText="position:fixed;pointer-events:none;background:#111;color:#fff;font:11px/1.4 ui-monospace,monospace;padding:3px 6px;border-radius:3px;z-index:2147483647;display:none;white-space:nowrap;max-width:90vw;overflow:hidden;text-overflow:ellipsis";
|
|
30
30
|
document.body.appendChild(tip);
|
|
31
31
|
}
|
|
32
32
|
function hideOutline(){if(outline)outline.style.display="none";if(tip)tip.style.display="none"}
|
|
@@ -43,6 +43,38 @@ function showOutline(el,loc){
|
|
|
43
43
|
function parseLoc(s){var m=/^(.+):(\\d+):(\\d+)$/.exec(s);if(!m)return null;return{file:m[1],line:+m[2],col:+m[3]}}
|
|
44
44
|
function findTarget(e){var n=e.target;while(n&&n.nodeType===1){if(n.hasAttribute&&n.hasAttribute("data-bosia-loc"))return n;n=n.parentNode}return null}
|
|
45
45
|
|
|
46
|
+
// Walk DOM ancestors collecting <Component> call-site markers (<!--bosia:o=…-->
|
|
47
|
+
// / <!--bosia:c-->) into an outermost-first array. At each ancestor we scan
|
|
48
|
+
// previous siblings tracking a depth counter so an earlier sibling component's
|
|
49
|
+
// open marker doesn't get attributed to a later sibling's element.
|
|
50
|
+
function collectStack(el){
|
|
51
|
+
var stack=[],cur=el;
|
|
52
|
+
while(cur){
|
|
53
|
+
var depth=0,sib=cur.previousSibling;
|
|
54
|
+
while(sib){
|
|
55
|
+
if(sib.nodeType===8){
|
|
56
|
+
var v=sib.nodeValue||"";
|
|
57
|
+
if(v==="bosia:c") depth++;
|
|
58
|
+
else if(v.lastIndexOf("bosia:o=",0)===0){
|
|
59
|
+
if(depth>0) depth--;
|
|
60
|
+
else stack.push(v.slice(8));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
sib=sib.previousSibling;
|
|
64
|
+
}
|
|
65
|
+
var p=cur.parentNode;
|
|
66
|
+
if(!p||p.nodeType!==1) break;
|
|
67
|
+
cur=p;
|
|
68
|
+
}
|
|
69
|
+
return stack.reverse();
|
|
70
|
+
}
|
|
71
|
+
function chainString(el){
|
|
72
|
+
var stack=collectStack(el);
|
|
73
|
+
var leaf=el.getAttribute("data-bosia-loc")||"";
|
|
74
|
+
if(!stack.length) return leaf;
|
|
75
|
+
return stack.concat(leaf).join(" → ");
|
|
76
|
+
}
|
|
77
|
+
|
|
46
78
|
function toast(msg,err){
|
|
47
79
|
var t=document.createElement("div");
|
|
48
80
|
t.textContent=msg;
|
|
@@ -62,10 +94,12 @@ function send(payload,onOk,onErr){
|
|
|
62
94
|
function closeForm(){if(form){form.remove();form=null}}
|
|
63
95
|
function openForm(loc,el){
|
|
64
96
|
closeForm();
|
|
97
|
+
var chain=chainString(el);
|
|
65
98
|
var r=el.getBoundingClientRect();
|
|
66
99
|
form=document.createElement("div");
|
|
67
100
|
form.style.cssText="position:fixed;left:"+r.left+"px;top:"+(r.bottom+6)+"px;background:#fff;color:#111;border:1px solid #d4d4d8;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:10px;width:340px;z-index:2147483647;font:13px ui-sans-serif,system-ui,sans-serif";
|
|
68
|
-
|
|
101
|
+
var header='<div style="font-size:11px;color:#71717a;margin-bottom:6px;font-family:ui-monospace,monospace;word-break:break-all">'+chain+'</div>';
|
|
102
|
+
form.innerHTML=header+
|
|
69
103
|
'<textarea placeholder="Describe a fix (Enter to send, Esc to cancel, empty = open in editor)" style="width:100%;min-height:64px;border:1px solid #e4e4e7;border-radius:4px;padding:6px;font:13px ui-sans-serif,system-ui,sans-serif;resize:vertical;box-sizing:border-box;outline:none"></textarea>'+
|
|
70
104
|
'<div style="margin-top:8px;display:flex;gap:6px;justify-content:flex-end">'+
|
|
71
105
|
'<button data-cancel style="padding:4px 10px;border:1px solid #e4e4e7;background:#fff;border-radius:4px;cursor:pointer;font-size:12px">Cancel</button>'+
|
|
@@ -75,9 +109,12 @@ function openForm(loc,el){
|
|
|
75
109
|
var ta=form.querySelector("textarea");
|
|
76
110
|
ta.focus();
|
|
77
111
|
function submit(){
|
|
78
|
-
var
|
|
112
|
+
var userComment=ta.value.trim();
|
|
79
113
|
var payload={file:loc.file,line:loc.line,col:loc.col};
|
|
80
|
-
if(
|
|
114
|
+
if(userComment){
|
|
115
|
+
var tree=chain.indexOf(" → ")>=0?("Component tree (outer → leaf): "+chain+"\\n\\n"):"";
|
|
116
|
+
payload.comment=tree+userComment;
|
|
117
|
+
}
|
|
81
118
|
send(payload,function(j){toast(j.mode==="ai"?"sent to AI":"opened "+loc.file+":"+loc.line)});
|
|
82
119
|
closeForm();
|
|
83
120
|
}
|
|
@@ -100,7 +137,7 @@ window.addEventListener("mousemove",function(e){
|
|
|
100
137
|
if(!altDown||form){hideOutline();return}
|
|
101
138
|
var el=findTarget(e);
|
|
102
139
|
if(!el){hideOutline();return}
|
|
103
|
-
showOutline(el,el
|
|
140
|
+
showOutline(el,chainString(el));
|
|
104
141
|
},true);
|
|
105
142
|
|
|
106
143
|
window.addEventListener("click",function(e){
|
|
@@ -137,7 +174,7 @@ if(ERR_ENABLED){
|
|
|
137
174
|
var t=e.target;
|
|
138
175
|
if(!t||!t.closest)return;
|
|
139
176
|
var el=t.closest("[data-bosia-loc]");
|
|
140
|
-
if(el)lastInteraction=el
|
|
177
|
+
if(el)lastInteraction=chainString(el);
|
|
141
178
|
}
|
|
142
179
|
window.addEventListener("mousedown",trackInteraction,true);
|
|
143
180
|
window.addEventListener("keydown",trackInteraction,true);
|