とりあえず省略記法に対応

This commit is contained in:
tai-cha 2025-03-02 09:53:53 +00:00
parent 8753c3cc37
commit ca80f4e273
6 changed files with 674 additions and 200 deletions

View File

@ -171,7 +171,7 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return resolveChildrenReferences(marker);
});
// 特殊なプロパティ変換用の関数
// 特殊なプロパティ変換用の関数 - i18n参照処理を強化
function formatSpecialProperty(key: string, value: any): string {
// 値がundefinedの場合は空文字列を返す
if (value === undefined) {
@ -183,55 +183,82 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return customStringify(value);
}
// 文字列でない場合はJSON5で文字列化
if (typeof value !== 'string') {
return JSON5.stringify(value);
// keywordsが配列の場合、特別に処理
if (key === 'keywords' && Array.isArray(value)) {
return `[${formatArrayForOutput(value)}]`;
}
// i18n.ts 参照を含む場合
if (value.includes('i18n.ts.')) {
return value; // クォートなしで直接返す
}
// 文字列値の場合の特別処理
if (typeof value === 'string') {
// i18n.ts 参照を含む場合 - クォートなしでそのまま出力
if (value.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in output: ${value}`);
return value;
}
// keywords が配列リテラルの形式の場合
if (key === 'keywords' && value.startsWith('[') && value.endsWith(']')) {
return value; // クォートなしで直接返す
// keywords が配列リテラルの形式の場合
if (key === 'keywords' && value.startsWith('[') && value.endsWith(']')) {
return value;
}
}
// 上記以外は通常の JSON5 文字列として返す
return JSON5.stringify(value);
}
// オブジェクトをカスタム形式に変換する関数
// オブジェクトをカスタム形式に変換する関数 - i18n参照処理を強化
function customStringify(obj: any, depth = 0): string {
const INDENT_STR = '\t';
// 配列の処理
if (Array.isArray(obj)) {
if (obj.length === 0) return '[]';
const indent = INDENT_STR.repeat(depth);
const childIndent = INDENT_STR.repeat(depth + 1);
const items = obj.map(item => `${childIndent}${customStringify(item, depth + 1)}`).join(',\n');
// 配列要素の処理
const items = obj.map(item => {
// オブジェクト要素
if (typeof item === 'object' && item !== null) {
return `${childIndent}${customStringify(item, depth + 1)}`;
}
// i18n参照を含む文字列要素
if (typeof item === 'string' && item.includes('i18n.ts.')) {
return `${childIndent}${item}`; // クォートなしでそのまま出力
}
// その他の要素
return `${childIndent}${JSON5.stringify(item)}`;
}).join(',\n');
return `[\n${items},\n${indent}]`;
}
// null または非オブジェクト
if (obj === null || typeof obj !== 'object') {
return JSON5.stringify(obj);
}
// オブジェクトの処理
const indent = INDENT_STR.repeat(depth);
const childIndent = INDENT_STR.repeat(depth + 1);
const entries = Object.entries(obj)
// 不要なプロパティを除去
.filter(([key, value]) => {
// valueがundefinedの場合は出力しない
if (value === undefined) return false;
// childrenが空配列の場合は出力しない
if (key === 'children' && Array.isArray(value) && value.length === 0) return false;
return true;
})
// 各プロパティを変換
.map(([key, value]) => {
// childrenが配列の場合で要素がある場合のみ特別処理
// 子要素配列の特殊処理
if (key === 'children' && Array.isArray(value) && value.length > 0) {
return `${childIndent}${key}: ${customStringify(value, depth + 1)}`;
}
// ラベルやその他プロパティを処理
return `${childIndent}${key}: ${formatSpecialProperty(key, value)}`;
});
@ -239,6 +266,20 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return `{\n${entries.join(',\n')},\n${indent}}`;
}
// 配列式の文字列表現を修正 - i18n参照を適切に処理
function formatArrayForOutput(items: any[]): string {
return items.map(item => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力
if (typeof item === 'string' && item.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in array: ${item}`);
return item; // クォートなしでそのまま
}
// その他の値はJSON5形式で文字列化
return JSON5.stringify(item);
}).join(', ');
}
// 最終出力用のデバッグ情報を生成
let totalMarkers = resolvedRootMarkers.length;
let totalChildren = 0;
@ -266,8 +307,6 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
// This file was automatically generated by create-search-index.
// Do not edit this file.
/* eslint-disable @stylistic/comma-spacing */
import { i18n } from '@/i18n.js';
export type SearchIndexItem = {
@ -282,8 +321,6 @@ export type SearchIndexItem = {
export const searchIndexes:SearchIndexItem[] = ${customStringify(resolvedRootMarkers)} as const;
export type SearchIndex = typeof searchIndexes;
/* eslint-enable @stylistic/comma-spacing */
`;
try {
@ -294,95 +331,350 @@ export type SearchIndex = typeof searchIndexes;
}
}
// 要素ノードからテキスト内容を抽出する関数 (Mustache構文のi18n参照にも対応)
function extractElementText(node: any): string | null {
if (!node) return null;
console.log(`Extracting text from node type=${node.type}, tag=${node.tag || 'unknown'}`);
// Mustache構文を検出するための正規表現パターン
const mustachePattern = /^\s*{{\s*(.*?)\s*}}\s*$/;
// childrenが配列でない場合、content直接チェック (インラインテキスト対応)
if (node.content) {
const content = node.content.trim();
console.log(`Direct node content found: ${content}`);
// Mustache構文のチェック
const mustacheMatch = content.match(mustachePattern);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
const extractedContent = mustacheMatch[1].trim();
console.log(`Extracted i18n reference from mustache: ${extractedContent}`);
return extractedContent;
}
// 直接i18n参照を含む場合
if (content.includes('i18n.ts.')) {
console.log(`Direct i18n reference found: ${content}`);
return content;
}
// その他のコンテンツ
if (content) {
return content;
}
}
// childrenがない場合は終了
if (!node.children || !Array.isArray(node.children)) {
return null;
}
// Mustacheテンプレート構文の特殊ード検出 (type=5はインターポレーション)
for (const child of node.children) {
if (child.type === 5) { // インターポレーションノード (Mustache表現)
console.log(`Found interpolation node (Mustache): `, child);
if (child.content && child.content.type === 4 && child.content.content) {
const content = child.content.content.trim();
console.log(`Interpolation content: ${content}`);
if (content.includes('i18n.ts.')) {
return content;
}
} else if (child.content && typeof child.content === 'object') {
// オブジェクト形式のcontentを再帰的に探索
console.log(`Complex interpolation node:`, JSON.stringify(child.content).substring(0, 100));
if (child.content.content) {
const content = child.content.content.trim();
if (content.includes('i18n.ts.')) {
console.log(`Found i18n reference in complex interpolation: ${content}`);
return content;
}
}
}
}
}
// 最初のパスで i18n.ts. 参照パターンを持つものを探す (最優先)
for (const child of node.children) {
if (child.type === 2 && child.content) { // 式ノード
const expr = child.content.trim();
if (expr.includes('i18n.ts.')) {
console.log(`Found i18n reference in expression node: ${expr}`);
return expr; // i18n参照を見つけたら即座に返す
}
}
}
// 2回目のパスで一般的な式を探す
for (const child of node.children) {
if (child.type === 2 && child.content) { // その他の式ノード
const expr = child.content.trim();
console.log(`Found expression: ${expr}`);
return expr;
}
}
// 3回目のパスでテキストードを探す
for (const child of node.children) {
if (child.type === 3 && child.content) { // テキストノード
const text = child.content.trim();
if (text) {
console.log(`Found text node: ${text}`);
// Mustache構文のチェック
const mustacheMatch = text.match(mustachePattern);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
console.log(`Extracted i18n ref from text mustache: ${mustacheMatch[1]}`);
return mustacheMatch[1].trim();
}
return text;
}
}
}
// 深さ優先で再帰的に探索 (子の子まで調べる)
for (const child of node.children) {
if (child.children && Array.isArray(child.children) && child.children.length > 0) {
const nestedContent = extractElementText(child);
if (nestedContent) {
console.log(`Found nested content: ${nestedContent}`);
return nestedContent;
}
} else if (child.type === 1) { // 子要素ノード - childrenがなくても内部を調査
const nestedContent = extractElementText(child);
if (nestedContent) {
console.log(`Found content in childless element: ${nestedContent}`);
return nestedContent;
}
}
}
return null;
}
// SearchLabelとSearchKeywordを探して抽出する関数 (スコープを適切に分離)
function extractLabelsAndKeywords(nodes: any[]): { label: string | null, keywords: any[] } {
let label: string | null = null;
const keywords: any[] = [];
console.log(`Extracting labels and keywords from ${nodes.length} nodes`);
// 再帰的にSearchLabelとSearchKeywordを探索ネストされたSearchMarkerは処理しない
function findComponents(nodes: any[]) {
for (const node of nodes) {
if (node.type === 1) { // Element node
console.log(`Checking element: ${node.tag}`);
// SearchMarkerの場合は、その子要素は別スコープなのでスキップ
if (node.tag === 'SearchMarker') {
console.log(`Found nested SearchMarker - skipping its content to maintain scope isolation`);
continue; // このSearchMarkerの中身は処理しない (スコープ分離)
}
// SearchLabelの処理
if (node.tag === 'SearchLabel') {
console.log(`Found SearchLabel node, structure:`, JSON.stringify(node).substring(0, 200) + '...');
// まず完全なノード内容の抽出を試みる
const content = extractElementText(node);
if (content) {
label = content;
console.log(`SearchLabel content extracted: ${content}`);
} else {
console.log(`SearchLabel found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === 5 && child.content) {
// content内の式を取り出す
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content);
console.log(`Interpolation expression: ${expression}`);
if (typeof expression === 'string' && expression.includes('i18n.ts.')) {
label = expression.trim();
console.log(`Found i18n in interpolation: ${label}`);
break;
}
}
// 式ノード
else if (child.type === 2 && child.content && child.content.includes('i18n.ts.')) {
label = child.content.trim();
console.log(`Found i18n in expression: ${label}`);
break;
}
// テキストードでもMustache構文を探す
else if (child.type === 3 && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
label = mustacheMatch[1].trim();
console.log(`Found i18n in text mustache: ${label}`);
break;
}
}
}
}
}
}
// SearchKeywordの処理
else if (node.tag === 'SearchKeyword') {
console.log(`Found SearchKeyword node`);
// まず完全なノード内容の抽出を試みる
const content = extractElementText(node);
if (content) {
keywords.push(content);
console.log(`SearchKeyword content extracted: ${content}`);
} else {
console.log(`SearchKeyword found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === 5 && child.content) {
// content内の式を取り出す
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content);
console.log(`Keyword interpolation: ${expression}`);
if (typeof expression === 'string' && expression.includes('i18n.ts.')) {
const keyword = expression.trim();
keywords.push(keyword);
console.log(`Found i18n keyword in interpolation: ${keyword}`);
break;
}
}
// 式ノード
else if (child.type === 2 && child.content && child.content.includes('i18n.ts.')) {
const keyword = child.content.trim();
keywords.push(keyword);
console.log(`Found i18n keyword in expression: ${keyword}`);
break;
}
// テキストードでもMustache構文を探す
else if (child.type === 3 && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
const keyword = mustacheMatch[1].trim();
keywords.push(keyword);
console.log(`Found i18n keyword in text mustache: ${keyword}`);
break;
}
}
}
}
}
}
// 子要素を再帰的に調査ただしSearchMarkerは除外
if (node.children && Array.isArray(node.children)) {
findComponents(node.children);
}
}
}
}
findComponents(nodes);
// デバッグ情報
console.log(`Extraction completed: label=${label}, keywords=[${keywords.join(', ')}]`);
return { label, keywords };
}
function extractUsageInfoFromTemplateAst(
templateAst: any,
code: string,
): SearchIndexItem[] {
// すべてのマーカー情報を保持するために、結果をトップレベルマーカー+すべての子マーカーを含む配列に変更
const allMarkers: SearchIndexItem[] = [];
// マーカーIDからオブジェクトへのマップ
const markerMap = new Map<string, SearchIndexItem>();
// 子マーカーIDを集約するためのセット
const childrenIds = new Set<string>();
if (!templateAst) {
return allMarkers;
}
// デバッグ情報
logger.info('Started extracting markers from AST');
if (!templateAst) return allMarkers;
// マーカーの基本情報を収集
function collectMarkers(node: any, parentId: string | null = null) {
// SearchMarkerコンポーネントの検出
if (node.type === 1 && node.tag === 'SearchMarker') {
// マーカーID生成 (markerId属性またはDOM内に記録されているものを使用)
// マーカーID取得
const markerIdProp = node.props?.find((p: any) => p.name === 'markerId');
const markerId = markerIdProp?.value?.content ||
node.__markerId ||
`marker-${Math.random().toString(36).substring(2, 10)}`;
logger.info(`Found SearchMarker with ID: ${markerId}`);
node.__markerId ||
`marker-${Math.random().toString(36).substring(2, 10)}`;
// マーカー基本情報
const markerInfo: SearchIndexItem = {
id: markerId,
children: [],
label: '',
label: '', // デフォルト値
keywords: [],
};
// 静的プロパティを抽出
// 静的プロパティを取得
if (node.props && Array.isArray(node.props)) {
node.props.forEach((prop: any) => {
for (const prop of node.props) {
if (prop.type === 6 && prop.name && prop.name !== 'markerId') {
// 静的プロパティの抽出
if (prop.name === 'path') markerInfo.path = prop.value?.content || '';
else if (prop.name === 'icon') markerInfo.icon = prop.value?.content || '';
else if (prop.name === 'label') markerInfo.label = prop.value?.content || '';
logger.info(`Static prop ${prop.name}:`, prop.value?.content);
}
});
}
}
// バインドプロパティを抽出
if (node.props && Array.isArray(node.props)) {
node.props.forEach((prop: any) => {
if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) {
const propName = prop.arg.content;
const propValue = prop.exp?.content || '';
// バインドプロパティを取得
const bindings = extractNodeBindings(node);
if (bindings.path) markerInfo.path = bindings.path;
if (bindings.icon) markerInfo.icon = bindings.icon;
if (bindings.label) markerInfo.label = bindings.label;
if (bindings.children) markerInfo.children = bindings.children;
if (bindings.keywords) {
if (Array.isArray(bindings.keywords)) {
markerInfo.keywords = bindings.keywords;
} else {
markerInfo.keywords = bindings.keywords || [];
}
}
logger.info(`Bind prop ${propName}:`, propValue);
// SearchLabelとSearchKeywordを抽出 (AST全体を探索)
if (node.children && Array.isArray(node.children)) {
console.log(`Processing marker ${markerId} for labels and keywords`);
const extracted = extractLabelsAndKeywords(node.children);
if (propName === 'label') {
markerInfo.label = propValue;
} else if (propName === 'path') {
markerInfo.path = propValue;
} else if (propName === 'icon') {
markerInfo.icon = propValue;
} else if (propName === 'keywords') {
markerInfo.keywords = propValue || '[]';
} else if (propName === 'children') {
markerInfo.children = propValue || '[]';
}
// SearchLabelからのラベル取得は最優先で適用
if (extracted.label) {
markerInfo.label = extracted.label;
console.log(`Using extracted label for ${markerId}: ${extracted.label}`);
} else if (markerInfo.label) {
console.log(`Using existing label for ${markerId}: ${markerInfo.label}`);
} else {
markerInfo.label = 'Unnamed marker';
console.log(`No label found for ${markerId}, using default`);
}
// SearchKeywordからのキーワード取得を追加
if (extracted.keywords.length > 0) {
const existingKeywords = Array.isArray(markerInfo.keywords) ?
[...markerInfo.keywords] :
(markerInfo.keywords ? [markerInfo.keywords] : []);
// i18n参照のキーワードは最優先で追加
const combinedKeywords = [...existingKeywords];
for (const kw of extracted.keywords) {
combinedKeywords.push(kw);
console.log(`Added extracted keyword to ${markerId}: ${kw}`);
}
});
markerInfo.keywords = combinedKeywords;
}
}
// ラベルがない場合はデフォルト値を設定
if (!markerInfo.label) {
markerInfo.label = 'Unnamed marker';
}
// キーワードがない場合はデフォルト値を設定
if (!markerInfo.keywords || (Array.isArray(markerInfo.keywords) && markerInfo.keywords.length === 0)) {
markerInfo.keywords = '[]';
}
// マーカーをマップに保存し、すべてのマーカーリストにも追加
// マーカーを登録
markerMap.set(markerId, markerInfo);
allMarkers.push(markerInfo); // すべてのマーカーを保持
allMarkers.push(markerInfo);
// 親子関係を記録
if (parentId) {
@ -395,11 +687,10 @@ function extractUsageInfoFromTemplateAst(
parent.children = [markerId];
}
childrenIds.add(markerId);
logger.info(`Added ${markerId} as child of ${parentId}`);
}
}
// 子ノードを処理(親は現在のノード)
// 子ノードを処理
if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: any) => {
collectMarkers(child, markerId);
@ -409,7 +700,7 @@ function extractUsageInfoFromTemplateAst(
return markerId;
}
// SearchMarkerでない場合は、子ノードを同じ親コンテキストで処理
// 子ノードを処理
if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: any) => {
collectMarkers(child, parentId);
@ -419,16 +710,169 @@ function extractUsageInfoFromTemplateAst(
return null;
}
// AST解析開始
// AST解析開始
collectMarkers(templateAst);
// デバッグ情報
logger.info(`Found ${markerMap.size} markers, ${childrenIds.size} children`);
// 重要: すべてのマーカー情報を返す
return allMarkers;
}
// バインドプロパティの処理を修正する関数
function extractNodeBindings(node: any): Record<string, any> {
const bindings: Record<string, any> = {};
if (!node.props || !Array.isArray(node.props)) return bindings;
// バインド式を収集
for (const prop of node.props) {
if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) {
const propName = prop.arg.content;
const propContent = prop.exp?.content || '';
logger.info(`Processing bind prop ${propName}: ${propContent}`);
// keywordsの特殊処理
if (propName === 'keywords') {
try {
const content = propContent.trim();
// 配列式の場合
if (content.startsWith('[') && content.endsWith(']')) {
// i18n参照や特殊な式を保持するため、各要素を個別に解析
const elements = parseArrayExpression(content);
if (elements.length > 0) {
bindings.keywords = elements;
logger.info(`Parsed keywords array: ${JSON5.stringify(elements)}`);
} else {
bindings.keywords = [];
logger.info('Empty keywords array');
}
}
// その他の式(非配列)
else if (content) {
bindings.keywords = content; // 式をそのまま保持
logger.info(`Keeping keywords as expression: ${content}`);
} else {
bindings.keywords = [];
logger.info('No keywords provided');
}
} catch (e) {
logger.error(`Failed to parse keywords binding: ${propContent}`, e);
// エラーが起きても何らかの値を設定
bindings.keywords = propContent || [];
}
}
// その他のプロパティ
else if (propName === 'label') {
// ラベルの場合も式として保持
bindings[propName] = propContent;
logger.info(`Set label from bind expression: ${propContent}`);
}
else {
bindings[propName] = propContent;
}
}
}
return bindings;
}
// 配列式をパースする補助関数(文字列リテラル処理を改善)
function parseArrayExpression(expr: string): any[] {
try {
// 単純なケースはJSON5でパースを試みる
return JSON5.parse(expr.replace(/'/g, '"'));
} catch (e) {
// 複雑なケースi18n.ts.xxx などの式を含む場合)は手動パース
logger.info(`Complex array expression, trying manual parsing: ${expr}`);
// "["と"]"を取り除く
const content = expr.substring(1, expr.length - 1).trim();
if (!content) return [];
const result: any[] = [];
let currentItem = '';
let depth = 0;
let inString = false;
let stringChar = '';
// カンマで区切る(ただし文字列内や入れ子の配列内のカンマは無視)
for (let i = 0; i < content.length; i++) {
const char = content[i];
if (inString) {
if (char === stringChar && content[i - 1] !== '\\') {
inString = false;
}
currentItem += char;
} else if (char === '"' || char === "'") {
inString = true;
stringChar = char;
currentItem += char;
} else if (char === '[') {
depth++;
currentItem += char;
} else if (char === ']') {
depth--;
currentItem += char;
} else if (char === ',' && depth === 0) {
// 項目の区切りを検出
const trimmed = currentItem.trim();
// 純粋な文字列リテラルの場合、実際の値に変換
if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
(trimmed.startsWith('"') && trimmed.endsWith('"'))) {
try {
result.push(JSON5.parse(trimmed));
} catch (err) {
result.push(trimmed);
}
} else {
// それ以外の式はそのままi18n.ts.xxx など)
result.push(trimmed);
}
currentItem = '';
} else {
currentItem += char;
}
}
// 最後の項目を処理
if (currentItem.trim()) {
const trimmed = currentItem.trim();
// 純粋な文字列リテラルの場合、実際の値に変換
if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
(trimmed.startsWith('"') && trimmed.endsWith('"'))) {
try {
result.push(JSON5.parse(trimmed));
} catch (err) {
result.push(trimmed);
}
} else {
// それ以外の式はそのままi18n.ts.xxx など)
result.push(trimmed);
}
}
logger.info(`Parsed complex array expression: ${expr} -> ${JSON.stringify(result)}`);
return result;
}
}
// 配列式の文字列表現を修正 - i18n参照を適切に処理
function formatArrayForOutput(items: any[]): string {
return items.map(item => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力
if (typeof item === 'string' && item.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in array: ${item}`);
return item; // クォートなしでそのまま
}
// その他の値はJSON5形式で文字列化
return JSON5.stringify(item);
}).join(', ');
}
export async function analyzeVueProps(options: {
targetFilePaths: string[],
exportFilePath: string,
@ -466,7 +910,7 @@ export async function analyzeVueProps(options: {
});
if (errors.length) {
logger.error(`Compile Error: ${filePath}`, errors);
logger.error(`Compile Error: ${filePath}, ${errors}`);
continue; // エラーが発生したファイルはスキップ
}
@ -578,7 +1022,7 @@ async function processVueFile(
s.appendRight(endOfStartTag, ` markerId="${generatedMarkerId}"`);
logger.info(`Adding markerId="${generatedMarkerId}" to ${id}:${lineNumber}`);
} else {
logger.warn(`markerId already exists in ${id}:${lineNumber}`);
logger.info(`markerId already exists in ${id}:${lineNumber}`);
}
}
}

