fix: unnecesary HMR when we opened setting page (#15756)

* refactor: add MarkerIdAssigner instead of processVueFile and remove transformedCodeCache object

* chore: add minimatch, a glob matcher

* chore: expose MarkerIdAssigner from plugin

* Revert "chore: expose MarkerIdAssigner from plugin"

This reverts commit 88c6d820f8.

* chore: add plugin to generate virtual module

* chore: parse inlining earlier

* chore: use virtual module in search

* chore: use remove old generation

* chore: fix type errors

* chore: add patch to workaround vitejs/vite#19792

* chore: improve filtering files to process

* chore: rename plugin

* docs: add comment for plugin ordering

* fix: unnecessary log

* fix: spdx license header
This commit is contained in:
anatawa12 2025-04-05 08:46:17 +09:00 committed by GitHub
parent ea9d85a0cc
commit 5949bb6c7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 447 additions and 1382 deletions

View File

@ -24,7 +24,6 @@
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets", "build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"build-storybook": "pnpm --filter frontend build-storybook", "build-storybook": "pnpm --filter frontend build-storybook",
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
"build-frontend-search-index": "pnpm --filter frontend build-search-index",
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", "start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"init": "pnpm migrate", "init": "pnpm migrate",
@ -85,7 +84,8 @@
"@aiscript-dev/aiscript-languageserver": "-" "@aiscript-dev/aiscript-languageserver": "-"
}, },
"patchedDependencies": { "patchedDependencies": {
"re2": "scripts/dependency-patches/re2.patch" "re2": "scripts/dependency-patches/re2.patch",
"vite": "scripts/dependency-patches/vite.patch"
} }
} }
} }

View File

