childrenがduplicate key errorを吐く問題をいったん解決
This commit is contained in:
parent
6d4d2c5c20
commit
f8282e8d1f
|
@ -201,6 +201,15 @@ async function processVueFile(
|
||||||
options: { targetFilePaths: string[], exportFilePath: string },
|
options: { targetFilePaths: string[], exportFilePath: string },
|
||||||
transformedCodeCache: Record<string, string>
|
transformedCodeCache: Record<string, string>
|
||||||
) {
|
) {
|
||||||
|
// すでにキャッシュに存在する場合は、そのまま返す
|
||||||
|
if (transformedCodeCache[id] && transformedCodeCache[id].includes('markerId=')) {
|
||||||
|
console.log(`[create-search-index] Using cached version for ${id}`);
|
||||||
|
return {
|
||||||
|
code: transformedCodeCache[id],
|
||||||
|
map: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const s = new MagicString(code); // magic-string のインスタンスを作成
|
const s = new MagicString(code); // magic-string のインスタンスを作成
|
||||||
const parsed = vueSfcParse(code, { filename: id });
|
const parsed = vueSfcParse(code, { filename: id });
|
||||||
if (!parsed.descriptor.template) {
|
if (!parsed.descriptor.template) {
|
||||||
|
@ -238,9 +247,34 @@ async function processVueFile(
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!hasMarkerIdProp) {
|
if (!hasMarkerIdProp) {
|
||||||
const startTagEnd = code.indexOf('>', node.loc.start.offset);
|
const nodeStart = node.loc.start.offset;
|
||||||
if (startTagEnd !== -1) {
|
let endOfStartTag;
|
||||||
s.appendRight(startTagEnd, ` markerId="${generatedMarkerId}"`);
|
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
// 子要素がある場合、最初の子要素の開始位置を基準にする
|
||||||
|
endOfStartTag = code.lastIndexOf('>', node.children[0].loc.start.offset);
|
||||||
|
} else if (node.loc.end.offset > nodeStart) {
|
||||||
|
// 子要素がない場合、自身の終了位置から逆算
|
||||||
|
const nodeSource = code.substring(nodeStart, node.loc.end.offset);
|
||||||
|
// 自己終了タグか通常の終了タグかを判断
|
||||||
|
if (nodeSource.includes('/>')) {
|
||||||
|
endOfStartTag = code.indexOf('/>', nodeStart) - 1;
|
||||||
|
} else {
|
||||||
|
endOfStartTag = code.indexOf('>', nodeStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endOfStartTag !== undefined && endOfStartTag !== -1) {
|
||||||
|
// markerId が既に存在しないことを確認
|
||||||
|
const tagText = code.substring(nodeStart, endOfStartTag + 1);
|
||||||
|
const markerIdRegex = /\s+markerId\s*=\s*["'][^"']*["']/;
|
||||||
|
|
||||||
|
if (!markerIdRegex.test(tagText)) {
|
||||||
|
s.appendRight(endOfStartTag, ` markerId="${generatedMarkerId}"`);
|
||||||
|
console.log(`[create-search-index] Adding markerId="${generatedMarkerId}" to ${id}:${lineNumber}`);
|
||||||
|
} else {
|
||||||
|
console.log(`[create-search-index] markerId already exists in ${id}:${lineNumber}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,39 +288,100 @@ async function processVueFile(
|
||||||
traverse(ast); // AST を traverse (1段階目: ID 生成と親子関係記録)
|
traverse(ast); // AST を traverse (1段階目: ID 生成と親子関係記録)
|
||||||
|
|
||||||
// 2段階目: :children 属性の追加
|
// 2段階目: :children 属性の追加
|
||||||
|
// 最初に親マーカーごとに子マーカーIDを集約する処理を追加
|
||||||
|
const parentChildrenMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
// 1. まず親ごとのすべての子マーカーIDを収集
|
||||||
markerRelations.forEach(relation => {
|
markerRelations.forEach(relation => {
|
||||||
if (relation.parentId) { // 親 ID が存在する (子マーカーである) 場合
|
if (relation.parentId) {
|
||||||
const parentRelation = markerRelations.find(r => r.markerId === relation.parentId); // 親 Relation を検索
|
if (!parentChildrenMap.has(relation.parentId)) {
|
||||||
if (parentRelation && parentRelation.node) {
|
parentChildrenMap.set(relation.parentId, []);
|
||||||
|
}
|
||||||
|
parentChildrenMap.get(relation.parentId)?.push(relation.markerId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. 親ごとにまとめて :children 属性を処理
|
||||||
|
for (const [parentId, childIds] of parentChildrenMap.entries()) {
|
||||||
|
const parentRelation = markerRelations.find(r => r.markerId === parentId);
|
||||||
|
if (!parentRelation || !parentRelation.node) continue;
|
||||||
|
|
||||||
const parentNode = parentRelation.node;
|
const parentNode = parentRelation.node;
|
||||||
const childrenProp = parentNode.props?.find((prop: any) => prop.type === 7 && prop.name === 'bind' && prop.arg?.content === 'children');
|
const childrenProp = parentNode.props?.find((prop: any) => prop.type === 7 && prop.name === 'bind' && prop.arg?.content === 'children');
|
||||||
const childMarkerId = relation.markerId;
|
|
||||||
|
// 親ノードの開始位置を特定
|
||||||
|
const parentNodeStart = parentNode.loc.start.offset;
|
||||||
|
const endOfParentStartTag = parentNode.children && parentNode.children.length > 0
|
||||||
|
? code.lastIndexOf('>', parentNode.children[0].loc.start.offset)
|
||||||
|
: code.indexOf('>', parentNodeStart);
|
||||||
|
|
||||||
|
if (endOfParentStartTag === -1) continue;
|
||||||
|
|
||||||
|
// 親タグのテキストを取得
|
||||||
|
const parentTagText = code.substring(parentNodeStart, endOfParentStartTag + 1);
|
||||||
|
|
||||||
if (childrenProp) {
|
if (childrenProp) {
|
||||||
// 既存の :children 属性を JavaScript 配列として解析・更新
|
// AST で :children 属性が検出された場合、それを更新
|
||||||
try {
|
try {
|
||||||
const childrenStart = code.indexOf('[', childrenProp.exp.loc.start.offset);
|
const childrenStart = code.indexOf('[', childrenProp.exp.loc.start.offset);
|
||||||
const childrenEnd = code.indexOf(']', childrenProp.exp.loc.start.offset);
|
const childrenEnd = code.indexOf(']', childrenProp.exp.loc.start.offset);
|
||||||
if (childrenStart !== -1 && childrenEnd !== -1) {
|
if (childrenStart !== -1 && childrenEnd !== -1) {
|
||||||
const childrenArrayStr = code.slice(childrenStart, childrenEnd + 1);
|
const childrenArrayStr = code.slice(childrenStart, childrenEnd + 1);
|
||||||
const childrenArray = JSON5.parse(childrenArrayStr.replace(/'/g, '"')); // JSON5 で解析 (シングルクォート対応)
|
let childrenArray = JSON5.parse(childrenArrayStr.replace(/'/g, '"'));
|
||||||
childrenArray.push(childMarkerId); // 子マーカーIDを追加
|
|
||||||
const updatedChildrenArrayStr = JSON.stringify(childrenArray).replace(/"/g, "'"); // シングルクォートの配列文字列に再変換
|
// 新しいIDを追加(重複は除外)
|
||||||
s.overwrite(childrenStart, childrenEnd + 1, updatedChildrenArrayStr); // 属性値を書き換え
|
const newIds = childIds.filter(id => !childrenArray.includes(id));
|
||||||
|
if (newIds.length > 0) {
|
||||||
|
childrenArray = [...childrenArray, ...newIds];
|
||||||
|
const updatedChildrenArrayStr = JSON.stringify(childrenArray).replace(/"/g, "'");
|
||||||
|
s.overwrite(childrenStart, childrenEnd + 1, updatedChildrenArrayStr);
|
||||||
|
console.log(`[create-search-index] Added ${newIds.length} child markerIds to existing :children in ${id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[create-search-index] Error updating :children attribute:', e); // エラーログ
|
console.error('[create-search-index] Error updating :children attribute:', e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// :children 属性が存在しない場合は新規作成 (テンプレートリテラルを使用)
|
// AST では検出されなかった場合、タグテキストを調べる
|
||||||
const startTagEnd = code.indexOf('>', parentNode.loc.start.offset); // 親の開始タグの閉じ > の位置
|
const childrenRegex = /:children\s*=\s*["']\[(.*?)\]["']/;
|
||||||
if (startTagEnd !== -1) {
|
const childrenMatch = parentTagText.match(childrenRegex);
|
||||||
s.appendRight(startTagEnd, ` :children="${JSON.stringify([childMarkerId]).replace(/"/g, "'")}"`); // :children 属性を追記
|
|
||||||
|
if (childrenMatch) {
|
||||||
|
// テキストから :children 属性値を解析して更新
|
||||||
|
try {
|
||||||
|
const childrenContent = childrenMatch[1];
|
||||||
|
const childrenArrayStr = `[${childrenContent}]`;
|
||||||
|
const childrenArray = JSON5.parse(childrenArrayStr.replace(/'/g, '"'));
|
||||||
|
|
||||||
|
// 新しいIDを追加(重複は除外)
|
||||||
|
const newIds = childIds.filter(id => !childrenArray.includes(id));
|
||||||
|
if (newIds.length > 0) {
|
||||||
|
childrenArray.push(...newIds);
|
||||||
|
|
||||||
|
// :children="[...]" の位置を特定して上書き
|
||||||
|
const attrStart = parentTagText.indexOf(':children=');
|
||||||
|
if (attrStart > -1) {
|
||||||
|
const attrValueStart = parentTagText.indexOf('[', attrStart);
|
||||||
|
const attrValueEnd = parentTagText.indexOf(']', attrValueStart) + 1;
|
||||||
|
if (attrValueStart > -1 && attrValueEnd > -1) {
|
||||||
|
const absoluteStart = parentNodeStart + attrValueStart;
|
||||||
|
const absoluteEnd = parentNodeStart + attrValueEnd;
|
||||||
|
const updatedArrayStr = JSON.stringify(childrenArray).replace(/"/g, "'");
|
||||||
|
s.overwrite(absoluteStart, absoluteEnd, updatedArrayStr);
|
||||||
|
console.log(`[create-search-index] Updated existing :children in tag text for ${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[create-search-index] Error updating :children in tag text:', e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// :children 属性がまだない場合、新規作成
|
||||||
|
s.appendRight(endOfParentStartTag, ` :children="${JSON.stringify(childIds).replace(/"/g, "'")}"`);
|
||||||
|
console.log(`[create-search-index] Created new :children attribute with ${childIds.length} markerIds in ${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformedCode = s.toString(); // 変換後のコードを取得
|
const transformedCode = s.toString(); // 変換後のコードを取得
|
||||||
|
|
Loading…
Reference in New Issue