View File

@ -0,0 +1,14 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<slot></slot>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" module>
</style>

View File

@ -0,0 +1,14 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<slot></slot>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" module>
</style>

View File

@ -25,6 +25,9 @@ import MkFooterSpacer from './global/MkFooterSpacer.vue';
import MkStickyContainer from './global/MkStickyContainer.vue';
import MkLazy from './global/MkLazy.vue';
import SearchMarker from './global/SearchMarker.vue';
import SearchLabel from './global/SearchLabel.vue';
import SearchKeyword from './global/SearchKeyword.vue';
import type { App } from 'vue';
export default function(app: App) {
@ -56,6 +59,8 @@ export const components = {
MkStickyContainer: MkStickyContainer,
MkLazy: MkLazy,
SearchMarker: SearchMarker,
SearchLabel: SearchLabel,
SearchKeyword: SearchKeyword,
};
declare module '@vue/runtime-core' {
@ -82,5 +87,7 @@ declare module '@vue/runtime-core' {
MkStickyContainer: typeof MkStickyContainer;
MkLazy: typeof MkLazy;
SearchMarker: typeof SearchMarker;
SearchLabel: typeof SearchLabel;
SearchKeyword: typeof SearchKeyword;
}
}

View File

@ -73,12 +73,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker
:label="i18n.ts.collapseRenotes"
:keywords="['renote', i18n.ts.collapseRenotesDescription]"
:keywords="['renote']"
>
<MkSwitch v-model="collapseRenotes">
<template #label>{{ i18n.ts.collapseRenotes }}</template>
<template #caption>{{ i18n.ts.collapseRenotesDescription }}</template>
<template #label><SearchLabel>{{ i18n.ts.collapseRenotes }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.collapseRenotesDescription }}</SearchKeyword></template>
</MkSwitch>
</SearchMarker>

View File

@ -7,8 +7,6 @@
// This file was automatically generated by create-search-index.
// Do not edit this file.
/* eslint-disable @stylistic/comma-spacing */
import { i18n } from '@/i18n.js';
export type SearchIndexItem = {
@ -32,22 +30,22 @@ export const searchIndexes:SearchIndexItem[] = [
{
id: 'gAvOWkPnm',
label: i18n.ts._profile.description,
keywords: ['description','bio'],
keywords: ['description', 'bio'],
},
{
id: 'jDQ9ug9JI',
label: i18n.ts.location,
keywords: ['location','locale'],
keywords: ['location', 'locale'],
},
{
id: '4IINpCs7w',
label: i18n.ts.birthday,
keywords: ['birthday','birthdate','age'],
keywords: ['birthday', 'birthdate', 'age'],
},
{
id: 'nrKSnXwYN',
label: i18n.ts.language,
keywords: ['language','locale'],
keywords: ['language', 'locale'],
},
{
id: 'xpFKUEupm',
@ -98,7 +96,7 @@ export const searchIndexes:SearchIndexItem[] = [
{
id: 'yGVh4afrC',
label: i18n.ts.autoAcceptFollowed,
keywords: ['follow','auto','accept'],
keywords: ['follow', 'auto', 'accept'],
},
{
id: 'vomfIAjG2',
@ -108,12 +106,12 @@ export const searchIndexes:SearchIndexItem[] = [
{
id: 'BakhCOlGl',
label: i18n.ts.followingVisibility,
keywords: ['following','visibility'],
keywords: ['following', 'visibility'],
},
{
id: 'nALctPZes',
label: i18n.ts.followersVisibility,
keywords: ['follower','visibility'],
keywords: ['follower', 'visibility'],
},
{
id: 'g39hgvANq',
@ -160,17 +158,17 @@ export const searchIndexes:SearchIndexItem[] = [
{
id: '6AAT3LUIL',
label: i18n.ts.rememberNoteVisibility,
keywords: ['remember','keep','note','visibility'],
keywords: ['remember', 'keep', 'note', 'visibility'],
},
{
id: '8d0FCNIgm',
label: i18n.ts.defaultNoteVisibility,
keywords: ['default','note','visibility'],
keywords: ['default', 'note', 'visibility'],
},
{
id: 'o3hisYwlV',
label: i18n.ts.keepCw,
keywords: ['remember','keep','note','cw'],
keywords: ['remember', 'keep', 'note', 'cw'],
},
],
label: i18n.ts.privacy,
@ -191,36 +189,36 @@ export const searchIndexes:SearchIndexItem[] = [
},
],
label: i18n.ts.wordMute,
keywords: ['note','word','soft','mute','hide'],
keywords: ['note', 'word', 'soft', 'mute', 'hide'],
},
{
id: 'evlmsuKtu',
label: i18n.ts.hardWordMute,
keywords: ['note','word','hard','mute','hide'],
keywords: ['note', 'word', 'hard', 'mute', 'hide'],
},
{
id: 'zLHWO9mBm',
label: i18n.ts.instanceMute,
keywords: ['note','server','instance','host','federation','mute','hide'],
keywords: ['note', 'server', 'instance', 'host', 'federation', 'mute', 'hide'],
},
{
id: 's3IxYcSKj',
label: `${i18n.ts.mutedUsers} (${ i18n.ts.renote })`,
keywords: ['renote','mute','hide','user'],
keywords: ['renote', 'mute', 'hide', 'user'],
},
{
id: 'iBnGIbcys',
label: i18n.ts.mutedUsers,
keywords: ['note','mute','hide','user'],
keywords: ['note', 'mute', 'hide', 'user'],
},
{
id: 'g6aGcN8X5',
label: i18n.ts.blockedUsers,
keywords: ['block','user'],
keywords: ['block', 'user'],
},
],
label: i18n.ts.muteAndBlock,
keywords: ['mute','block'],
keywords: ['mute', 'block'],
path: '/settings/mute-block',
icon: 'ti ti-ban',
},
@ -235,22 +233,22 @@ export const searchIndexes:SearchIndexItem[] = [
{
id: '3zpvHzV5g',
label: i18n.ts.overridedDeviceKind,
keywords: ['device','type','kind','smartphone','tablet','desktop'],
keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
},
{
id: '1QvSeZtNe',
label: i18n.ts.showFixedPostForm,
keywords: ['post','form','timeline'],
keywords: ['post', 'form', 'timeline'],
},
{
id: 'oVjAZ97m1',
label: i18n.ts.showFixedPostFormInChannel,
keywords: ['post','form','timeline','channel'],
keywords: ['post', 'form', 'timeline', 'channel'],
},
{
id: '6sIzeMWoB',
label: i18n.ts.pinnedList,
keywords: ['pinned','list'],
keywords: ['pinned', 'list'],
},
{
id: '6HbFzMsfZ',
@ -261,238 +259,238 @@ export const searchIndexes:SearchIndexItem[] = [
keywords: ['renote', i18n.ts.collapseRenotesDescription],
},
{
id: 'r8RoaDGyB',
id: 'ge9OZWVVN',
label: i18n.ts.showNoteActionsOnlyHover,
keywords: ['hover','show','footer','action'],
keywords: ['hover', 'show', 'footer', 'action'],
},
{
id: 'dhe5ltCVy',
id: 'qkpSLdjU0',
label: i18n.ts.showClipButtonInNoteFooter,
keywords: ['footer','action','clip','show'],
keywords: ['footer', 'action', 'clip', 'show'],
},
{
id: 'lJijzarvh',
id: 'A3lCFvhIW',
label: i18n.ts.enableAdvancedMfm,
keywords: ['mfm','enable','show','advanced'],
keywords: ['mfm', 'enable', 'show', 'advanced'],
},
{
id: 'plFY7Zr0Y',
id: 'AhvTBCdWA',
label: i18n.ts.enableAnimatedMfm,
keywords: ['mfm','enable','show','animated'],
keywords: ['mfm', 'enable', 'show', 'animated'],
},
{
id: 'uCWeJdWGo',
id: 'hsXMJyRt9',
label: i18n.ts.enableQuickAddMfmFunction,
keywords: ['mfm','enable','show','advanced','picker','form','function','fn'],
keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
},
{
id: 'jojGm1s0T',
id: 'caZ2i1vUp',
label: i18n.ts.showReactionsCount,
keywords: ['reaction','count','show'],
keywords: ['reaction', 'count', 'show'],
},
{
id: 'gob3LGyDO',
id: 'zeBSHyLvX',
label: i18n.ts.showGapBetweenNotesInTimeline,
keywords: ['note','timeline','gap'],
keywords: ['note', 'timeline', 'gap'],
},
{
id: 'v5IaTjjUK',
id: 'iCXH6Slng',
label: i18n.ts.loadRawImages,
keywords: ['image','photo','picture','media','thumbnail','quality','raw','attachment'],
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'],
},
{
id: '9rlymuz2e',
id: 'dLhN3FVue',
label: i18n.ts.reactionsDisplaySize,
keywords: ['reaction','size','scale','display'],
keywords: ['reaction', 'size', 'scale', 'display'],
},
{
id: 'a6JkO6iHN',
id: 'vmlTGQcw9',
label: i18n.ts.limitWidthOfReaction,
keywords: ['reaction','size','scale','display','width','limit'],
keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
},
{
id: 'B2C8Chpn3',
id: 'urTAUjuCD',
label: i18n.ts.instanceTicker,
keywords: ['ticker','information','label','instance','server','host','federation'],
keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
},
{
id: 'lXGQcJA0m',
id: 'jEMNPc04n',
label: i18n.ts.displayOfSensitiveMedia,
keywords: ['attachment','image','photo','picture','media','thumbnail','nsfw','sensitive','display','show','hide','visibility'],
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
},
{
id: 'fI9unfBG9',
id: 'dbVdQ8uQ6',
label: i18n.ts.mediaListWithOneImageAppearance,
keywords: ['attachment','image','photo','picture','media','thumbnail','list','size','height'],
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
},
],
label: i18n.ts.displayOfNote,
keywords: ['note','display'],
keywords: ['note', 'display'],
},
{
id: 'ksPnvPfsq',
id: 'reaXNqM8S',
children: [
{
id: 'rlKh8qQSy',
id: 'x5ekE7znD',
label: i18n.ts.useGroupedNotifications,
keywords: ['group'],
},
{
id: 'mZoLcRxn9',
id: 'iUWlBX9ZI',
label: i18n.ts.position,
keywords: ['position'],
},
{
id: 'mu8Fghr9P',
id: 'vrBikwOLp',
label: i18n.ts.stackAxis,
keywords: ['stack','axis','direction'],
keywords: ['stack', 'axis', 'direction'],
},
],
label: i18n.ts.notificationDisplay,
keywords: ['notification','display'],
keywords: ['notification', 'display'],
},
{
id: 'sUAe1tYeV',
id: 'ufhXubmEr',
children: [
{
id: 'pXk2Bq5c7',
id: 'fgl7X4XsD',
label: i18n.ts.reduceUiAnimation,
keywords: ['animation','motion','reduce'],
keywords: ['animation', 'motion', 'reduce'],
},
{
id: 'l92lxxESG',
id: 'bjKigdnsy',
label: i18n.ts.useBlurEffect,
keywords: ['blur'],
},
{
id: '5fw6zkK39',
id: 'CGoeiZtv2',
label: i18n.ts.useBlurEffectForModal,
keywords: ['blur','modal'],
keywords: ['blur', 'modal'],
},
{
id: 'm3kpvUE3f',
id: 'bnzqN2Uv5',
label: i18n.ts.disableShowingAnimatedImages,
keywords: ['disable','animation','image','photo','picture','media','thumbnail','gif'],
keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'],
},
{
id: 'EEHGMwhkC',
id: '9LEabU98l',
label: i18n.ts.highlightSensitiveMedia,
keywords: ['highlight','sensitive','nsfw','image','photo','picture','media','thumbnail'],
keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
},
{
id: 'hBnm0B8aI',
id: 'aiKchQcTg',
label: i18n.ts.squareAvatars,
keywords: ['avatar','icon','square'],
keywords: ['avatar', 'icon', 'square'],
},
{
id: 'm9Q5z11L8',
id: '370ytj4BG',
label: i18n.ts.showAvatarDecorations,
keywords: ['avatar','icon','decoration','show'],
keywords: ['avatar', 'icon', 'decoration', 'show'],
},
{
id: 'pHvwcwF4c',
id: 'sNxpyIsU0',
label: i18n.ts.useSystemFont,
keywords: ['font','system','native'],
keywords: ['font', 'system', 'native'],
},
{
id: '3lcbrBHYZ',
id: 'lNM8JR8Fq',
label: i18n.ts.forceShowAds,
keywords: ['ad','show'],
keywords: ['ad', 'show'],
},
{
id: '523Bx87JU',
id: 'rDKuKXq3L',
label: i18n.ts.seasonalScreenEffect,
keywords: ['effect','show'],
keywords: ['effect', 'show'],
},
{
id: '7dFSaWz4u',
id: 'eTBtusX71',
label: i18n.ts.useNativeUIForVideoAudioPlayer,
keywords: ['native','system','video','audio','player','media'],
keywords: ['native', 'system', 'video', 'audio', 'player', 'media'],
},
{
id: 'q3Vv5zIZu',
id: 'c2IIsJe2s',
label: i18n.ts.menuStyle,
keywords: ['menu','style','popup','drawer'],
keywords: ['menu', 'style', 'popup', 'drawer'],
},
{
id: 'd1Gno6GaT',
id: 'zeg5SUJfO',
label: i18n.ts.emojiStyle,
keywords: ['emoji','style','native','system','fluent','twemoji'],
keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
},
{
id: '3sV67CRuN',
id: 'dSCrbhyrx',
label: i18n.ts.fontSize,
keywords: ['font','size'],
keywords: ['font', 'size'],
},
],
label: i18n.ts.appearance,
keywords: ['appearance'],
},
{
id: 'AOASYDlhv',
id: 'onFBs0tYX',
children: [
{
id: 'rwvOv068t',
id: 'gmuZO8DML',
label: i18n.ts.openImageInNewTab,
keywords: ['image','photo','picture','media','thumbnail','new','tab'],
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
},
{
id: '1XB7XWwbI',
id: '5pZfWlbB2',
label: i18n.ts.useReactionPickerForContextMenu,
keywords: ['reaction','picker','contextmenu','open'],
keywords: ['reaction', 'picker', 'contextmenu', 'open'],
},
{
id: '4fjitJYAl',
id: 'pihxkFGES',
label: i18n.ts.enableInfiniteScroll,
keywords: ['load','auto','more'],
keywords: ['load', 'auto', 'more'],
},
{
id: 'f2Nk4GdTa',
id: '1QcQVuU3X',
label: i18n.ts.keepScreenOn,
keywords: ['keep','screen','display','on'],
keywords: ['keep', 'screen', 'display', 'on'],
},
{
id: '3D54jQsGn',
id: 'DPsw4YfoC',
label: i18n.ts.disableStreamingTimeline,
keywords: ['disable','streaming','timeline'],
keywords: ['disable', 'streaming', 'timeline'],
},
{
id: '6MKp7i7iH',
id: 'nXcDddZr9',
label: i18n.ts.enableHorizontalSwipe,
keywords: ['swipe','horizontal','tab'],
keywords: ['swipe', 'horizontal', 'tab'],
},
{
id: 'eSvGS9DsY',
id: 'sq5mQo7Th',
label: i18n.ts.alwaysConfirmFollow,
keywords: ['follow','confirm','always'],
keywords: ['follow', 'confirm', 'always'],
},
{
id: 'kGYY8LCdK',
id: '9IuNcZ9Ct',
label: i18n.ts.confirmWhenRevealingSensitiveMedia,
keywords: ['sensitive','nsfw','media','image','photo','picture','attachment','confirm'],
keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
},
{
id: 'fdOu3BDKL',
id: '4BhdUdrlf',
label: i18n.ts.confirmOnReact,
keywords: ['reaction','confirm'],
keywords: ['reaction', 'confirm'],
},
{
id: 'isbDLeTjm',
id: 'qqA6jS0Fy',
label: i18n.ts.whenServerDisconnected,
keywords: ['server','disconnect','reconnect','reload','streaming'],
keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
},
{
id: 'F5werzQkF',
id: 'EPnMDBcWn',
label: i18n.ts._contextMenu.title,
keywords: ['contextmenu','system','native'],
keywords: ['contextmenu', 'system', 'native'],
},
{
id: 'CPNGOZAoV',
id: 'iHo9Udj7J',
label: i18n.ts.numberOfPageCache,
keywords: ['cache','page'],
keywords: ['cache', 'page'],
},
{
id: '5XHiLyaol',
id: '8KHaBRiOz',
label: i18n.ts.dataSaver,
keywords: ['datasaver'],
},
@ -508,5 +506,3 @@ export const searchIndexes:SearchIndexItem[] = [
] as const;
export type SearchIndex = typeof searchIndexes;
/* eslint-enable @stylistic/comma-spacing */