@ -4,77 +4,68 @@
*/ */
import { parse as vueSfcParse } from 'vue/compiler-sfc'; import { parse as vueSfcParse } from 'vue/compiler-sfc';
import type { LogOptions, Plugin } from 'vite'; import {
createLogger,
EnvironmentModuleGraph,
normalizePath,
type LogErrorOptions,
type LogOptions,
type Plugin,
type PluginOption
} from 'vite';
import fs from 'node:fs'; import fs from 'node:fs';
import { glob } from 'glob'; import { glob } from 'glob';
import JSON5 from 'json5'; import JSON5 from 'json5';
import MagicString from 'magic-string'; import MagicString, { SourceMap } from 'magic-string';
import path from 'node:path' import path from 'node:path'
import { hash, toBase62 } from '../vite.config'; import { hash, toBase62 } from '../vite.config';
import { createLogger } from 'vite'; import { minimatch } from 'minimatch';
import type {
AttributeNode, CompoundExpressionNode, DirectiveNode,
ElementNode,
RootNode, SimpleExpressionNode,
TemplateChildNode,
} from '@vue/compiler-core';
import { NodeTypes } from '@vue/compiler-core';
interface VueAstNode { export type AnalysisResult<T = SearchIndexItem> = {
type: number;
tag?: string;
loc?: {
start: { offset: number, line: number, column: number },
end: { offset: number, line: number, column: number },
source?: string
};
props?: Array<{
name: string;
type: number;
value?: { content?: string };
arg?: { content?: string };
exp?: { content?: string; loc?: any };
}>;
children?: VueAstNode[];
content?: any;
__markerId?: string;
__children?: string[];
}
export type AnalysisResult = {
filePath: string; filePath: string;
usage: SearchIndexItem[]; usage: T[];
} }
export type SearchIndexItem = { export type SearchIndexItem = SearchIndexItemLink<SearchIndexItem>;
export type SearchIndexStringItem = SearchIndexItemLink<string>;
export interface SearchIndexItemLink<T> {
id: string; id: string;
path?: string; path?: string;
label: string; label: string;
keywords: string | string[]; keywords: string | string[];
icon?: string; icon?: string;
inlining?: string[]; inlining?: string[];
children?: SearchIndexItem[]; children?: T[];
}; }
export type Options = { export type Options = {
targetFilePaths: string[], targetFilePaths: string[],
exportFilePath: string, mainVirtualModule: string,
modulesToHmrOnUpdate: string[],
fileVirtualModulePrefix?: string,
fileVirtualModuleSuffix?: string,
verbose?: boolean, verbose?: boolean,
}; };
// 関連するノードタイプの定数化
const NODE_TYPES = {
ELEMENT: 1,
EXPRESSION: 2,
TEXT: 3,
INTERPOLATION: 5, // Mustache
};
// マーカー関係を表す型 // マーカー関係を表す型
interface MarkerRelation { interface MarkerRelation {
parentId?: string; parentId?: string;
markerId: string; markerId: string;
node: VueAstNode; node: ElementNode;
} }
// ロガー // ロガー
let logger = { let logger = {
info: (msg: string, options?: LogOptions) => { }, info: (msg: string, options?: LogOptions) => { },
warn: (msg: string, options?: LogOptions) => { }, warn: (msg: string, options?: LogOptions) => { },
error: (msg: string, options?: LogOptions) => { }, error: (msg: string, options?: LogErrorOptions) => { },
}; };
let loggerInitialized = false; let loggerInitialized = false;
@ -99,14 +90,11 @@ function initLogger(options: Options) {
} }
} }
/** function collectSearchItemIndexes(analysisResults: AnalysisResult<SearchIndexStringItem>[]): SearchIndexItem[] {
* TypeScriptファイルとして出力する
*/
function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisResult[]): void {
logger.info(`Processing ${analysisResults.length} files for output`); logger.info(`Processing ${analysisResults.length} files for output`);
// 新しいツリー構造を構築 // 新しいツリー構造を構築
const allMarkers = new Map<string, SearchIndexItem>(); const allMarkers = new Map<string, SearchIndexStringItem>();
// 1. すべてのマーカーを一旦フラットに収集 // 1. すべてのマーカーを一旦フラットに収集
for (const file of analysisResults) { for (const file of analysisResults) {
@ -115,10 +103,9 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
for (const marker of file.usage) { for (const marker of file.usage) {
if (marker.id) { if (marker.id) {
// キーワードとchildren処理を共通化 // キーワードとchildren処理を共通化
const processedMarker = { const processedMarker: SearchIndexStringItem = {
...marker, ...marker,
keywords: processMarkerProperty(marker.keywords, 'keywords'), keywords: processMarkerProperty(marker.keywords, 'keywords'),
children: processMarkerProperty(marker.children || [], 'children')
}; };
allMarkers.set(marker.id, processedMarker); allMarkers.set(marker.id, processedMarker);
@ -143,14 +130,13 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
const { totalMarkers, totalChildren } = countMarkers(resolvedRootMarkers); const { totalMarkers, totalChildren } = countMarkers(resolvedRootMarkers);
logger.info(`Total markers in tree: ${totalMarkers} (${resolvedRootMarkers.length} roots + ${totalChildren} nested children)`); logger.info(`Total markers in tree: ${totalMarkers} (${resolvedRootMarkers.length} roots + ${totalChildren} nested children)`);
// 6. 結果をTS形式で出力 return resolvedRootMarkers;
writeOutputFile(outputPath, resolvedRootMarkers);
} }
/** /**
* keywordsやchildren * keywordsやchildren
*/ */
function processMarkerProperty(propValue: any, propType: 'keywords' | 'children'): any { function processMarkerProperty(propValue: string | string[], propType: 'keywords' | 'children'): string | string[] {
// 文字列の配列表現を解析 // 文字列の配列表現を解析
if (typeof propValue === 'string' && propValue.startsWith('[') && propValue.endsWith(']')) { if (typeof propValue === 'string' && propValue.startsWith('[') && propValue.endsWith(']')) {
try { try {
@ -169,7 +155,7 @@ function processMarkerProperty(propValue: any, propType: 'keywords' | 'children'
/** /**
* IDを収集する * IDを収集する
*/ */
function collectChildIds(allMarkers: Map<string, SearchIndexItem>): Set<string> { function collectChildIds(allMarkers: Map<string, SearchIndexStringItem>): Set<string> {
const childIds = new Set<string>(); const childIds = new Set<string>();
allMarkers.forEach((marker, id) => { allMarkers.forEach((marker, id) => {
@ -232,10 +218,10 @@ function collectChildIds(allMarkers: Map<string, SearchIndexItem>): Set<string>
* *
*/ */
function identifyRootMarkers( function identifyRootMarkers(
allMarkers: Map<string, SearchIndexItem>, allMarkers: Map<string, SearchIndexStringItem>,
childIds: Set<string> childIds: Set<string>
): SearchIndexItem[] { ): SearchIndexStringItem[] {
const rootMarkers: SearchIndexItem[] = []; const rootMarkers: SearchIndexStringItem[] = [];
allMarkers.forEach((marker, id) => { allMarkers.forEach((marker, id) => {
if (!childIds.has(id)) { if (!childIds.has(id)) {
@ -251,12 +237,12 @@ function identifyRootMarkers(
* IDから実際のオブジェクトに解決する * IDから実際のオブジェクトに解決する
*/ */
function resolveChildReferences( function resolveChildReferences(
rootMarkers: SearchIndexItem[], rootMarkers: SearchIndexStringItem[],
allMarkers: Map<string, SearchIndexItem> allMarkers: Map<string, SearchIndexStringItem>
): SearchIndexItem[] { ): SearchIndexItem[] {
function resolveChildrenForMarker(marker: SearchIndexItem): SearchIndexItem { function resolveChildrenForMarker(marker: SearchIndexStringItem): SearchIndexItem {
// マーカーのディープコピーを作成 // マーカーのディープコピーを作成
const resolvedMarker = { ...marker }; const resolvedMarker: SearchIndexItem = { ...marker, children: [] };
// 明示的に子マーカー配列を作成 // 明示的に子マーカー配列を作成
const resolvedChildren: SearchIndexItem[] = []; const resolvedChildren: SearchIndexItem[] = [];
@ -351,55 +337,19 @@ function countMarkers(markers: SearchIndexItem[]): { totalMarkers: number, total
return { totalMarkers, totalChildren }; return { totalMarkers, totalChildren };
} }
/**
* TypeScriptファイルを出力
*/
function writeOutputFile(outputPath: string, resolvedRootMarkers: SearchIndexItem[]): void {
try {
const tsOutput = generateTypeScriptCode(resolvedRootMarkers);
fs.writeFileSync(outputPath, tsOutput, 'utf-8');
// 強制的に出力させるためにViteロガーを使わない
console.log(`Successfully wrote search index to ${outputPath} with ${resolvedRootMarkers.length} root entries`);
} catch (error) {
logger.error('[create-search-index]: error writing output: ', error);
}
}
/** /**
* TypeScriptコード生成 * TypeScriptコード生成
*/ */
function generateTypeScriptCode(resolvedRootMarkers: SearchIndexItem[]): string { function generateJavaScriptCode(resolvedRootMarkers: SearchIndexItem[]): string {
return ` return `import { i18n } from '@/i18n.js';\n`
/* + `export const searchIndexes = ${customStringify(resolvedRootMarkers)};\n`;
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
// This file was automatically generated by create-search-index.
// Do not edit this file.
import { i18n } from '@/i18n.js';
export type SearchIndexItem = {
id: string;
path?: string;
label: string;
keywords: string[];
icon?: string;
children?: SearchIndexItem[];
};
export const searchIndexes: SearchIndexItem[] = ${customStringify(resolvedRootMarkers)} as const;
export type SearchIndex = typeof searchIndexes;
`;
} }
/** /**
* *
* i18n参照を保持しつつ適切な形式に変換 * i18n参照を保持しつつ適切な形式に変換
*/ */
function customStringify(obj: any, depth = 0): string { function customStringify(obj: unknown, depth = 0): string {
const INDENT_STR = '\t'; const INDENT_STR = '\t';
// 配列の処理 // 配列の処理
@ -441,7 +391,6 @@ function customStringify(obj: any, depth = 0): string {
.filter(([key, value]) => { .filter(([key, value]) => {
if (value === undefined) return false; if (value === undefined) return false;
if (key === 'children' && Array.isArray(value) && value.length === 0) return false; if (key === 'children' && Array.isArray(value) && value.length === 0) return false;
if (key === 'inlining') return false;
return true; return true;
}) })
// 各プロパティを変換 // 各プロパティを変換
@ -462,7 +411,7 @@ function customStringify(obj: any, depth = 0): string {
/** /**
* *
*/ */
function formatSpecialProperty(key: string, value: any): string { function formatSpecialProperty(key: string, value: unknown): string {
// 値がundefinedの場合は空文字列を返す // 値がundefinedの場合は空文字列を返す
if (value === undefined) { if (value === undefined) {
return '""'; return '""';
@ -499,7 +448,7 @@ function formatSpecialProperty(key: string, value: any): string {
/** /**
* *
*/ */
function formatArrayForOutput(items: any[]): string { function formatArrayForOutput(items: unknown[]): string {
return items.map(item => { return items.map(item => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力 // i18n.ts. 参照の文字列はそのままJavaScript式として出力
if (typeof item === 'string' && isI18nReference(item)) { if (typeof item === 'string' && isI18nReference(item)) {
@ -516,17 +465,18 @@ function formatArrayForOutput(items: any[]): string {
* *
* *
*/ */
function extractElementText(node: VueAstNode): string | null { function extractElementText(node: TemplateChildNode): string | null {
if (!node) return null; if (!node) return null;
if (node.type === NodeTypes.COMPOUND_EXPRESSION) throw new Error("Unexpected COMPOUND_EXPRESSION");
logger.info(`Extracting text from node type=${node.type}, tag=${node.tag || 'unknown'}`); logger.info(`Extracting text from node type=${node.type}, tag=${'tag' in node ? node.tag : 'unknown'}`);
// 1. 直接コンテンツの抽出を試行 // 1. 直接コンテンツの抽出を試行
const directContent = extractDirectContent(node); const directContent = extractDirectContent(node);
if (directContent) return directContent; if (directContent) return directContent;
// 子要素がない場合は終了 // 子要素がない場合は終了
if (!node.children || !Array.isArray(node.children)) { if (!('children' in node) || !Array.isArray(node.children)) {
return null; return null;
} }
@ -548,12 +498,13 @@ function extractElementText(node: VueAstNode): string | null {
/** /**
* *
*/ */
function extractDirectContent(node: VueAstNode): string | null { function extractDirectContent(node: TemplateChildNode): string | null {
if (!node.content) return null; if (!('content' in node)) return null;
if (typeof node.content == 'object' && node.content.type === NodeTypes.COMPOUND_EXPRESSION) throw new Error("Unexpected COMPOUND_EXPRESSION");
const content = typeof node.content === 'string' const content = typeof node.content === 'string' ? node.content.trim()
? node.content.trim() : node.content.type !== NodeTypes.INTERPOLATION ? node.content.content.trim()
: (node.content.content ? node.content.content.trim() : null); : null;
if (!content) return null; if (!content) return null;
@ -582,9 +533,9 @@ function extractDirectContent(node: VueAstNode): string | null {
/** /**
* Mustache * Mustache
*/ */
function extractInterpolationContent(children: VueAstNode[]): string | null { function extractInterpolationContent(children: TemplateChildNode[]): string | null {
for (const child of children) { for (const child of children) {
if (child.type === NODE_TYPES.INTERPOLATION) { if (child.type === NodeTypes.INTERPOLATION) {
logger.info(`Found interpolation node (Mustache): ${JSON.stringify(child.content).substring(0, 100)}...`); logger.info(`Found interpolation node (Mustache): ${JSON.stringify(child.content).substring(0, 100)}...`);
if (child.content && child.content.type === 4 && child.content.content) { if (child.content && child.content.type === 4 && child.content.content) {
@ -595,6 +546,7 @@ function extractInterpolationContent(children: VueAstNode[]): string | null {
return content; return content;
} }
} else if (child.content && typeof child.content === 'object') { } else if (child.content && typeof child.content === 'object') {
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("Unexpected COMPOUND_EXPRESSION");
// オブジェクト形式のcontentを探索 // オブジェクト形式のcontentを探索
logger.info(`Complex interpolation node: ${JSON.stringify(child.content).substring(0, 100)}...`); logger.info(`Complex interpolation node: ${JSON.stringify(child.content).substring(0, 100)}...`);
@ -616,10 +568,10 @@ function extractInterpolationContent(children: VueAstNode[]): string | null {
/** /**
* *
*/ */
function extractExpressionContent(children: VueAstNode[]): string | null { function extractExpressionContent(children: TemplateChildNode[]): string | null {
// i18n.ts. 参照パターンを持つものを優先 // i18n.ts. 参照パターンを持つものを優先
for (const child of children) { for (const child of children) {
if (child.type === NODE_TYPES.EXPRESSION && child.content) { if (child.type === NodeTypes.TEXT && child.content) {
const expr = child.content.trim(); const expr = child.content.trim();
if (isI18nReference(expr)) { if (isI18nReference(expr)) {
@ -631,7 +583,7 @@ function extractExpressionContent(children: VueAstNode[]): string | null {
// その他の式 // その他の式
for (const child of children) { for (const child of children) {
if (child.type === NODE_TYPES.EXPRESSION && child.content) { if (child.type === NodeTypes.TEXT && child.content) {
const expr = child.content.trim(); const expr = child.content.trim();
logger.info(`Found expression: ${expr}`); logger.info(`Found expression: ${expr}`);
return expr; return expr;
@ -644,9 +596,9 @@ function extractExpressionContent(children: VueAstNode[]): string | null {
/** /**
* *
*/ */
function extractTextContent(children: VueAstNode[]): string | null { function extractTextContent(children: TemplateChildNode[]): string | null {
for (const child of children) { for (const child of children) {
if (child.type === NODE_TYPES.TEXT && child.content) { if (child.type === NodeTypes.COMMENT && child.content) {
const text = child.content.trim(); const text = child.content.trim();
if (text) { if (text) {
@ -672,16 +624,16 @@ function extractTextContent(children: VueAstNode[]): string | null {
/** /**
* *
*/ */
function extractNestedContent(children: VueAstNode[]): string | null { function extractNestedContent(children: TemplateChildNode[]): string | null {
for (const child of children) { for (const child of children) {
if (child.children && Array.isArray(child.children) && child.children.length > 0) { if ('children' in child && Array.isArray(child.children) && child.children.length > 0) {
const nestedContent = extractElementText(child); const nestedContent = extractElementText(child);
if (nestedContent) { if (nestedContent) {
logger.info(`Found nested content: ${nestedContent}`); logger.info(`Found nested content: ${nestedContent}`);
return nestedContent; return nestedContent;
} }
} else if (child.type === NODE_TYPES.ELEMENT) { } else if (child.type === NodeTypes.ELEMENT) {
// childrenがなくても内部を調査 // childrenがなくても内部を調査
const nestedContent = extractElementText(child); const nestedContent = extractElementText(child);
@ -699,16 +651,16 @@ function extractNestedContent(children: VueAstNode[]): string | null {
/** /**
* SearchLabelとSearchKeywordを探して抽出する関数 * SearchLabelとSearchKeywordを探して抽出する関数
*/ */
function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null, keywords: any[] } { function extractLabelsAndKeywords(nodes: TemplateChildNode[]): { label: string | null, keywords: string[] } {
let label: string | null = null; let label: string | null = null;
const keywords: any[] = []; const keywords: string[] = [];
logger.info(`Extracting labels and keywords from ${nodes.length} nodes`); logger.info(`Extracting labels and keywords from ${nodes.length} nodes`);
// 再帰的にSearchLabelとSearchKeywordを探索ネストされたSearchMarkerは処理しない // 再帰的にSearchLabelとSearchKeywordを探索ネストされたSearchMarkerは処理しない
function findComponents(nodes: VueAstNode[]) { function findComponents(nodes: TemplateChildNode[]) {
for (const node of nodes) { for (const node of nodes) {
if (node.type === NODE_TYPES.ELEMENT) { if (node.type === NodeTypes.ELEMENT) {
logger.info(`Checking element: ${node.tag}`); logger.info(`Checking element: ${node.tag}`);
// SearchMarkerの場合は、その子要素は別スコープなのでスキップ // SearchMarkerの場合は、その子要素は別スコープなのでスキップ
@ -730,11 +682,12 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
logger.info(`SearchLabel found but extraction failed, trying direct children inspection`); logger.info(`SearchLabel found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認 // バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) { {
for (const child of node.children) { for (const child of node.children) {
// Mustacheインターポレーション // Mustacheインターポレーション
if (child.type === NODE_TYPES.INTERPOLATION && child.content) { if (child.type === NodeTypes.INTERPOLATION && child.content) {
// content内の式を取り出す // content内の式を取り出す
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("unexpected COMPOUND_EXPRESSION");
const expression = child.content.content || const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) || (child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content); JSON.stringify(child.content);
@ -747,13 +700,13 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
} }
} }
// 式ノード // 式ノード
else if (child.type === NODE_TYPES.EXPRESSION && child.content && isI18nReference(child.content)) { else if (child.type === NodeTypes.TEXT && child.content && isI18nReference(child.content)) {
label = child.content.trim(); label = child.content.trim();
logger.info(`Found i18n in expression: ${label}`); logger.info(`Found i18n in expression: ${label}`);
break; break;
} }
// テキストードでもMustache構文を探す // テキストードでもMustache構文を探す
else if (child.type === NODE_TYPES.TEXT && child.content) { else if (child.type === NodeTypes.COMMENT && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/); const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) { if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) {
label = mustacheMatch[1].trim(); label = mustacheMatch[1].trim();
@ -778,11 +731,12 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
logger.info(`SearchKeyword found but extraction failed, trying direct children inspection`); logger.info(`SearchKeyword found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認 // バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) { {
for (const child of node.children) { for (const child of node.children) {
// Mustacheインターポレーション // Mustacheインターポレーション
if (child.type === NODE_TYPES.INTERPOLATION && child.content) { if (child.type === NodeTypes.INTERPOLATION && child.content) {
// content内の式を取り出す // content内の式を取り出す
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("unexpected COMPOUND_EXPRESSION");
const expression = child.content.content || const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) || (child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content); JSON.stringify(child.content);
@ -796,14 +750,14 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
} }
} }
// 式ノード // 式ノード
else if (child.type === NODE_TYPES.EXPRESSION && child.content && isI18nReference(child.content)) { else if (child.type === NodeTypes.TEXT && child.content && isI18nReference(child.content)) {
const keyword = child.content.trim(); const keyword = child.content.trim();
keywords.push(keyword); keywords.push(keyword);
logger.info(`Found i18n keyword in expression: ${keyword}`); logger.info(`Found i18n keyword in expression: ${keyword}`);
break; break;
} }
// テキストードでもMustache構文を探す // テキストードでもMustache構文を探す
else if (child.type === NODE_TYPES.TEXT && child.content) { else if (child.type === NodeTypes.COMMENT && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/); const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) { if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) {
const keyword = mustacheMatch[1].trim(); const keyword = mustacheMatch[1].trim();
@ -834,23 +788,22 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
function extractUsageInfoFromTemplateAst( function extractUsageInfoFromTemplateAst(
templateAst: any, templateAst: RootNode | undefined,
id: string, id: string,
): SearchIndexItem[] { ): SearchIndexStringItem[] {
const allMarkers: SearchIndexItem[] = []; const allMarkers: SearchIndexStringItem[] = [];
const markerMap = new Map<string, SearchIndexItem>(); const markerMap = new Map<string, SearchIndexItemLink<string>>();
const childrenIds = new Set<string>(); const childrenIds = new Set<string>();
const normalizedId = id.replace(/\\/g, '/'); const normalizedId = id.replace(/\\/g, '/');
if (!templateAst) return allMarkers; if (!templateAst) return allMarkers;
// マーカーの基本情報を収集 // マーカーの基本情報を収集
function collectMarkers(node: VueAstNode, parentId: string | null = null) { function collectMarkers(node: TemplateChildNode | RootNode, parentId: string | null = null) {
if (node.type === 1 && node.tag === 'SearchMarker') { if (node.type === NodeTypes.ELEMENT && node.tag === 'SearchMarker') {
// マーカーID取得 // マーカーID取得
const markerIdProp = node.props?.find((p: any) => p.name === 'markerId'); const markerIdProp = node.props?.find(p => p.name === 'markerId');
const markerId = markerIdProp?.value?.content || const markerId = markerIdProp?.type == NodeTypes.ATTRIBUTE ? markerIdProp.value?.content : null;
node.__markerId;
// SearchMarkerにマーカーIDがない場合はエラー // SearchMarkerにマーカーIDがない場合はエラー
if (markerId == null) { if (markerId == null) {
@ -859,7 +812,7 @@ function extractUsageInfoFromTemplateAst(
} }
// マーカー基本情報 // マーカー基本情報
const markerInfo: SearchIndexItem = { const markerInfo: SearchIndexStringItem = {
id: markerId, id: markerId,
children: [], children: [],
label: '', // デフォルト値 label: '', // デフォルト値
@ -882,7 +835,7 @@ function extractUsageInfoFromTemplateAst(
if (bindings.path) markerInfo.path = bindings.path; if (bindings.path) markerInfo.path = bindings.path;
if (bindings.icon) markerInfo.icon = bindings.icon; if (bindings.icon) markerInfo.icon = bindings.icon;
if (bindings.label) markerInfo.label = bindings.label; if (bindings.label) markerInfo.label = bindings.label;
if (bindings.children) markerInfo.children = bindings.children; if (bindings.children) markerInfo.children = processMarkerProperty(bindings.children, 'children') as string[];
if (bindings.inlining) { if (bindings.inlining) {
markerInfo.inlining = bindings.inlining; markerInfo.inlining = bindings.inlining;
logger.info(`Added inlining ${JSON.stringify(bindings.inlining)} to marker ${markerId}`); logger.info(`Added inlining ${JSON.stringify(bindings.inlining)} to marker ${markerId}`);
@ -946,19 +899,19 @@ function extractUsageInfoFromTemplateAst(
} }
// 子ノードを処理 // 子ノードを処理
if (node.children && Array.isArray(node.children)) { for (const child of node.children) {
node.children.forEach((child: VueAstNode) => {
collectMarkers(child, markerId); collectMarkers(child, markerId);
});
} }
return markerId; return markerId;
} }
// SearchMarkerでない場合は再帰的に子ードを処理 // SearchMarkerでない場合は再帰的に子ードを処理
else if (node.children && Array.isArray(node.children)) { else if ('children' in node && Array.isArray(node.children)) {
node.children.forEach((child: VueAstNode) => { for (const child of node.children) {
if (typeof child == 'object' && child.type !== NodeTypes.SIMPLE_EXPRESSION) {
collectMarkers(child, parentId); collectMarkers(child, parentId);
}); }
}
} }
return null; return null;
@ -969,16 +922,22 @@ function extractUsageInfoFromTemplateAst(
return allMarkers; return allMarkers;
} }
type SpecialBindings = {
inlining: string[];
keywords: string[] | string;
};
type Bindings = Partial<Omit<Record<keyof SearchIndexItem, string>, keyof SpecialBindings> & SpecialBindings>;
// バインドプロパティの処理を修正する関数 // バインドプロパティの処理を修正する関数
function extractNodeBindings(node: VueAstNode): Record<keyof SearchIndexItem, any> { function extractNodeBindings(node: TemplateChildNode | RootNode): Bindings {
const bindings: Record<string, any> = {}; const bindings: Bindings = {};
if (!node.props || !Array.isArray(node.props)) return bindings; if (node.type !== NodeTypes.ELEMENT) return bindings;
// バインド式を収集 // バインド式を収集
for (const prop of node.props) { for (const prop of node.props) {
if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) { if (prop.type === NodeTypes.DIRECTIVE && prop.name === 'bind' && prop.arg && 'content' in prop.arg) {
const propName = prop.arg.content; const propName = prop.arg.content;
if (prop.exp?.type === NodeTypes.COMPOUND_EXPRESSION) throw new Error('unexpected COMPOUND_EXPRESSION');
const propContent = prop.exp?.content || ''; const propContent = prop.exp?.content || '';
logger.info(`Processing bind prop ${propName}: ${propContent}`); logger.info(`Processing bind prop ${propName}: ${propContent}`);
@ -1055,7 +1014,7 @@ function extractNodeBindings(node: VueAstNode): Record<keyof SearchIndexItem, an
} }
// 配列式をパースする補助関数(文字列リテラル処理を改善) // 配列式をパースする補助関数(文字列リテラル処理を改善)
function parseArrayExpression(expr: string): any[] { function parseArrayExpression(expr: string): string[] {
try { try {
// 単純なケースはJSON5でパースを試みる // 単純なケースはJSON5でパースを試みる
return JSON5.parse(expr.replace(/'/g, '"')); return JSON5.parse(expr.replace(/'/g, '"'));
@ -1067,7 +1026,7 @@ function parseArrayExpression(expr: string): any[] {
const content = expr.substring(1, expr.length - 1).trim(); const content = expr.substring(1, expr.length - 1).trim();
if (!content) return []; if (!content) return [];
const result: any[] = []; const result: string[] = [];
let currentItem = ''; let currentItem = '';
let depth = 0; let depth = 0;
let inString = false; let inString = false;
@ -1138,37 +1097,16 @@ function parseArrayExpression(expr: string): any[] {
} }
} }
export async function analyzeVueProps(options: Options & { export function collectFileMarkers(files: [id: string, code: string][]): AnalysisResult<SearchIndexStringItem> {
transformedCodeCache: Record<string, string>, const allMarkers: SearchIndexStringItem[] = [];
}): Promise<void> { for (const [id, code] of files) {
initLogger(options);
const allMarkers: SearchIndexItem[] = [];
// 対象ファイルパスを glob で展開
const filePaths = options.targetFilePaths.reduce<string[]>((acc, filePathPattern) => {
const matchedFiles = glob.sync(filePathPattern);
return [...acc, ...matchedFiles];
}, []);
logger.info(`Found ${filePaths.length} matching files to analyze`);
for (const filePath of filePaths) {
const absolutePath = path.join(process.cwd(), filePath);
const id = absolutePath.replace(/\\/g, '/'); // 絶対パスに変換
const code = options.transformedCodeCache[id]; // options 経由でキャッシュ参照
if (!code) { // キャッシュミスの場合
logger.error(`Error: No cached code found for: ${id}.`); // エラーログ
throw new Error(`No cached code found for: ${id}.`); // エラーを投げる
}
try { try {
const { descriptor, errors } = vueSfcParse(options.transformedCodeCache[id], { const { descriptor, errors } = vueSfcParse(code, {
filename: filePath, filename: id,
}); });
if (errors.length > 0) { if (errors.length > 0) {
logger.error(`Compile Error: ${filePath}, ${errors}`); logger.error(`Compile Error: ${id}, ${errors}`);
continue; // エラーが発生したファイルはスキップ continue; // エラーが発生したファイルはスキップ
} }
@ -1176,83 +1114,76 @@ export async function analyzeVueProps(options: Options & {
if (fileMarkers && fileMarkers.length > 0) { if (fileMarkers && fileMarkers.length > 0) {
allMarkers.push(...fileMarkers); // すべてのマーカーを収集 allMarkers.push(...fileMarkers); // すべてのマーカーを収集
logger.info(`Successfully extracted ${fileMarkers.length} markers from ${filePath}`); logger.info(`Successfully extracted ${fileMarkers.length} markers from ${id}`);
} else { } else {
logger.info(`No markers found in ${filePath}`); logger.info(`No markers found in ${id}`);
} }
} catch (error) { } catch (error) {
logger.error(`Error analyzing file ${filePath}:`, error); logger.error(`Error analyzing file ${id}:`, error);
} }
} }
// 収集したすべてのマーカー情報を使用 // 収集したすべてのマーカー情報を使用
const analysisResult: AnalysisResult[] = [ return {
{
filePath: "combined-markers", // すべてのファイルのマーカーを1つのエントリとして扱う filePath: "combined-markers", // すべてのファイルのマーカーを1つのエントリとして扱う
usage: allMarkers, usage: allMarkers,
};
}
type TransformedCode = {
code: string,
map: SourceMap,
};
export class MarkerIdAssigner {
// key: file id
private cache: Map<string, TransformedCode>;
constructor() {
this.cache = new Map();
} }
];
outputAnalysisResultAsTS(options.exportFilePath, analysisResult); // すべてのマーカー情報を渡す public onInvalidate(id: string) {
} this.cache.delete(id);
}
interface MarkerRelation { public processFile(id: string, code: string): TransformedCode {
parentId?: string; // try cache first
markerId: string; if (this.cache.has(id)) {
node: VueAstNode; return this.cache.get(id)!;
} }
const transformed = this.#processImpl(id, code);
async function processVueFile( this.cache.set(id, transformed);
code: string, return transformed;
id: string, }
options: Options,
transformedCodeCache: Record<string, string>
): Promise<{
code: string,
map: any,
transformedCodeCache: Record<string, string>
}> {
const normalizedId = id.replace(/\\/g, '/'); // ファイルパスを正規化
// 開発モード時はコード内容に変更があれば常に再処理する
// コード内容が同じ場合のみキャッシュを使用
const isDevMode = process.env.NODE_ENV === 'development';
#processImpl(id: string, code: string): TransformedCode {
const s = new MagicString(code); // magic-string のインスタンスを作成 const s = new MagicString(code); // magic-string のインスタンスを作成
if (!isDevMode && transformedCodeCache[normalizedId] && transformedCodeCache[normalizedId].includes('markerId=')) {
logger.info(`Using cached version for ${id}`);
return {
code: transformedCodeCache[normalizedId],
map: s.generateMap({ source: id, includeContent: true }),
transformedCodeCache
};
}
// すでに処理済みのファイルでコードに変更がない場合はキャッシュを返す
if (transformedCodeCache[normalizedId] === code) {
logger.info(`Code unchanged for ${id}, using cached version`);
return {
code: transformedCodeCache[normalizedId],
map: s.generateMap({ source: id, includeContent: true }),
transformedCodeCache
};
}
const parsed = vueSfcParse(code, { filename: id }); const parsed = vueSfcParse(code, { filename: id });
if (!parsed.descriptor.template) { if (!parsed.descriptor.template) {
return { return {
code, code,
map: s.generateMap({ source: id, includeContent: true }), map: s.generateMap({ source: id, includeContent: true }),
transformedCodeCache
}; };
} }
const ast = parsed.descriptor.template.ast; // テンプレート AST を取得 const ast = parsed.descriptor.template.ast; // テンプレート AST を取得
const markerRelations: MarkerRelation[] = []; // MarkerRelation 配列を初期化 const markerRelations: MarkerRelation[] = []; // MarkerRelation 配列を初期化
if (ast) { if (!ast) {
function traverse(node: any, currentParent?: any) { return {
if (node.type === 1 && node.tag === 'SearchMarker') { code: s.toString(), // 変更後のコードを返す
map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生成 (sourceMap: true が必要)
};
}
type SearchMarkerElementNode = ElementNode & {
__markerId?: string,
__children?: string[],
};
function traverse(node: RootNode | TemplateChildNode | SimpleExpressionNode | CompoundExpressionNode, currentParent?: SearchMarkerElementNode) {
if (node.type === NodeTypes.ELEMENT && node.tag === 'SearchMarker') {
// 行番号はコード先頭からの改行数で取得 // 行番号はコード先頭からの改行数で取得
const lineNumber = code.slice(0, node.loc.start.offset).split('\n').length; const lineNumber = code.slice(0, node.loc.start.offset).split('\n').length;
// ファイルパスと行番号からハッシュ値を生成 // ファイルパスと行番号からハッシュ値を生成
@ -1261,14 +1192,14 @@ async function processVueFile(
const generatedMarkerId = toBase62(hash(`${idKey}:${lineNumber}`)); const generatedMarkerId = toBase62(hash(`${idKey}:${lineNumber}`));
const props = node.props || []; const props = node.props || [];
const hasMarkerIdProp = props.some((prop: any) => prop.type === 6 && prop.name === 'markerId'); const hasMarkerIdProp = props.some((prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === 'markerId');
const nodeMarkerId = hasMarkerIdProp const nodeMarkerId = hasMarkerIdProp
? props.find((prop: any) => prop.type === 6 && prop.name === 'markerId')?.value?.content as string ? props.find((prop): prop is AttributeNode => prop.type === NodeTypes.ATTRIBUTE && prop.name === 'markerId')?.value?.content as string
: generatedMarkerId; : generatedMarkerId;
node.__markerId = nodeMarkerId; (node as SearchMarkerElementNode).__markerId = nodeMarkerId;
// 子マーカーの場合、親ノードに __children を設定しておく // 子マーカーの場合、親ノードに __children を設定しておく
if (currentParent && currentParent.type === 1 && currentParent.tag === 'SearchMarker') { if (currentParent) {
currentParent.__children = currentParent.__children || []; currentParent.__children = currentParent.__children || [];
currentParent.__children.push(nodeMarkerId); currentParent.__children.push(nodeMarkerId);
} }
@ -1313,9 +1244,13 @@ async function processVueFile(
} }
} }
const newParent = node.type === 1 && node.tag === 'SearchMarker' ? node : currentParent; const newParent: SearchMarkerElementNode | undefined = node.type === NodeTypes.ELEMENT && node.tag === 'SearchMarker' ? node : currentParent;
if (node.children && Array.isArray(node.children)) { if ('children' in node) {
node.children.forEach(child => traverse(child, newParent)); for (const child of node.children) {
if (typeof child == 'object') {
traverse(child, newParent);
}
}
} }
} }
@ -1341,7 +1276,11 @@ async function processVueFile(
if (!parentRelation || !parentRelation.node) continue; 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): prop is DirectiveNode =>
prop.type === NodeTypes.DIRECTIVE &&
prop.name === 'bind' &&
prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION &&
prop.arg.content === 'children');
// 親ノードの開始位置を特定 // 親ノードの開始位置を特定
const parentNodeStart = parentNode.loc!.start.offset; const parentNodeStart = parentNode.loc!.start.offset;
@ -1416,53 +1355,64 @@ async function processVueFile(
} }
} }
} }
}
const transformedCode = s.toString(); // 変換後のコードを取得
transformedCodeCache[normalizedId] = transformedCode; // 変換後のコードをキャッシュに保存
return { return {
code: transformedCode, // 変更後のコードを返す code: s.toString(), // 変更後のコードを返す
map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生成 (sourceMap: true が必要) map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生成 (sourceMap: true が必要)
transformedCodeCache // キャッシュも返す
}; };
}
export async function generateSearchIndex(options: Options, transformedCodeCache: Record<string, string> = {}) {
const filePaths = options.targetFilePaths.reduce<string[]>((acc, filePathPattern) => {
const matchedFiles = glob.sync(filePathPattern);
return [...acc, ...matchedFiles];
}, []);
for (const filePath of filePaths) {
const id = path.resolve(filePath); // 絶対パスに変換
const code = fs.readFileSync(filePath, 'utf-8'); // ファイル内容を読み込む
const { transformedCodeCache: newCache } = await processVueFile(code, id, options, transformedCodeCache); // processVueFile 関数を呼び出す
transformedCodeCache = newCache; // キャッシュを更新
} }
await analyzeVueProps({ ...options, transformedCodeCache }); // 開発サーバー起動時にも analyzeVueProps を実行 async getOrLoad(id: string) {
// if there already exists a cache, return it
// note cahce will be invalidated on file change so the cache must be up to date
let code = this.getCached(id)?.code;
if (code != null) {
return code;
}
return transformedCodeCache; // キャッシュを返す // if no cache found, read and parse the file
const originalCode = await fs.promises.readFile(id, 'utf-8');
// Other code may already parsed the file while we were waiting for the file to be read so re-check the cache
code = this.getCached(id)?.code;
if (code != null) {
return code;
}
// parse the file
code = this.processFile(id, originalCode)?.code;
return code;
}
getCached(id: string) {
return this.cache.get(id);
}
} }
// Rollup プラグインとして export // Rollup プラグインとして export
export default function pluginCreateSearchIndex(options: Options): Plugin { export default function pluginCreateSearchIndex(options: Options): PluginOption {
let transformedCodeCache: Record<string, string> = {}; // キャッシュオブジェクトをプラグインスコープで定義 const assigner = new MarkerIdAssigner();
const isDevServer = process.env.NODE_ENV === 'development'; // 開発サーバーかどうか return [
createSearchIndex(options, assigner),
pluginCreateSearchIndexVirtualModule(options, assigner),
]
}
function createSearchIndex(options: Options, assigner: MarkerIdAssigner): Plugin {
initLogger(options); // ロガーを初期化 initLogger(options); // ロガーを初期化
const root = normalizePath(process.cwd());
return { function isTargetFile(id: string): boolean {
name: 'createSearchIndex', const relativePath = path.posix.relative(root, id);
enforce: 'pre', return options.targetFilePaths.some(pat => minimatch(relativePath, pat))
async buildStart() {
if (!isDevServer) {
return;
} }
transformedCodeCache = await generateSearchIndex(options, transformedCodeCache); return {
name: 'autoAssignMarkerId',
enforce: 'pre',
watchChange(id) {
assigner.onInvalidate(id);
}, },
async transform(code, id) { async transform(code, id) {
@ -1470,43 +1420,88 @@ export default function pluginCreateSearchIndex(options: Options): Plugin {
return; return;
} }
// targetFilePaths にマッチするファイルのみ処理を行う if (!isTargetFile(id)) {
// glob パターンでマッチング
let isMatch = false; // isMatch の初期値を false に設定
for (const pattern of options.targetFilePaths) { // パターンごとにマッチング確認
const globbedFiles = glob.sync(pattern);
for (const globbedFile of globbedFiles) {
const normalizedGlobbedFile = path.resolve(globbedFile); // glob 結果を絶対パスに
const normalizedId = path.resolve(id); // id を絶対パスに
if (normalizedGlobbedFile === normalizedId) { // 絶対パス同士で比較
isMatch = true;
break; // マッチしたらループを抜ける
}
}
if (isMatch) break; // いずれかのパターンでマッチしたら、outer loop も抜ける
}
if (!isMatch) {
return; return;
} }
// ファイルの内容が変更された場合は再処理を行う return assigner.processFile(id, code);
const normalizedId = id.replace(/\\/g, '/'); },
const hasContentChanged = !transformedCodeCache[normalizedId] || transformedCodeCache[normalizedId] !== code; };
}
const transformed = await processVueFile(code, id, options, transformedCodeCache); export function pluginCreateSearchIndexVirtualModule(options: Options, asigner: MarkerIdAssigner): Plugin {
transformedCodeCache = transformed.transformedCodeCache; // キャッシュを更新 const searchIndexPrefix = options.fileVirtualModulePrefix ?? 'search-index-individual:';
const searchIndexSuffix = options.fileVirtualModuleSuffix ?? '.ts';
const allSearchIndexFile = options.mainVirtualModule;
const root = normalizePath(process.cwd());
if (isDevServer && hasContentChanged) { function isTargetFile(id: string): boolean {
await analyzeVueProps({ ...options, transformedCodeCache }); // ファイルが変更されたときのみ分析を実行 const relativePath = path.posix.relative(root, id);
return options.targetFilePaths.some(pat => minimatch(relativePath, pat))
} }
return transformed; function parseSearchIndexFileId(id: string): string | null {
const noQuery = id.split('?')[0];
if (noQuery.startsWith(searchIndexPrefix) && noQuery.endsWith(searchIndexSuffix)) {
const filePath = id.slice(searchIndexPrefix.length).slice(0, -searchIndexSuffix.length);
if (isTargetFile(filePath)) {
return filePath;
}
}
return null;
}
return {
name: 'generateSearchIndexVirtualModule',
// hotUpdate hook を vite:vue よりもあとに実行したいため enforce: post
enforce: 'post',
async resolveId(id) {
if (id == allSearchIndexFile) {
return '\0' + allSearchIndexFile;
}
const searchIndexFilePath = parseSearchIndexFileId(id);
if (searchIndexFilePath != null) {
return id;
}
return undefined;
}, },
async writeBundle() { async load(id) {
await analyzeVueProps({ ...options, transformedCodeCache }); // ビルド時にも analyzeVueProps を実行 if (id == '\0' + allSearchIndexFile) {
const files = await Promise.all(options.targetFilePaths.map(async (filePathPattern) => await glob(filePathPattern))).then(paths => paths.flat());
let generatedFile = '';
let arrayElements = '';
for (let file of files) {
const normalizedRelative = normalizePath(file);
const absoluteId = normalizePath(path.join(process.cwd(), normalizedRelative)) + searchIndexSuffix;
const variableName = normalizedRelative.replace(/[\/.-]/g, '_');
generatedFile += `import { searchIndexes as ${variableName} } from '${searchIndexPrefix}${absoluteId}';\n`;
arrayElements += ` ...${variableName},\n`;
}
generatedFile += `export let searchIndexes = [\n${arrayElements}];\n`;
return generatedFile;
}
const searchIndexFilePath = parseSearchIndexFileId(id);
if (searchIndexFilePath != null) {
// call load to update the index file when the file is changed
this.addWatchFile(searchIndexFilePath);
const code = await asigner.getOrLoad(searchIndexFilePath);
return generateJavaScriptCode(collectSearchItemIndexes([collectFileMarkers([[id, code]])]));
}
return null;
}, },
hotUpdate(this: { environment: { moduleGraph: EnvironmentModuleGraph } }, { file, modules }) {
if (isTargetFile(file)) {
const updateMods = options.modulesToHmrOnUpdate.map(id => this.environment.moduleGraph.getModuleById(path.posix.join(root, id))).filter(x => x != null);
return [...modules, ...updateMods];
}
return modules;
}
}; };
} }

View File

@ -5,7 +5,6 @@
"scripts": { "scripts": {
"watch": "vite", "watch": "vite",
"build": "vite build", "build": "vite build",
"build-search-index": "vite-node --config \"./vite-node.config.ts\" \"./scripts/generate-search-index.ts\"",
"storybook-dev": "nodemon --verbose --watch src --ext \"mdx,ts,vue\" --ignore \"*.stories.ts\" --exec \"pnpm build-storybook-pre && pnpm exec storybook dev -p 6006 --ci\"", "storybook-dev": "nodemon --verbose --watch src --ext \"mdx,ts,vue\" --ignore \"*.stories.ts\" --exec \"pnpm build-storybook-pre && pnpm exec storybook dev -p 6006 --ci\"",
"build-storybook-pre": "(tsc -p .storybook || echo done.) && node .storybook/generate.js && node .storybook/preload-locale.js && node .storybook/preload-theme.js", "build-storybook-pre": "(tsc -p .storybook || echo done.) && node .storybook/generate.js && node .storybook/preload-locale.js && node .storybook/preload-theme.js",
"build-storybook": "pnpm build-storybook-pre && storybook build --webpack-stats-json storybook-static", "build-storybook": "pnpm build-storybook-pre && storybook build --webpack-stats-json storybook-static",
@ -115,6 +114,7 @@
"@typescript-eslint/eslint-plugin": "8.27.0", "@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0", "@typescript-eslint/parser": "8.27.0",
"@vitest/coverage-v8": "3.0.9", "@vitest/coverage-v8": "3.0.9",
"@vue/compiler-core": "3.5.13",
"@vue/runtime-core": "3.5.13", "@vue/runtime-core": "3.5.13",
"acorn": "8.14.1", "acorn": "8.14.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
@ -125,6 +125,7 @@
"happy-dom": "17.4.4", "happy-dom": "17.4.4",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"minimatch": "10.0.1",
"msw": "2.7.3", "msw": "2.7.3",
"msw-storybook-addon": "2.0.4", "msw-storybook-addon": "2.0.4",
"nodemon": "3.1.9", "nodemon": "3.1.9",

View File

@ -1,15 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { searchIndexes } from '../vite.config.js';
import { generateSearchIndex } from '../lib/vite-plugin-create-search-index.js';
async function main() {
for (const searchIndex of searchIndexes) {
await generateSearchIndex(searchIndex);
}
}
main();

View File

@ -94,7 +94,7 @@ export type SuperMenuDef = {
<script lang="ts" setup> <script lang="ts" setup>
import { useTemplateRef, ref, watch, nextTick } from 'vue'; import { useTemplateRef, ref, watch, nextTick } from 'vue';
import type { SearchIndexItem } from '@/utility/autogen/settings-search-index.js'; import type { SearchIndexItem } from '@/utility/settings-search-index.js';
import MkInput from '@/components/MkInput.vue'; import MkInput from '@/components/MkInput.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { getScrollContainer } from '@@/js/scroll.js'; import { getScrollContainer } from '@@/js/scroll.js';

View File

@ -42,7 +42,7 @@ import { instance } from '@/instance.js';
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js'; import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { useRouter } from '@/router.js'; import { useRouter } from '@/router.js';
import { searchIndexes } from '@/utility/autogen/settings-search-index.js'; import { searchIndexes } from '@/utility/settings-search-index.js';
import { enableAutoBackup, getPreferencesProfileMenu } from '@/preferences/utility.js'; import { enableAutoBackup, getPreferencesProfileMenu } from '@/preferences/utility.js';
import { store } from '@/store.js'; import { store } from '@/store.js';
import { signout } from '@/signout.js'; import { signout } from '@/signout.js';

View File

@ -1,993 +0,0 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
// This file was automatically generated by create-search-index.
// Do not edit this file.
import { i18n } from '@/i18n.js';
export type SearchIndexItem = {
id: string;
path?: string;
label: string;
keywords: string[];
icon?: string;
children?: SearchIndexItem[];
};
export const searchIndexes: SearchIndexItem[] = [
{
id: 'flXd1LC7r',
children: [
{
id: 'hB11H5oul',
label: i18n.ts.syncDeviceDarkMode,
keywords: ['sync', 'device', 'dark', 'light', 'mode'],
},
{
id: 'fDbLtIKeo',
label: i18n.ts.themeForLightMode,
keywords: ['light', 'theme'],
},
{
id: 'CsSVILKpX',
label: i18n.ts.themeForDarkMode,
keywords: ['dark', 'theme'],
},
{
id: 'jwW5HULqA',
label: i18n.ts._settings.enableSyncThemesBetweenDevices,
keywords: ['sync', 'themes', 'devices'],
},
],
label: i18n.ts.theme,
keywords: ['theme'],
path: '/settings/theme',
icon: 'ti ti-palette',
},
{
id: '6fFIRXUww',
children: [
{
id: 'EcwZE7dCl',
label: i18n.ts.notUseSound,
keywords: ['mute'],
},
{
id: '9MxYVIf7k',
label: i18n.ts.useSoundOnlyWhenActive,
keywords: ['active', 'mute'],
},
{
id: '94afQxKat',
label: i18n.ts.masterVolume,
keywords: ['volume', 'master'],
},
],
label: i18n.ts.sounds,
keywords: ['sounds', i18n.ts._settings.soundsBanner],
path: '/settings/sounds',
icon: 'ti ti-music',
},
{
id: '5BjnxMfYV',
children: [
{
id: '75QPEg57v',
children: [
{
id: 'CiHijRkGG',
label: i18n.ts.changePassword,
keywords: [],
},
],
label: i18n.ts.password,
keywords: ['password'],
},
{
id: '2fa',
children: [
{
id: 'qCXM0HtJ7',
label: i18n.ts.totp,
keywords: ['totp', 'app', i18n.ts.totpDescription],
},
{
id: '3g1RePuD9',
label: i18n.ts.securityKeyAndPasskey,
keywords: ['security', 'key', 'passkey'],
},
{
id: 'pFRud5u8k',
label: i18n.ts.passwordLessLogin,
keywords: ['password', 'less', 'key', 'passkey', 'login', 'signin', i18n.ts.passwordLessLoginDescription],
},
],
label: i18n.ts['2fa'],
keywords: ['2fa'],
},
],
label: i18n.ts.security,
keywords: ['security', i18n.ts._settings.securityBanner],
path: '/settings/security',
icon: 'ti ti-lock',
},
{
id: 'w4L6myH61',
children: [
{
id: 'ru8DrOn3J',
label: i18n.ts._profile.changeBanner,
keywords: ['banner', 'change'],
},
{
id: 'CCnD8Apnu',
label: i18n.ts._profile.changeAvatar,
keywords: ['avatar', 'icon', 'change'],
},
{
id: 'yFEVCJxFX',
label: i18n.ts._profile.name,
keywords: ['name'],
},
{
id: '2O1S5reaB',
label: i18n.ts._profile.description,
keywords: ['description', 'bio'],
},
{
id: 'pWi4OLS8g',
label: i18n.ts.location,
keywords: ['location', 'locale'],
},
{
id: 'oLO5X6Wtw',
label: i18n.ts.birthday,
keywords: ['birthday', 'birthdate', 'age'],
},
{
id: 'm2trKwPgq',
label: i18n.ts.language,
keywords: ['language', 'locale'],
},
{
id: 'kfDZxCDp9',
label: i18n.ts._profile.metadataEdit,
keywords: ['metadata'],
},
{
id: 'uPt3MFymp',
label: i18n.ts._profile.followedMessage,
keywords: ['follow', 'message', i18n.ts._profile.followedMessageDescription],
},
{
id: 'wuGg0tBjw',
label: i18n.ts.reactionAcceptance,
keywords: ['reaction'],
},
{
id: 'EezPpmMnf',
children: [
{
id: 'f2cRLh8ad',
label: i18n.ts.flagAsCat,
keywords: ['cat'],
},
{
id: 'eVoViiF3h',
label: i18n.ts.flagAsBot,
keywords: ['bot'],
},
],
label: i18n.ts.advancedSettings,
keywords: [],
},
],
label: i18n.ts.profile,
keywords: ['profile'],
path: '/settings/profile',
icon: 'ti ti-user',
},
{
id: '2rp9ka5Ht',
children: [
{
id: 'BhAQiHogN',
label: i18n.ts.makeFollowManuallyApprove,
keywords: ['follow', 'lock', i18n.ts.lockedAccountInfo],
},
{
id: '4DeWGsPaD',
label: i18n.ts.autoAcceptFollowed,
keywords: ['follow', 'auto', 'accept'],
},
{
id: 'iaM6zUmO9',
label: i18n.ts.makeReactionsPublic,
keywords: ['reaction', 'public', i18n.ts.makeReactionsPublicDescription],
},
{
id: '5Q6uhghzV',
label: i18n.ts.followingVisibility,
keywords: ['following', 'visibility'],
},
{
id: 'pZ9q65FX5',
label: i18n.ts.followersVisibility,
keywords: ['follower', 'visibility'],
},
{
id: 'DMS4yvAGg',
label: i18n.ts.hideOnlineStatus,
keywords: ['online', 'status', i18n.ts.hideOnlineStatusDescription],
},
{
id: '8rEsGuN8w',
label: i18n.ts.noCrawle,
keywords: ['crawle', 'index', 'search', i18n.ts.noCrawleDescription],
},
{
id: 's7LdSpiLn',
label: i18n.ts.preventAiLearning,
keywords: ['crawle', 'ai', i18n.ts.preventAiLearningDescription],
},
{
id: 'l2Wf1s2ad',
label: i18n.ts.makeExplorable,
keywords: ['explore', i18n.ts.makeExplorableDescription],
},
{
id: 'xEYlOghao',
label: i18n.ts._chat.chatAllowedUsers,
keywords: ['chat'],
},
{
id: 'BnOtlyaAh',
children: [
{
id: 'BzMIVBpL0',
label: i18n.ts._accountSettings.requireSigninToViewContents,
keywords: ['login', 'signin'],
},
{
id: 'jJUqPqBAv',
label: i18n.ts._accountSettings.makeNotesFollowersOnlyBefore,
keywords: ['follower', i18n.ts._accountSettings.makeNotesFollowersOnlyBeforeDescription],
},
{
id: 'ra10txIFV',
label: i18n.ts._accountSettings.makeNotesHiddenBefore,
keywords: ['hidden', i18n.ts._accountSettings.makeNotesHiddenBeforeDescription],
},
],
label: i18n.ts.lockdown,
keywords: ['lockdown'],
},
],
label: i18n.ts.privacy,
keywords: ['privacy', i18n.ts._settings.privacyBanner],
path: '/settings/privacy',
icon: 'ti ti-lock-open',
},
{
id: '3yCAv0IsZ',
children: [
{
id: 'AKvDrxSj5',
children: [
{
id: 'a5b9RjEvq',
label: i18n.ts.uiLanguage,
keywords: ['language'],
},
{
id: '9ragaff40',
label: i18n.ts.overridedDeviceKind,
keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
},
{
id: 'lfI3yMX9g',
label: i18n.ts.showAvatarDecorations,
keywords: ['avatar', 'icon', 'decoration', 'show'],
},
{
id: '31Y4IcGEf',
label: i18n.ts.alwaysConfirmFollow,
keywords: ['follow', 'confirm', 'always'],
},
{
id: '78q2asrLS',
label: i18n.ts.highlightSensitiveMedia,
keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
},
{
id: 'zydOfGYip',
label: i18n.ts.confirmWhenRevealingSensitiveMedia,
keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
},
{
id: 'wqpOC22Zm',
label: i18n.ts.enableAdvancedMfm,
keywords: ['mfm', 'enable', 'show', 'advanced'],
},
{
id: 'c98gbF9c6',
label: i18n.ts.enableInfiniteScroll,
keywords: ['auto', 'load', 'auto', 'more', 'scroll'],
},
{
id: '6ANRSOaNg',
label: i18n.ts.emojiStyle,
keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
},
],
label: i18n.ts.general,
keywords: ['general'],
},
{
id: '5G6O6qdis',
children: [
{
id: 'khT3n6byY',
label: i18n.ts.showFixedPostForm,
keywords: ['post', 'form', 'timeline'],
},
{
id: 'q5ElfNSou',
label: i18n.ts.showFixedPostFormInChannel,
keywords: ['post', 'form', 'timeline', 'channel'],
},
{
id: '3GcWIaZf8',
label: i18n.ts.collapseRenotes,
keywords: ['renote', i18n.ts.collapseRenotesDescription],
},
{
id: 'd2H4E5ys6',
label: i18n.ts.showGapBetweenNotesInTimeline,
keywords: ['note', 'timeline', 'gap'],
},
{
id: '1LHOhDKGW',
label: i18n.ts.disableStreamingTimeline,
keywords: ['disable', 'streaming', 'timeline'],
},
{
id: 'DSzwvTp7i',
label: i18n.ts.pinnedList,
keywords: ['pinned', 'list'],
},
{
id: 'ykifk3NHS',
label: i18n.ts.showNoteActionsOnlyHover,
keywords: ['hover', 'show', 'footer', 'action'],
},
{
id: 'tLGyaQagB',
label: i18n.ts.showClipButtonInNoteFooter,
keywords: ['footer', 'action', 'clip', 'show'],
},
{
id: '7W6g8Dcqz',
label: i18n.ts.showReactionsCount,
keywords: ['reaction', 'count', 'show'],
},
{
id: 'uAOoH3LFF',
label: i18n.ts.confirmOnReact,
keywords: ['reaction', 'confirm'],
},
{
id: 'eCiyZLC8n',
label: i18n.ts.loadRawImages,
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'],
},
{
id: '68u9uRmFP',
label: i18n.ts.useReactionPickerForContextMenu,
keywords: ['reaction', 'picker', 'contextmenu', 'open'],
},
{
id: 'yxehrHZ6x',
label: i18n.ts.reactionsDisplaySize,
keywords: ['reaction', 'size', 'scale', 'display'],
},
{
id: 'gi8ILaE2Z',
label: i18n.ts.limitWidthOfReaction,
keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
},
{
id: 'cEQJZ7DQG',
label: i18n.ts.mediaListWithOneImageAppearance,
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
},
{
id: 'haX4QVulD',
label: i18n.ts.instanceTicker,
keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
},
{
id: 'pneYnQekL',
label: i18n.ts.displayOfSensitiveMedia,
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
},
],
label: i18n.ts._settings.timelineAndNote,
keywords: ['timeline', 'note'],
},
{
id: 'eJ2jme16W',
children: [
{
id: 'ErMQr6LQk',
label: i18n.ts.keepCw,
keywords: ['remember', 'keep', 'note', 'cw'],
},
{
id: 'zrJicawH9',
label: i18n.ts.rememberNoteVisibility,
keywords: ['remember', 'keep', 'note', 'visibility'],
},
{
id: 'BaQfrVO82',
label: i18n.ts.enableQuickAddMfmFunction,
keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
},
{
id: 'C2WYcVM1d',
label: i18n.ts.defaultNoteVisibility,
keywords: ['default', 'note', 'visibility'],
},
],
label: i18n.ts.postForm,
keywords: ['post', 'form'],
},
{
id: 'sQXSA6gik',
children: [
{
id: 'rICn8stqk',
label: i18n.ts.useGroupedNotifications,
keywords: ['group'],
},
{
id: 'xFmAg2tDe',
label: i18n.ts.position,
keywords: ['position'],
},
{
id: 'Ek4Cw3VPq',
label: i18n.ts.stackAxis,
keywords: ['stack', 'axis', 'direction'],
},
],
label: i18n.ts.notifications,
keywords: ['notification'],
},
{
id: 'gDVCqZfxm',
children: [
{
id: 'ei8Ix3s4S',
label: i18n.ts._settings._chat.showSenderName,
keywords: ['show', 'sender', 'name'],
},
{
id: '2E7vdIUQd',
label: i18n.ts._settings._chat.sendOnEnter,
keywords: ['send', 'enter', 'newline'],
},
],
label: i18n.ts.chat,
keywords: ['chat', 'messaging'],
},
{
id: '96LnS1sxB',
children: [
{
id: 'vPQPvmntL',
label: i18n.ts.reduceUiAnimation,
keywords: ['animation', 'motion', 'reduce'],
},
{
id: 'wfJ91vwzq',
label: i18n.ts.disableShowingAnimatedImages,
keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'],
},
{
id: '42b1L4xdq',
label: i18n.ts.enableAnimatedMfm,
keywords: ['mfm', 'enable', 'show', 'animated'],
},
{
id: 'dLkRNHn3k',
label: i18n.ts.enableHorizontalSwipe,
keywords: ['swipe', 'horizontal', 'tab'],
},
{
id: 'BvooTWFW5',
label: i18n.ts.keepScreenOn,
keywords: ['keep', 'screen', 'display', 'on'],
},
{
id: 'yzbghkAq0',
label: i18n.ts.useNativeUIForVideoAudioPlayer,
keywords: ['native', 'system', 'video', 'audio', 'player', 'media'],
},
{
id: 'aSbKFHbOy',
label: i18n.ts._settings.makeEveryTextElementsSelectable,
keywords: ['text', 'selectable'],
},
{
id: 'bTcAsPvNz',
label: i18n.ts.menuStyle,
keywords: ['menu', 'style', 'popup', 'drawer'],
},
{
id: 'lSVBaLnyW',
label: i18n.ts._contextMenu.title,
keywords: ['contextmenu', 'system', 'native'],
},
{
id: 'pec0uMPq5',
label: i18n.ts.fontSize,
keywords: ['font', 'size'],
},
{
id: 'Eh7vTluDO',
label: i18n.ts.useSystemFont,
keywords: ['font', 'system', 'native'],
},
],
label: i18n.ts.accessibility,
keywords: ['accessibility', i18n.ts._settings.accessibilityBanner],
},
{
id: 'vTRSKf1JA',
children: [
{
id: '2VjlA02wB',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['blur'],
},
{
id: 'f6J0lmg1g',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['blur', 'modal'],
},
{
id: 'hQqXhfNg8',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['sticky'],
},
],
label: i18n.ts.performance,
keywords: ['performance'],
},
{
id: 'utM8dEobb',
label: i18n.ts.dataSaver,
keywords: ['datasaver'],
},
{
id: 'gOUvwkE9t',
children: [
{
id: 'iUMUvFURf',
label: i18n.ts.squareAvatars,
keywords: ['avatar', 'icon', 'square'],
},
{
id: 'ceyPO9Ywi',
label: i18n.ts.seasonalScreenEffect,
keywords: ['effect', 'show'],
},
{
id: 'ztwIlsXhP',
label: i18n.ts.openImageInNewTab,
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
},
{
id: 'vLSsQbZEo',
label: i18n.ts.withRepliesByDefaultForNewlyFollowed,
keywords: ['follow', 'replies'],
},
{
id: 'hQt85bBIX',
label: i18n.ts.whenServerDisconnected,
keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
},
{
id: 'C9SyK2m0',
label: i18n.ts.numberOfPageCache,
keywords: ['cache', 'page'],
},
{
id: '2U0iVUtfW',
label: i18n.ts.forceShowAds,
keywords: ['ad', 'show'],
},
{
id: '1rA7ADEXY',
label: i18n.ts.hemisphere,
keywords: [],
},
{
id: 'vRayx89Rt',
label: i18n.ts.additionalEmojiDictionary,
keywords: ['emoji', 'dictionary', 'additional', 'extra'],
},
],
label: i18n.ts.other,
keywords: ['other'],
},
],
label: i18n.ts.preferences,
keywords: ['general', 'preferences', i18n.ts._settings.preferencesBanner],
path: '/settings/preferences',
icon: 'ti ti-adjustments',
},
{
id: 'mwkwtw83Y',
label: i18n.ts.plugins,
keywords: ['plugin', 'addon', 'extension', i18n.ts._settings.pluginBanner],
path: '/settings/plugin',
icon: 'ti ti-plug',
},
{
id: 'F1uK9ssiY',
children: [
{
id: 'E0ndmaP6Q',
label: i18n.ts._role.policies,
keywords: ['account', 'info'],
},
{
id: 'r5SjfwZJc',
label: i18n.ts.rolesAssignedToMe,
keywords: ['roles'],
},
{
id: 'cm7LrjgaW',
label: i18n.ts.accountMigration,
keywords: ['account', 'move', 'migration'],
},
{
id: 'ozfqNviP3',
label: i18n.ts.closeAccount,
keywords: ['account', 'close', 'delete', i18n.ts._accountDelete.requestAccountDelete],
},
{
id: 'tpywgkpxy',
label: i18n.ts.experimentalFeatures,
keywords: ['experimental', 'feature', 'flags'],
},
{
id: 'zWbGKohZ2',
label: i18n.ts.developer,
keywords: ['developer', 'mode', 'debug'],
},
],
label: i18n.ts.other,
keywords: ['other'],
path: '/settings/other',
icon: 'ti ti-dots',
},
{
id: '9bNikHWzQ',
children: [
{
id: 't6XtfnRm9',
label: i18n.ts._settings.showNavbarSubButtons,
keywords: ['navbar', 'sidebar', 'toggle', 'button', 'sub'],
},
],
label: i18n.ts.navbar,
keywords: ['navbar', 'menu', 'sidebar'],
path: '/settings/navbar',
icon: 'ti ti-list',
},
{
id: '3icEvyv2D',
children: [
{
id: 'lO3uFTkPN',
children: [
{
id: '5JKaXRqyt',
label: i18n.ts.showMutedWord,
keywords: ['show'],
},
],
label: i18n.ts.wordMute,
keywords: ['note', 'word', 'soft', 'mute', 'hide'],
},
{
id: 'fMkjL3dK4',
label: i18n.ts.hardWordMute,
keywords: ['note', 'word', 'hard', 'mute', 'hide'],
},
{
id: 'cimSzQXN0',
label: i18n.ts.instanceMute,
keywords: ['note', 'server', 'instance', 'host', 'federation', 'mute', 'hide'],
},
{
id: 'gq8rPy3Du',
label: `${i18n.ts.mutedUsers} (${ i18n.ts.renote })`,
keywords: ['renote', 'mute', 'hide', 'user'],
},
{
id: 'mh2r7EUbF',
label: i18n.ts.mutedUsers,
keywords: ['note', 'mute', 'hide', 'user'],
},
{
id: 'AUS1OgHrn',
label: i18n.ts.blockedUsers,
keywords: ['block', 'user'],
},
],
label: i18n.ts.muteAndBlock,
keywords: ['mute', 'block', i18n.ts._settings.muteAndBlockBanner],
path: '/settings/mute-block',
icon: 'ti ti-ban',
},
{
id: 'yR1OSyLiT',
children: [
{
id: 'yMJzyzOUk',
label: i18n.ts._emojiPalette.enableSyncBetweenDevicesForPalettes,
keywords: ['sync', 'palettes', 'devices'],
},
{
id: 'wCE09vgZr',
label: i18n.ts._emojiPalette.paletteForMain,
keywords: ['main', 'palette'],
},
{
id: 'uCzRPrSNx',
label: i18n.ts._emojiPalette.paletteForReaction,
keywords: ['reaction', 'palette'],
},
{
id: 'hgQr28WUk',
children: [
{
id: 'fY04NIHSQ',
label: i18n.ts.size,
keywords: ['emoji', 'picker', 'scale', 'size'],
},
{
id: '3j7vlaL7t',
label: i18n.ts.numberOfColumn,
keywords: ['emoji', 'picker', 'width', 'column', 'size'],
},
{
id: 'zPX8z1Bcy',
label: i18n.ts.height,
keywords: ['emoji', 'picker', 'height', 'size'],
},
{
id: '2CSkZa4tl',
label: i18n.ts.style,
keywords: ['emoji', 'picker', 'style'],
},
],
label: i18n.ts.emojiPickerDisplay,
keywords: ['emoji', 'picker', 'display'],
},
],
label: i18n.ts.emojiPalette,
keywords: ['emoji', 'palette'],
path: '/settings/emoji-palette',
icon: 'ti ti-mood-happy',
},
{
id: '3Tcxw4Fwl',
children: [
{
id: 'iIai9O65I',
label: i18n.ts.emailAddress,
keywords: ['email', 'address'],
},
{
id: 'i6cC6oi0m',
label: i18n.ts.receiveAnnouncementFromInstance,
keywords: ['announcement', 'email'],
},
{
id: 'C1YTinP11',
label: i18n.ts.emailNotification,
keywords: ['notification', 'email'],
},
],
label: i18n.ts.email,
keywords: ['email'],
path: '/settings/email',
icon: 'ti ti-mail',
},
{
id: 'tnYoppRiv',
children: [
{
id: 'cN3dsGNxu',
label: i18n.ts.usageAmount,
keywords: ['capacity', 'usage'],
},
{
id: 'rOAOU2P6C',
label: i18n.ts.statistics,
keywords: ['statistics', 'usage'],
},
{
id: 'uXGlQXATx',
label: i18n.ts.uploadFolder,
keywords: ['default', 'upload', 'folder'],
},
{
id: 'goQdtf3dD',
label: i18n.ts.keepOriginalFilename,
keywords: ['keep', 'original', 'filename', i18n.ts.keepOriginalFilenameDescription],
},
{
id: '83xRo0XJl',
label: i18n.ts.alwaysMarkSensitive,
keywords: ['always', 'default', 'mark', 'nsfw', 'sensitive', 'media', 'file'],
},
{
id: 'BrBqZL35E',
label: i18n.ts.enableAutoSensitive,
keywords: ['auto', 'nsfw', 'sensitive', 'media', 'file', i18n.ts.enableAutoSensitiveDescription],
},
],
label: i18n.ts.drive,
keywords: ['drive', i18n.ts._settings.driveBanner],
path: '/settings/drive',
icon: 'ti ti-cloud',
},
{
id: 'FfZdOs8y',
children: [
{
id: 'B1ZU6Ur54',
label: i18n.ts._deck.enableSyncBetweenDevicesForProfiles,
keywords: ['sync', 'profiles', 'devices'],
},
{
id: 'wWH4pxMQN',
label: i18n.ts._deck.useSimpleUiForNonRootPages,
keywords: ['ui', 'root', 'page'],
},
{
id: '3LR509BvD',
label: i18n.ts.defaultNavigationBehaviour,
keywords: ['default', 'navigation', 'behaviour', 'window'],
},
{
id: 'ybU8RLXgm',
label: i18n.ts._deck.alwaysShowMainColumn,
keywords: ['always', 'show', 'main', 'column'],
},
{
id: 'xRasZyAVl',
label: i18n.ts._deck.columnAlign,
keywords: ['column', 'align'],
},
{
id: '6qcyPd0oJ',
label: i18n.ts._deck.deckMenuPosition,
keywords: ['menu', 'position'],
},
{
id: '4zk2Now4S',
label: i18n.ts._deck.navbarPosition,
keywords: ['navbar', 'position'],
},
{
id: 'CGNtJ2I3n',
label: i18n.ts._deck.columnGap,
keywords: ['column', 'gap', 'margin'],
},
{
id: 'rxPDMo7bE',
label: i18n.ts.setWallpaper,
keywords: ['wallpaper'],
},
],
label: i18n.ts.deck,
keywords: ['deck', 'ui'],
path: '/settings/deck',
icon: 'ti ti-columns',
},
{
id: 'BlJ2rsw9h',
children: [
{
id: '9bLU1nIjt',
label: i18n.ts._settings.api,
keywords: ['api', 'app', 'token', 'accessToken'],
},
{
id: '5VSGOVYR0',
label: i18n.ts._settings.webhook,
keywords: ['webhook'],
},
],
label: i18n.ts._settings.serviceConnection,
keywords: ['app', 'service', 'connect', 'webhook', 'api', 'token', i18n.ts._settings.serviceConnectionBanner],
path: '/settings/connect',
icon: 'ti ti-link',
},
{
id: 'gtaOSdIJB',
label: i18n.ts.avatarDecorations,
keywords: ['avatar', 'icon', 'decoration'],
path: '/settings/avatar-decoration',
icon: 'ti ti-sparkles',
},
{
id: 'zK6posor9',
label: i18n.ts.accounts,
keywords: ['accounts'],
path: '/settings/accounts',
icon: 'ti ti-users',
},
{
id: '330Q4mf8E',
children: [
{
id: 'eGSjUDIKu',
label: i18n.ts._exportOrImport.allNotes,
keywords: ['notes'],
},
{
id: 'iMDgUVgRu',
label: i18n.ts._exportOrImport.favoritedNotes,
keywords: ['favorite', 'notes'],
},
{
id: '3y6KgkVbT',
label: i18n.ts._exportOrImport.clips,
keywords: ['clip', 'notes'],
},
{
id: 'cKiHkj8HE',
label: i18n.ts._exportOrImport.followingList,
keywords: ['following', 'users'],
},
{
id: '3zzmQXn0t',
label: i18n.ts._exportOrImport.userLists,
keywords: ['user', 'lists'],
},
{
id: '3ZGXcEqWZ',
label: i18n.ts._exportOrImport.muteList,
keywords: ['mute', 'users'],
},
{
id: '84oL7B1Dr',
label: i18n.ts._exportOrImport.blockingList,
keywords: ['block', 'users'],
},
{
id: 'ckqi48Kbl',
label: i18n.ts.antennas,
keywords: ['antennas'],
},
],
label: i18n.ts._settings.accountData,
keywords: ['import', 'export', 'data', 'archive', i18n.ts._settings.accountDataBanner],
path: '/settings/account-data',
icon: 'ti ti-package',
},
] as const;
export type SearchIndex = typeof searchIndexes;

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { searchIndexes as generated } from 'search-index:settings';
import type { GeneratedSearchIndexItem } from 'search-index:settings';
export type SearchIndexItem = {
id: string;
path?: string;
label: string;
keywords: string[];
icon?: string;
children?: SearchIndexItem[];
};
const rootMods = new Map(generated.map(item => [item.id, item]));
function walk(item: GeneratedSearchIndexItem) {
if (item.inlining) {
for (const id of item.inlining) {
const inline = rootMods.get(id);
if (inline) {
(item.children ??= []).push(inline);
rootMods.delete(id);
} else {
console.log('[Settings Search Index] Failed to inline', id);
}
}
}
for (const child of item.children ?? []) {
walk(child);
}
}
for (const item of generated) {
walk(item);
}
export const searchIndexes: SearchIndexItem[] = generated;

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
declare module 'search-index:settings' {
export type GeneratedSearchIndexItem = {
id: string;
path?: string;
label: string;
keywords: string[];
icon?: string;
inlining?: string[];
children?: GeneratedSearchIndexItem[];
};
export const searchIndexes: GeneratedSearchIndexItem[];
}

View File

@ -24,7 +24,8 @@ const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.s
*/ */
export const searchIndexes = [{ export const searchIndexes = [{
targetFilePaths: ['src/pages/settings/*.vue'], targetFilePaths: ['src/pages/settings/*.vue'],
exportFilePath: './src/utility/autogen/settings-search-index.ts', mainVirtualModule: 'search-index:settings',
modulesToHmrOnUpdate: ['src/pages/settings/index.vue'],
verbose: process.env.FRONTEND_SEARCH_INDEX_VERBOSE === 'true', verbose: process.env.FRONTEND_SEARCH_INDEX_VERBOSE === 'true',
}] satisfies SearchIndexOptions[]; }] satisfies SearchIndexOptions[];

View File

@ -13,6 +13,9 @@ patchedDependencies:
re2: re2:
hash: 018babd22b7ce951bcd10d6246f1e541a7ac7ba212f7fa8985e774ece67d08e1 hash: 018babd22b7ce951bcd10d6246f1e541a7ac7ba212f7fa8985e774ece67d08e1
path: scripts/dependency-patches/re2.patch path: scripts/dependency-patches/re2.patch
vite:
hash: cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29
path: scripts/dependency-patches/vite.patch
importers: importers:
@ -726,7 +729,7 @@ importers:
version: 15.1.1 version: 15.1.1
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: 5.2.3 specifier: 5.2.3
version: 5.2.3(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) version: 5.2.3(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))
'@vue/compiler-sfc': '@vue/compiler-sfc':
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13 version: 3.5.13
@ -864,7 +867,7 @@ importers:
version: 1.13.1(vue@3.5.13(typescript@5.8.2)) version: 1.13.1(vue@3.5.13(typescript@5.8.2))
vite: vite:
specifier: 6.2.4 specifier: 6.2.4
version: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) version: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
vue: vue:
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13(typescript@5.8.2) version: 3.5.13(typescript@5.8.2)
@ -916,7 +919,7 @@ importers:
version: 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2) version: 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)
'@storybook/react-vite': '@storybook/react-vite':
specifier: 8.6.7 specifier: 8.6.7
version: 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.36.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) version: 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.36.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@storybook/test': '@storybook/test':
specifier: 8.6.7 specifier: 8.6.7
version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)) version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
@ -931,7 +934,7 @@ importers:
version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2)) version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2))
'@storybook/vue3-vite': '@storybook/vue3-vite':
specifier: 8.6.7 specifier: 8.6.7
version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) version: 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))
'@testing-library/vue': '@testing-library/vue':
specifier: 8.1.0 specifier: 8.1.0
version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2)) version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))
@ -977,6 +980,9 @@ importers:
'@vitest/coverage-v8': '@vitest/coverage-v8':
specifier: 3.0.9 specifier: 3.0.9
version: 3.0.9(vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) version: 3.0.9(vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@vue/compiler-core':
specifier: 3.5.13
version: 3.5.13
'@vue/runtime-core': '@vue/runtime-core':
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13 version: 3.5.13
@ -1007,6 +1013,9 @@ importers:
micromatch: micromatch:
specifier: 4.0.8 specifier: 4.0.8
version: 4.0.8 version: 4.0.8
minimatch:
specifier: 10.0.1
version: 10.0.1
msw: msw:
specifier: 2.7.3 specifier: 2.7.3
version: 2.7.3(@types/node@22.13.11)(typescript@5.8.2) version: 2.7.3(@types/node@22.13.11)(typescript@5.8.2)
@ -1081,7 +1090,7 @@ importers:
version: 15.1.1 version: 15.1.1
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: 5.2.3 specifier: 5.2.3
version: 5.2.3(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) version: 5.2.3(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))
'@vue/compiler-sfc': '@vue/compiler-sfc':
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13 version: 3.5.13
@ -1135,7 +1144,7 @@ importers:
version: 11.1.0 version: 11.1.0
vite: vite:
specifier: 6.2.4 specifier: 6.2.4
version: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) version: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
vue: vue:
specifier: 3.5.13 specifier: 3.5.13
version: 3.5.13(typescript@5.8.2) version: 3.5.13(typescript@5.8.2)
@ -1723,10 +1732,6 @@ packages:
resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.24.7':
resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.24.8': '@babel/helper-string-parser@7.24.8':
resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -1751,11 +1756,6 @@ packages:
resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/parser@7.24.7':
resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
engines: {node: '>=6.0.0'}
hasBin: true
'@babel/parser@7.25.6': '@babel/parser@7.25.6':
resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@ -1850,10 +1850,6 @@ packages:
resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/types@7.24.7':
resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
engines: {node: '>=6.9.0'}
'@babel/types@7.25.6': '@babel/types@7.25.6':
resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -11836,8 +11832,6 @@ snapshots:
dependencies: dependencies:
'@babel/types': 7.25.6 '@babel/types': 7.25.6
'@babel/helper-string-parser@7.24.7': {}
'@babel/helper-string-parser@7.24.8': {} '@babel/helper-string-parser@7.24.8': {}
'@babel/helper-validator-identifier@7.24.7': {} '@babel/helper-validator-identifier@7.24.7': {}
@ -11864,10 +11858,6 @@ snapshots:
js-tokens: 4.0.0 js-tokens: 4.0.0
picocolors: 1.1.1 picocolors: 1.1.1
'@babel/parser@7.24.7':
dependencies:
'@babel/types': 7.25.6
'@babel/parser@7.25.6': '@babel/parser@7.25.6':
dependencies: dependencies:
'@babel/types': 7.25.6 '@babel/types': 7.25.6
@ -11973,12 +11963,6 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/types@7.24.7':
dependencies:
'@babel/helper-string-parser': 7.24.7
'@babel/helper-validator-identifier': 7.24.7
to-fast-properties: 2.0.0
'@babel/types@7.25.6': '@babel/types@7.25.6':
dependencies: dependencies:
'@babel/helper-string-parser': 7.24.8 '@babel/helper-string-parser': 7.24.8
@ -12848,12 +12832,12 @@ snapshots:
'@types/yargs': 17.0.19 '@types/yargs': 17.0.19
chalk: 4.1.2 chalk: 4.1.2
'@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.2)(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))': '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.2)(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))':
dependencies: dependencies:
glob: 10.4.5 glob: 10.4.5
magic-string: 0.27.0 magic-string: 0.27.0
react-docgen-typescript: 2.2.2(typescript@5.8.2) react-docgen-typescript: 2.2.2(typescript@5.8.2)
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
optionalDependencies: optionalDependencies:
typescript: 5.8.2 typescript: 5.8.2
@ -14369,13 +14353,13 @@ snapshots:
react: 19.0.0 react: 19.0.0
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
'@storybook/builder-vite@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))': '@storybook/builder-vite@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))':
dependencies: dependencies:
'@storybook/csf-plugin': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)) '@storybook/csf-plugin': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
browser-assert: 1.2.1 browser-assert: 1.2.1
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5) storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
ts-dedent: 2.2.0 ts-dedent: 2.2.0
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
'@storybook/components@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))': '@storybook/components@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))':
dependencies: dependencies:
@ -14438,11 +14422,11 @@ snapshots:
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5) storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
'@storybook/react-vite@8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.36.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))': '@storybook/react-vite@8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.36.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))':
dependencies: dependencies:
'@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.8.2)(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.8.2)(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@rollup/pluginutils': 5.1.4(rollup@4.36.0) '@rollup/pluginutils': 5.1.4(rollup@4.36.0)
'@storybook/builder-vite': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) '@storybook/builder-vite': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@storybook/react': 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2) '@storybook/react': 8.6.7(@storybook/test@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(typescript@5.8.2)
find-up: 5.0.0 find-up: 5.0.0
magic-string: 0.30.17 magic-string: 0.30.17
@ -14452,7 +14436,7 @@ snapshots:
resolve: 1.22.8 resolve: 1.22.8
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5) storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
tsconfig-paths: 4.2.0 tsconfig-paths: 4.2.0
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
optionalDependencies: optionalDependencies:
'@storybook/test': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)) '@storybook/test': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
transitivePeerDependencies: transitivePeerDependencies:
@ -14501,15 +14485,15 @@ snapshots:
dependencies: dependencies:
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5) storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
'@storybook/vue3-vite@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))': '@storybook/vue3-vite@8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))':
dependencies: dependencies:
'@storybook/builder-vite': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) '@storybook/builder-vite': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@storybook/vue3': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2)) '@storybook/vue3': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2))
find-package-json: 1.2.0 find-package-json: 1.2.0
magic-string: 0.30.17 magic-string: 0.30.17
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5) storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
typescript: 5.8.2 typescript: 5.8.2
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
vue-component-meta: 2.0.16(typescript@5.8.2) vue-component-meta: 2.0.16(typescript@5.8.2)
vue-docgen-api: 4.75.1(vue@3.5.13(typescript@5.8.2)) vue-docgen-api: 4.75.1(vue@3.5.13(typescript@5.8.2))
transitivePeerDependencies: transitivePeerDependencies:
@ -15350,9 +15334,9 @@ snapshots:
'@ungap/structured-clone@1.2.0': {} '@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-vue@5.2.3(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))': '@vitejs/plugin-vue@5.2.3(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))':
dependencies: dependencies:
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
vue: 3.5.13(typescript@5.8.2) vue: 3.5.13(typescript@5.8.2)
'@vitest/coverage-v8@3.0.9(vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))': '@vitest/coverage-v8@3.0.9(vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))':
@ -15387,14 +15371,14 @@ snapshots:
chai: 5.2.0 chai: 5.2.0
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
'@vitest/mocker@3.0.9(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))': '@vitest/mocker@3.0.9(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))':
dependencies: dependencies:
'@vitest/spy': 3.0.9 '@vitest/spy': 3.0.9
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.17 magic-string: 0.30.17
optionalDependencies: optionalDependencies:
msw: 2.7.3(@types/node@22.13.11)(typescript@5.8.2) msw: 2.7.3(@types/node@22.13.11)(typescript@5.8.2)
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
'@vitest/pretty-format@2.0.5': '@vitest/pretty-format@2.0.5':
dependencies: dependencies:
@ -16554,8 +16538,8 @@ snapshots:
constantinople@4.0.1: constantinople@4.0.1:
dependencies: dependencies:
'@babel/parser': 7.24.7 '@babel/parser': 7.25.6
'@babel/types': 7.24.7 '@babel/types': 7.25.6
content-disposition@0.5.4: content-disposition@0.5.4:
dependencies: dependencies:
@ -19134,7 +19118,7 @@ snapshots:
'@babel/generator': 7.23.5 '@babel/generator': 7.23.5
'@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5) '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5)
'@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5) '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5)
'@babel/types': 7.24.7 '@babel/types': 7.25.6
'@jest/expect-utils': 29.7.0 '@jest/expect-utils': 29.7.0
'@jest/transform': 29.7.0 '@jest/transform': 29.7.0
'@jest/types': 29.6.3 '@jest/types': 29.6.3
@ -22580,7 +22564,7 @@ snapshots:
debug: 4.4.0(supports-color@8.1.1) debug: 4.4.0(supports-color@8.1.1)
es-module-lexer: 1.6.0 es-module-lexer: 1.6.0
pathe: 2.0.3 pathe: 2.0.3
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- jiti - jiti
@ -22597,7 +22581,7 @@ snapshots:
vite-plugin-turbosnap@1.0.3: {} vite-plugin-turbosnap@1.0.3: {}
vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3): vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3):
dependencies: dependencies:
esbuild: 0.25.1 esbuild: 0.25.1
postcss: 8.5.3 postcss: 8.5.3
@ -22616,7 +22600,7 @@ snapshots:
vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3): vitest@3.0.9(@types/debug@4.1.12)(@types/node@22.13.11)(happy-dom@17.4.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3):
dependencies: dependencies:
'@vitest/expect': 3.0.9 '@vitest/expect': 3.0.9
'@vitest/mocker': 3.0.9(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(vite@6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)) '@vitest/mocker': 3.0.9(msw@2.7.3(@types/node@22.13.11)(typescript@5.8.2))(vite@6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3))
'@vitest/pretty-format': 3.0.9 '@vitest/pretty-format': 3.0.9
'@vitest/runner': 3.0.9 '@vitest/runner': 3.0.9
'@vitest/snapshot': 3.0.9 '@vitest/snapshot': 3.0.9
@ -22632,7 +22616,7 @@ snapshots:
tinyexec: 0.3.2 tinyexec: 0.3.2
tinypool: 1.0.2 tinypool: 1.0.2
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
vite: 6.2.4(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite: 6.2.4(patch_hash=cb4a32b4c98072ee9756b54d2da01411e766907004dac5fb3abc965dac9c6a29)(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
vite-node: 3.0.9(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3) vite-node: 3.0.9(@types/node@22.13.11)(sass@1.86.0)(terser@5.39.0)(tsx@4.19.3)
why-is-node-running: 2.3.0 why-is-node-running: 2.3.0
optionalDependencies: optionalDependencies:
@ -22887,7 +22871,7 @@ snapshots:
with@7.0.2: with@7.0.2:
dependencies: dependencies:
'@babel/parser': 7.25.6 '@babel/parser': 7.25.6
'@babel/types': 7.24.7 '@babel/types': 7.25.6
assert-never: 1.2.1 assert-never: 1.2.1
babel-walk: 3.0.0-canary-5 babel-walk: 3.0.0-canary-5

View File

@ -0,0 +1,31 @@
diff --git a/dist/node/chunks/dep-DrOo5SEf.js b/dist/node/chunks/dep-DrOo5SEf.js
index 329e68bd27e55a56d815fa6b4de2d615a8c2b343..9d9f58e90ae836f80063b698e307fec436e53e07 100644
--- a/dist/node/chunks/dep-DrOo5SEf.js
+++ b/dist/node/chunks/dep-DrOo5SEf.js
@@ -45971,7 +45971,7 @@ function importAnalysisPlugin(config) {
let isPartiallySelfAccepting = false;
const importedBindings = enablePartialAccept ? /* @__PURE__ */ new Map() : null;
const toAbsoluteUrl = (url) => path$d.posix.resolve(path$d.posix.dirname(importerModule.url), url);
- const normalizeUrl = async (url, pos, forceSkipImportAnalysis = false) => {
+ const normalizeUrl = async (url, pos, forceSkipImportAnalysis = false, stripBase2 = false) => {
url = stripBase(url, base);
let importerFile = importer;
if (depsOptimizer && moduleListContains(depsOptimizer.options.exclude, url)) {
@@ -46031,7 +46031,7 @@ function importAnalysisPlugin(config) {
e.pos = pos;
throw e;
}
- if (!ssr) url = joinUrlSegments(base, url);
+ if (!ssr && !stripBase2) url = joinUrlSegments(base, url);
return [url, resolved.id];
};
const orderedImportedUrls = new Array(imports.length);
@@ -46288,7 +46288,7 @@ See ${colors$1.blue(
const pluginImports = this._addedImports;
if (pluginImports) {
(await Promise.all(
- [...pluginImports].map((id) => normalizeUrl(id, 0, true))
+ [...pluginImports].map((id) => normalizeUrl(id, 0, true, true))
)).forEach(([url]) => importedUrls.add(url));
}
if (ssr && importerModule.isSelfAccepting) {