Files
qiming/qiming-vite-plugin-design-mode/packages/client-shared/src/sourceInfoResolver.js
2026-06-01 13:43:09 +08:00

157 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { AttributeNames } from './attributeNames';
import { extractSourceInfo } from './sourceInfo';
/**
* BFS for the first descendant whose `{prefix}-info` points at a different file than `currentFile`.
* Used to detect wrapper components (e.g. `<button>` inside a design-system `Button`).
*
* @param element Root to search under
* @param currentFile File path of the current elements mapping
*/
function findChildFromDifferentFile(element, currentFile) {
const queue = [];
for (let i = 0; i < element.children.length; i++) {
const child = element.children[i];
if (child instanceof HTMLElement) {
queue.push(child);
}
}
let depth = 0;
const maxDepth = 5;
while (queue.length > 0 && depth < maxDepth) {
const levelSize = queue.length;
for (let i = 0; i < levelSize; i++) {
const child = queue.shift();
if (!child)
continue;
const childInfo = extractSourceInfo(child);
if (childInfo && childInfo.fileName !== currentFile) {
return child;
}
for (let j = 0; j < child.children.length; j++) {
const grandChild = child.children[j];
if (grandChild instanceof HTMLElement) {
queue.push(grandChild);
}
}
}
depth++;
}
return null;
}
/**
* Resolve the **usage-site** `SourceInfo` for an element.
*
* Pass-through/static-content nodes may be compiled inside a UI-kit file; this walks
* parents / `children-source` / cross-file children so selections map to the caller file.
*/
export function resolveSourceInfo(element) {
const hasStaticContent = element.hasAttribute(AttributeNames.staticContent);
const currentInfo = extractSourceInfo(element);
const currentFile = currentInfo?.fileName;
if (currentInfo?.isUIComponent) {
let parent = element.parentElement;
let depth = 0;
while (parent && depth < 20) {
const parentInfo = extractSourceInfo(parent);
if (parentInfo?.fileName && !parentInfo.isUIComponent) {
return {
fileName: parentInfo.fileName,
lineNumber: parentInfo.lineNumber,
columnNumber: parentInfo.columnNumber,
elementType: element.tagName?.toLowerCase() || 'unknown',
componentName: currentInfo?.componentName,
functionName: currentInfo?.functionName
};
}
parent = parent.parentElement;
depth++;
}
}
const candidates = [
'data-xagi-children-source',
'data-source-children-source',
AttributeNames.childrenSource
];
let childrenSource = null;
for (const attr of candidates) {
const val = element.getAttribute(attr);
if (val) {
childrenSource = val;
break;
}
}
if (childrenSource) {
const parts = childrenSource.split(':');
if (parts.length >= 3) {
const fileName = parts.slice(0, -2).join(':'); // Paths may contain `:`
const lineNumber = parseInt(parts[parts.length - 2], 10);
const columnNumber = parseInt(parts[parts.length - 1], 10);
if (!isNaN(lineNumber) && !isNaN(columnNumber)) {
return {
fileName,
lineNumber,
columnNumber,
elementType: element.tagName?.toLowerCase() || 'unknown',
componentName: currentInfo?.componentName,
functionName: currentInfo?.functionName
};
}
}
}
if (currentFile) {
const childWithDifferentSource = findChildFromDifferentFile(element, currentFile);
if (childWithDifferentSource) {
const childInfo = extractSourceInfo(childWithDifferentSource);
if (childInfo && childInfo.fileName !== currentFile) {
return {
fileName: childInfo.fileName,
lineNumber: childInfo.lineNumber,
columnNumber: childInfo.columnNumber,
elementType: element.tagName?.toLowerCase() || 'unknown',
componentName: currentInfo?.componentName,
functionName: currentInfo?.functionName
};
}
}
}
if (!hasStaticContent) {
return extractSourceInfo(element);
}
let currentElement = element;
let depth = 0;
while (currentElement && depth < 20) {
const parent = currentElement.parentElement;
if (!parent) {
break;
}
const parentInfo = extractSourceInfo(parent);
const parentFile = parentInfo?.fileName;
const parentHasStaticContent = parent.hasAttribute(AttributeNames.staticContent);
if (parentFile && (!parentHasStaticContent || parentFile !== currentFile)) {
return parentInfo;
}
currentElement = parent;
depth++;
}
return extractSourceInfo(element);
}
/**
* Heuristic: node lives in a component **definition** (both parent/child static, same file).
*/
export function isInComponentDefinition(element) {
const hasStaticContent = element.hasAttribute(AttributeNames.staticContent);
const sourceInfo = extractSourceInfo(element);
const sourceFile = sourceInfo?.fileName;
if (!hasStaticContent || !sourceFile) {
return false;
}
const parent = element.parentElement;
if (!parent) {
return false;
}
const parentInfo = extractSourceInfo(parent);
const parentFile = parentInfo?.fileName;
const parentHasStaticContent = parent.hasAttribute(AttributeNames.staticContent);
return parentHasStaticContent && parentFile === sourceFile;
}
//# sourceMappingURL=sourceInfoResolver.js.map