Merge branch 'misskey-develop' into merge/2025-03-24

# Conflicts:
#	.github/workflows/storybook.yml
#	package.json
#	packages/frontend/src/utility/autogen/settings-search-index.ts
#	pnpm-lock.yaml
This commit is contained in:
Hazelnoot 2025-04-05 12:20:19 -04:00
commit 7e7350eab5
65 changed files with 486 additions and 1651 deletions

View file

@ -1888,6 +1888,8 @@ _role:
descriptionOfIsExplorable: "La línia de temps d'aquest rol i la llista d'usuaris seran públics si s'activa."
displayOrder: "Posició "
descriptionOfDisplayOrder: "Com més gran és el número, més dalt la seva posició a la interfície."
preserveAssignmentOnMoveAccount: "L'estat de l'assignació també es trasllada amb el compte migrat"
preserveAssignmentOnMoveAccount_description: "Si s'activa quan es migra un compte amb aquest rol, el compte migrat també heretarà aquest rol."
canEditMembersByModerator: "Permetre que els moderadors editin la llista d'usuaris en aquest rol"
descriptionOfCanEditMembersByModerator: "Quan s'activa, els moderadors, així com els administradors, podran afegir i treure usuaris d'aquest rol. Si es troba desactivat, només els administradors poden assignar usuaris."
priority: "Prioritat"

View file

@ -1888,6 +1888,8 @@ _role:
descriptionOfIsExplorable: "This role's timeline and the list of users with this will be made public if enabled."
displayOrder: "Position"
descriptionOfDisplayOrder: "The higher the number, the higher its UI position."
preserveAssignmentOnMoveAccount: "Preserve role assignment during migration"
preserveAssignmentOnMoveAccount_description: "When turned on, this role will be carried over to the destination account when an account with this role is migrated."
canEditMembersByModerator: "Allow moderators to edit the list of members for this role"
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
priority: "Priority"

View file

@ -1888,6 +1888,8 @@ _role:
descriptionOfIsExplorable: "Selezionandolo, la timeline del ruolo diventerà accessibile pubblicamente. Tranne se il ruolo non è pubblico."
displayOrder: "Ordine di visualizzazione"
descriptionOfDisplayOrder: "I valori più alti vengono visualizzati per primi"
preserveAssignmentOnMoveAccount: "Mantenere l'assegnazione alla migrazione del profilo"
preserveAssignmentOnMoveAccount_description: "Attivando, il ruolo verrà portato sul profilo destinatario, durante la migrazione."
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
priority: "Priorità"

View file

@ -1887,6 +1887,8 @@ _role:
descriptionOfIsExplorable: "打开后将公开角色时间线。如果角色不是公开的,就无法公开时间线。"
displayOrder: "显示顺序"
descriptionOfDisplayOrder: "数字越大,显示位置越靠前。"
preserveAssignmentOnMoveAccount: "将分配状态继承到目标账户"
preserveAssignmentOnMoveAccount_description: "启用后,当迁移具有该角色的账户时,目标账户也会继承该角色。"
canEditMembersByModerator: "允许监察员编辑成员"
descriptionOfCanEditMembersByModerator: "如果选中,监察员和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
priority: "优先级"

View file

@ -1,6 +1,6 @@
{
"name": "sharkey",
"version": "2025.4.0-rc.0",
"version": "2025.4.0-rc.1",
"codename": "shonk",
"repository": {
"type": "git",
@ -24,7 +24,6 @@
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"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-frontend-search-index": "pnpm --filter frontend build-search-index",
"start": "pnpm check:connect && cd packages/backend && MK_WARNED_ABOUT_CONFIG=true node ./built/boot/entry.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"init": "pnpm migrate",

View file

@ -15,8 +15,6 @@
focus: ':alpha<0.3<@accent',
bg: '#000',
fg: '#dadada',
fgTransparentWeak: ':alpha<0.75<@fg',
fgTransparent: ':alpha<0.5<@fg',
fgHighlighted: ':lighten<3<@fg',
fgOnAccent: '#fff',
fgOnWhite: '#333',
@ -26,7 +24,6 @@
panelHighlight: ':lighten<3<@panel',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
panelBorder: '" solid 1px var(--MI_THEME-divider)',
thread: ':lighten<12<@panel',
windowHeader: ':alpha<0.85<@panel',

View file

@ -15,8 +15,6 @@
focus: ':alpha<0.3<@accent',
bg: '#fff',
fg: '#5f5f5f',
fgTransparentWeak: ':alpha<0.75<@fg',
fgTransparent: ':alpha<0.5<@fg',
fgHighlighted: ':darken<3<@fg',
fgOnAccent: '#fff',
fgOnWhite: '#333',
@ -26,7 +24,6 @@
panelHighlight: ':darken<3<@panel',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
panelBorder: '" solid 1px var(--MI_THEME-divider)',
thread: ':darken<12<@panel',
windowHeader: ':alpha<0.85<@panel',

View file

@ -46,7 +46,6 @@
fgOnWhite: '@accent',
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
},
}

View file

@ -14,7 +14,6 @@
fgOnWhite: '@accent',
divider: 'rgba(255, 255, 255, 0.14)',
panel: 'rgb(47, 47, 44)',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
header: ':alpha<0.7<@panel',
navBg: '#363636',
renote: '@accent',

View file

@ -14,7 +14,6 @@
fgOnWhite: '@accent',
divider: 'rgba(255, 255, 255, 0.14)',
panel: '#2d2d2d',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
header: ':alpha<0.7<@panel',
navBg: '#363636',
renote: '@accent',

View file

@ -15,7 +15,6 @@
fgOnWhite: '@accent',
divider: 'rgba(255, 255, 255, 0.1)',
panel: '#18181c',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
renote: '@accent',
mention: '#f2c97d',
mentionMe: '@accent',

View file

@ -15,7 +15,6 @@
fgOnWhite: '@accent',
divider: '#e7fffb24',
panel: '#192320',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
popup: '#293330',
renote: '@accent',
mentionMe: '#ffaa00',

View file

@ -15,7 +15,6 @@
fgOnWhite: '@accent',
divider: '#e7fffb24',
panel: '#192320',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
popup: '#293330',
renote: '@accent',
mentionMe: '#b4e900',

View file

@ -49,7 +49,6 @@
navIndicator: '@indicator',
driveFolderBg: ':alpha<0.3<@accent',
fgHighlighted: ':lighten<3<@fg',
fgTransparent: ':alpha<0.5<@fg',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
buttonGradateA: '@accent',
@ -58,8 +57,6 @@
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
deckBg: '#142022',
},

View file

@ -15,7 +15,6 @@
divider: '#cfcfcf',
panel: '#ebe7e5',
panelHeaderBg: '@panel',
panelHeaderDivider: '@divider',
header: ':alpha<0.7<@panel',
navBg: '#ebe7e5',
renote: '#229e92',

View file

@ -15,7 +15,6 @@
header: ':alpha<0.7<@panel',
navBg: '#fff',
panel: '#fff',
panelHeaderDivider: '@divider',
mentionMe: 'rgb(0, 179, 70)',
},
}

View file

@ -13,7 +13,6 @@
fgOnWhite: '@accent',
panel: '#fff',
divider: 'rgb(230 233 234)',
panelHeaderDivider: '@divider',
renote: '@accent',
link: '@accent',
mention: '@accent',

View file

@ -51,7 +51,6 @@
buttonHoverBg: '#0000001a',
driveFolderBg: ':alpha<0.3<@accent',
fgHighlighted: ':lighten<3<@fg',
fgTransparent: ':alpha<0.5<@fg',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
buttonGradateA: '@accent',
@ -60,8 +59,6 @@
panelHighlight: ':lighten<3<@panel',
scrollbarHandle: '#74747433',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
},
}

View file

@ -41,15 +41,12 @@
navIndicator: '@accent',
driveFolderBg: ':alpha<0.3<@accent',
fgHighlighted: ':darken<3<@fg',
fgTransparent: ':alpha<0.5<@fg',
fgOnWhite: '@accent',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
htmlThemeColor: '@bg',
panelHighlight: ':darken<3<@panel',
scrollbarHandle: 'rgba(0, 0, 0, 0.2)',
fgTransparentWeak: ':alpha<0.75<@fg',
panelHeaderDivider: '@divider',
scrollbarHandleHover: 'rgba(0, 0, 0, 0.4)',
},
}

View file

@ -4,77 +4,68 @@
*/
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 { glob } from 'glob';
import JSON5 from 'json5';
import MagicString from 'magic-string';
import MagicString, { SourceMap } from 'magic-string';
import path from 'node:path'
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 {
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 = {
export type AnalysisResult<T = SearchIndexItem> = {
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;
path?: string;
label: string;
keywords: string | string[];
icon?: string;
inlining?: string[];
children?: SearchIndexItem[];
};
children?: T[];
}
export type Options = {
targetFilePaths: string[],
exportFilePath: string,
mainVirtualModule: string,
modulesToHmrOnUpdate: string[],
fileVirtualModulePrefix?: string,
fileVirtualModuleSuffix?: string,
verbose?: boolean,
};
// 関連するノードタイプの定数化
const NODE_TYPES = {
ELEMENT: 1,
EXPRESSION: 2,
TEXT: 3,
INTERPOLATION: 5, // Mustache
};
// マーカー関係を表す型
interface MarkerRelation {
parentId?: string;
markerId: string;
node: VueAstNode;
node: ElementNode;
}
// ロガー
let logger = {
info: (msg: string, options?: LogOptions) => { },
warn: (msg: string, options?: LogOptions) => { },
error: (msg: string, options?: LogOptions) => { },
error: (msg: string, options?: LogErrorOptions) => { },
};
let loggerInitialized = false;
@ -99,14 +90,11 @@ function initLogger(options: Options) {
}
}
/**
* TypeScriptファイルとして出力する
*/
function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisResult[]): void {
function collectSearchItemIndexes(analysisResults: AnalysisResult<SearchIndexStringItem>[]): SearchIndexItem[] {
logger.info(`Processing ${analysisResults.length} files for output`);
// 新しいツリー構造を構築
const allMarkers = new Map<string, SearchIndexItem>();
const allMarkers = new Map<string, SearchIndexStringItem>();
// 1. すべてのマーカーを一旦フラットに収集
for (const file of analysisResults) {
@ -115,10 +103,9 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
for (const marker of file.usage) {
if (marker.id) {
// キーワードとchildren処理を共通化
const processedMarker = {
const processedMarker: SearchIndexStringItem = {
...marker,
keywords: processMarkerProperty(marker.keywords, 'keywords'),
children: processMarkerProperty(marker.children || [], 'children')
};
allMarkers.set(marker.id, processedMarker);
@ -143,14 +130,13 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
const { totalMarkers, totalChildren } = countMarkers(resolvedRootMarkers);
logger.info(`Total markers in tree: ${totalMarkers} (${resolvedRootMarkers.length} roots + ${totalChildren} nested children)`);
// 6. 結果をTS形式で出力
writeOutputFile(outputPath, resolvedRootMarkers);
return resolvedRootMarkers;
}
/**
* 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(']')) {
try {
@ -169,7 +155,7 @@ function processMarkerProperty(propValue: any, propType: 'keywords' | 'children'
/**
* IDを収集する
*/
function collectChildIds(allMarkers: Map<string, SearchIndexItem>): Set<string> {
function collectChildIds(allMarkers: Map<string, SearchIndexStringItem>): Set<string> {
const childIds = new Set<string>();
allMarkers.forEach((marker, id) => {
@ -232,10 +218,10 @@ function collectChildIds(allMarkers: Map<string, SearchIndexItem>): Set<string>
*
*/
function identifyRootMarkers(
allMarkers: Map<string, SearchIndexItem>,
allMarkers: Map<string, SearchIndexStringItem>,
childIds: Set<string>
): SearchIndexItem[] {
const rootMarkers: SearchIndexItem[] = [];
): SearchIndexStringItem[] {
const rootMarkers: SearchIndexStringItem[] = [];
allMarkers.forEach((marker, id) => {
if (!childIds.has(id)) {
@ -251,12 +237,12 @@ function identifyRootMarkers(
* IDから実際のオブジェクトに解決する
*/
function resolveChildReferences(
rootMarkers: SearchIndexItem[],
allMarkers: Map<string, SearchIndexItem>
rootMarkers: SearchIndexStringItem[],
allMarkers: Map<string, SearchIndexStringItem>
): SearchIndexItem[] {
function resolveChildrenForMarker(marker: SearchIndexItem): SearchIndexItem {
function resolveChildrenForMarker(marker: SearchIndexStringItem): SearchIndexItem {
// マーカーのディープコピーを作成
const resolvedMarker = { ...marker };
const resolvedMarker: SearchIndexItem = { ...marker, children: [] };
// 明示的に子マーカー配列を作成
const resolvedChildren: SearchIndexItem[] = [];
@ -351,55 +337,19 @@ function countMarkers(markers: SearchIndexItem[]): { totalMarkers: number, total
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コード生成
*/
function generateTypeScriptCode(resolvedRootMarkers: SearchIndexItem[]): string {
return `
/*
* 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;
`;
function generateJavaScriptCode(resolvedRootMarkers: SearchIndexItem[]): string {
return `import { i18n } from '@/i18n.js';\n`
+ `export const searchIndexes = ${customStringify(resolvedRootMarkers)};\n`;
}
/**
*
* i18n参照を保持しつつ適切な形式に変換
*/
function customStringify(obj: any, depth = 0): string {
function customStringify(obj: unknown, depth = 0): string {
const INDENT_STR = '\t';
// 配列の処理
@ -441,7 +391,6 @@ function customStringify(obj: any, depth = 0): string {
.filter(([key, value]) => {
if (value === undefined) return false;
if (key === 'children' && Array.isArray(value) && value.length === 0) return false;
if (key === 'inlining') return false;
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の場合は空文字列を返す
if (value === undefined) {
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 => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力
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.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. 直接コンテンツの抽出を試行
const directContent = extractDirectContent(node);
if (directContent) return directContent;
// 子要素がない場合は終了
if (!node.children || !Array.isArray(node.children)) {
if (!('children' in node) || !Array.isArray(node.children)) {
return null;
}
@ -548,12 +498,13 @@ function extractElementText(node: VueAstNode): string | null {
/**
*
*/
function extractDirectContent(node: VueAstNode): string | null {
if (!node.content) return null;
function extractDirectContent(node: TemplateChildNode): string | 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'
? node.content.trim()
: (node.content.content ? node.content.content.trim() : null);
const content = typeof node.content === 'string' ? node.content.trim()
: node.content.type !== NodeTypes.INTERPOLATION ? node.content.content.trim()
: null;
if (!content) return null;
@ -582,9 +533,9 @@ function extractDirectContent(node: VueAstNode): string | null {
/**
* Mustache
*/
function extractInterpolationContent(children: VueAstNode[]): string | null {
function extractInterpolationContent(children: TemplateChildNode[]): string | null {
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)}...`);
if (child.content && child.content.type === 4 && child.content.content) {
@ -595,6 +546,7 @@ function extractInterpolationContent(children: VueAstNode[]): string | null {
return content;
}
} else if (child.content && typeof child.content === 'object') {
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("Unexpected COMPOUND_EXPRESSION");
// オブジェクト形式のcontentを探索
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. 参照パターンを持つものを優先
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();
if (isI18nReference(expr)) {
@ -631,7 +583,7 @@ function extractExpressionContent(children: VueAstNode[]): string | null {
// その他の式
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();
logger.info(`Found expression: ${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) {
if (child.type === NODE_TYPES.TEXT && child.content) {
if (child.type === NodeTypes.COMMENT && child.content) {
const text = child.content.trim();
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) {
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);
if (nestedContent) {
logger.info(`Found nested content: ${nestedContent}`);
return nestedContent;
}
} else if (child.type === NODE_TYPES.ELEMENT) {
} else if (child.type === NodeTypes.ELEMENT) {
// childrenがなくても内部を調査
const nestedContent = extractElementText(child);
@ -699,16 +651,16 @@ function extractNestedContent(children: VueAstNode[]): string | null {
/**
* 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;
const keywords: any[] = [];
const keywords: string[] = [];
logger.info(`Extracting labels and keywords from ${nodes.length} nodes`);
// 再帰的にSearchLabelとSearchKeywordを探索ネストされたSearchMarkerは処理しない
function findComponents(nodes: VueAstNode[]) {
function findComponents(nodes: TemplateChildNode[]) {
for (const node of nodes) {
if (node.type === NODE_TYPES.ELEMENT) {
if (node.type === NodeTypes.ELEMENT) {
logger.info(`Checking element: ${node.tag}`);
// SearchMarkerの場合は、その子要素は別スコープなのでスキップ
@ -730,11 +682,12 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
logger.info(`SearchLabel found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
{
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === NODE_TYPES.INTERPOLATION && child.content) {
if (child.type === NodeTypes.INTERPOLATION && child.content) {
// content内の式を取り出す
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("unexpected COMPOUND_EXPRESSION");
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
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();
logger.info(`Found i18n in expression: ${label}`);
break;
}
// テキストードでも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*$/);
if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) {
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`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
{
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === NODE_TYPES.INTERPOLATION && child.content) {
if (child.type === NodeTypes.INTERPOLATION && child.content) {
// content内の式を取り出す
if (child.content.type == NodeTypes.COMPOUND_EXPRESSION) throw new Error("unexpected COMPOUND_EXPRESSION");
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
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();
keywords.push(keyword);
logger.info(`Found i18n keyword in expression: ${keyword}`);
break;
}
// テキストードでも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*$/);
if (mustacheMatch && mustacheMatch[1] && isI18nReference(mustacheMatch[1])) {
const keyword = mustacheMatch[1].trim();
@ -834,23 +788,22 @@ function extractLabelsAndKeywords(nodes: VueAstNode[]): { label: string | null,
function extractUsageInfoFromTemplateAst(
templateAst: any,
templateAst: RootNode | undefined,
id: string,
): SearchIndexItem[] {
const allMarkers: SearchIndexItem[] = [];
const markerMap = new Map<string, SearchIndexItem>();
): SearchIndexStringItem[] {
const allMarkers: SearchIndexStringItem[] = [];
const markerMap = new Map<string, SearchIndexItemLink<string>>();
const childrenIds = new Set<string>();
const normalizedId = id.replace(/\\/g, '/');
if (!templateAst) return allMarkers;
// マーカーの基本情報を収集
function collectMarkers(node: VueAstNode, parentId: string | null = null) {
if (node.type === 1 && node.tag === 'SearchMarker') {
function collectMarkers(node: TemplateChildNode | RootNode, parentId: string | null = null) {
if (node.type === NodeTypes.ELEMENT && node.tag === 'SearchMarker') {
// マーカーID取得
const markerIdProp = node.props?.find((p: any) => p.name === 'markerId');
const markerId = markerIdProp?.value?.content ||
node.__markerId;
const markerIdProp = node.props?.find(p => p.name === 'markerId');
const markerId = markerIdProp?.type == NodeTypes.ATTRIBUTE ? markerIdProp.value?.content : null;
// SearchMarkerにマーカーIDがない場合はエラー
if (markerId == null) {
@ -859,7 +812,7 @@ function extractUsageInfoFromTemplateAst(
}
// マーカー基本情報
const markerInfo: SearchIndexItem = {
const markerInfo: SearchIndexStringItem = {
id: markerId,
children: [],
label: '', // デフォルト値
@ -882,7 +835,7 @@ function extractUsageInfoFromTemplateAst(
if (bindings.path) markerInfo.path = bindings.path;
if (bindings.icon) markerInfo.icon = bindings.icon;
if (bindings.label) markerInfo.label = bindings.label;
if (bindings.children) markerInfo.children = bindings.children;
if (bindings.children) markerInfo.children = processMarkerProperty(bindings.children, 'children') as string[];
if (bindings.inlining) {
markerInfo.inlining = bindings.inlining;
logger.info(`Added inlining ${JSON.stringify(bindings.inlining)} to marker ${markerId}`);
@ -946,19 +899,19 @@ function extractUsageInfoFromTemplateAst(
}
// 子ノードを処理
if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: VueAstNode) => {
for (const child of node.children) {
collectMarkers(child, markerId);
});
}
return markerId;
}
// SearchMarkerでない場合は再帰的に子ードを処理
else if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: VueAstNode) => {
else if ('children' in node && Array.isArray(node.children)) {
for (const child of node.children) {
if (typeof child == 'object' && child.type !== NodeTypes.SIMPLE_EXPRESSION) {
collectMarkers(child, parentId);
});
}
}
}
return null;
@ -969,16 +922,22 @@ function extractUsageInfoFromTemplateAst(
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> {
const bindings: Record<string, any> = {};
function extractNodeBindings(node: TemplateChildNode | RootNode): Bindings {
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) {
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;
if (prop.exp?.type === NodeTypes.COMPOUND_EXPRESSION) throw new Error('unexpected COMPOUND_EXPRESSION');
const propContent = prop.exp?.content || '';
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 {
// 単純なケースはJSON5でパースを試みる
return JSON5.parse(expr.replace(/'/g, '"'));
@ -1067,7 +1026,7 @@ function parseArrayExpression(expr: string): any[] {
const content = expr.substring(1, expr.length - 1).trim();
if (!content) return [];
const result: any[] = [];
const result: string[] = [];
let currentItem = '';
let depth = 0;
let inString = false;
@ -1138,37 +1097,16 @@ function parseArrayExpression(expr: string): any[] {
}
}
export async function analyzeVueProps(options: Options & {
transformedCodeCache: Record<string, string>,
}): Promise<void> {
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}.`); // エラーを投げる
}
export function collectFileMarkers(files: [id: string, code: string][]): AnalysisResult<SearchIndexStringItem> {
const allMarkers: SearchIndexStringItem[] = [];
for (const [id, code] of files) {
try {
const { descriptor, errors } = vueSfcParse(options.transformedCodeCache[id], {
filename: filePath,
const { descriptor, errors } = vueSfcParse(code, {
filename: id,
});
if (errors.length > 0) {
logger.error(`Compile Error: ${filePath}, ${errors}`);
logger.error(`Compile Error: ${id}, ${errors}`);
continue; // エラーが発生したファイルはスキップ
}
@ -1176,83 +1114,76 @@ export async function analyzeVueProps(options: Options & {
if (fileMarkers && fileMarkers.length > 0) {
allMarkers.push(...fileMarkers); // すべてのマーカーを収集
logger.info(`Successfully extracted ${fileMarkers.length} markers from ${filePath}`);
logger.info(`Successfully extracted ${fileMarkers.length} markers from ${id}`);
} else {
logger.info(`No markers found in ${filePath}`);
logger.info(`No markers found in ${id}`);
}
} catch (error) {
logger.error(`Error analyzing file ${filePath}:`, error);
logger.error(`Error analyzing file ${id}:`, error);
}
}
// 収集したすべてのマーカー情報を使用
const analysisResult: AnalysisResult[] = [
{
return {
filePath: "combined-markers", // すべてのファイルのマーカーを1つのエントリとして扱う
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 {
parentId?: string;
markerId: string;
node: VueAstNode;
}
async function processVueFile(
code: string,
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';
public processFile(id: string, code: string): TransformedCode {
// try cache first
if (this.cache.has(id)) {
return this.cache.get(id)!;
}
const transformed = this.#processImpl(id, code);
this.cache.set(id, transformed);
return transformed;
}
#processImpl(id: string, code: string): TransformedCode {
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 });
if (!parsed.descriptor.template) {
return {
code,
map: s.generateMap({ source: id, includeContent: true }),
transformedCodeCache
};
}
const ast = parsed.descriptor.template.ast; // テンプレート AST を取得
const markerRelations: MarkerRelation[] = []; // MarkerRelation 配列を初期化
if (ast) {
function traverse(node: any, currentParent?: any) {
if (node.type === 1 && node.tag === 'SearchMarker') {
if (!ast) {
return {
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;
// ファイルパスと行番号からハッシュ値を生成
@ -1261,14 +1192,14 @@ async function processVueFile(
const generatedMarkerId = toBase62(hash(`${idKey}:${lineNumber}`));
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
? 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;
node.__markerId = nodeMarkerId;
(node as SearchMarkerElementNode).__markerId = nodeMarkerId;
// 子マーカーの場合、親ノードに __children を設定しておく
if (currentParent && currentParent.type === 1 && currentParent.tag === 'SearchMarker') {
if (currentParent) {
currentParent.__children = currentParent.__children || [];
currentParent.__children.push(nodeMarkerId);
}
@ -1313,9 +1244,13 @@ async function processVueFile(
}
}
const newParent = node.type === 1 && node.tag === 'SearchMarker' ? node : currentParent;
if (node.children && Array.isArray(node.children)) {
node.children.forEach(child => traverse(child, newParent));
const newParent: SearchMarkerElementNode | undefined = node.type === NodeTypes.ELEMENT && node.tag === 'SearchMarker' ? node : currentParent;
if ('children' in node) {
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;
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;
@ -1416,53 +1355,64 @@ async function processVueFile(
}
}
}
}
const transformedCode = s.toString(); // 変換後のコードを取得
transformedCodeCache[normalizedId] = transformedCode; // 変換後のコードをキャッシュに保存
return {
code: transformedCode, // 変更後のコードを返す
code: s.toString(), // 変更後のコードを返す
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
export default function pluginCreateSearchIndex(options: Options): Plugin {
let transformedCodeCache: Record<string, string> = {}; // キャッシュオブジェクトをプラグインスコープで定義
const isDevServer = process.env.NODE_ENV === 'development'; // 開発サーバーかどうか
export default function pluginCreateSearchIndex(options: Options): PluginOption {
const assigner = new MarkerIdAssigner();
return [
createSearchIndex(options, assigner),
pluginCreateSearchIndexVirtualModule(options, assigner),
]
}
function createSearchIndex(options: Options, assigner: MarkerIdAssigner): Plugin {
initLogger(options); // ロガーを初期化
const root = normalizePath(process.cwd());
return {
name: 'createSearchIndex',
enforce: 'pre',
async buildStart() {
if (!isDevServer) {
return;
function isTargetFile(id: string): boolean {
const relativePath = path.posix.relative(root, id);
return options.targetFilePaths.some(pat => minimatch(relativePath, pat))
}
transformedCodeCache = await generateSearchIndex(options, transformedCodeCache);
return {
name: 'autoAssignMarkerId',
enforce: 'pre',
watchChange(id) {
assigner.onInvalidate(id);
},
async transform(code, id) {
@ -1470,43 +1420,88 @@ export default function pluginCreateSearchIndex(options: Options): Plugin {
return;
}
// targetFilePaths にマッチするファイルのみ処理を行う
// 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) {
if (!isTargetFile(id)) {
return;
}
// ファイルの内容が変更された場合は再処理を行う
const normalizedId = id.replace(/\\/g, '/');
const hasContentChanged = !transformedCodeCache[normalizedId] || transformedCodeCache[normalizedId] !== code;
return assigner.processFile(id, code);
},
};
}
const transformed = await processVueFile(code, id, options, transformedCodeCache);
transformedCodeCache = transformed.transformedCodeCache; // キャッシュを更新
export function pluginCreateSearchIndexVirtualModule(options: Options, asigner: MarkerIdAssigner): Plugin {
const searchIndexPrefix = options.fileVirtualModulePrefix ?? 'search-index-individual:';
const searchIndexSuffix = options.fileVirtualModuleSuffix ?? '.ts';
const allSearchIndexFile = options.mainVirtualModule;
const root = normalizePath(process.cwd());
if (isDevServer && hasContentChanged) {
await analyzeVueProps({ ...options, transformedCodeCache }); // ファイルが変更されたときのみ分析を実行
function isTargetFile(id: string): boolean {
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() {
await analyzeVueProps({ ...options, transformedCodeCache }); // ビルド時にも analyzeVueProps を実行
async load(id) {
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": {
"watch": "vite",
"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\"",
"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",
@ -120,6 +119,7 @@
"@typescript-eslint/eslint-plugin": "8.27.0",
"@typescript-eslint/parser": "8.27.0",
"@vitest/coverage-v8": "3.0.9",
"@vue/compiler-core": "3.5.13",
"@vue/runtime-core": "3.5.13",
"acorn": "8.14.1",
"cross-env": "7.0.3",
@ -129,6 +129,7 @@
"happy-dom": "17.4.4",
"intersection-observer": "0.12.2",
"micromatch": "4.0.8",
"minimatch": "10.0.1",
"msw": "2.7.3",
"msw-storybook-addon": "2.0.4",
"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

@ -140,7 +140,7 @@ watch(v, newValue => {
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -60,7 +60,7 @@ const onInput = () => {
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -181,12 +181,17 @@ onUnmounted(() => {
left: 0;
color: var(--MI_THEME-panelHeaderFg);
background: var(--MI_THEME-panelHeaderBg);
border-bottom: solid 0.5px var(--MI_THEME-panelHeaderDivider);
z-index: 2;
line-height: 1.4em;
background: color-mix(in srgb, var(--MI_THEME-panelHeaderBg) 35%, transparent);
}
@container style(--MI_THEME-panelHeaderBg: var(--MI_THEME-panel)) {
.header {
box-shadow: 0 0.5px 0 0 light-dark(#0002, #fff2);
}
}
.title {
margin: 0;
padding: 12px 16px;

View file

@ -175,7 +175,7 @@ onMounted(() => {
}
.headerLower {
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
font-size: .85em;
padding-left: 4px;
}
@ -209,13 +209,13 @@ onMounted(() => {
}
.headerTextSub {
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
font-size: .85em;
}
.headerRight {
margin-left: auto;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
white-space: nowrap;
}

View file

@ -201,7 +201,7 @@ defineExpose({
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -78,7 +78,7 @@ export default defineComponent({
> .caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -213,7 +213,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
> .caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -268,7 +268,7 @@ function show() {
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -94,7 +94,7 @@ export type SuperMenuDef = {
<script lang="ts" setup>
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 { i18n } from '@/i18n.js';
import { getScrollContainer } from '@@/js/scroll.js';

View file

@ -100,7 +100,7 @@ const toggle = () => {
.caption {
margin: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
font-size: 0.85em;
&:empty {

View file

@ -307,6 +307,6 @@ onMounted(async () => {
.description {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -160,7 +160,7 @@ onUnmounted(() => {
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -298,7 +298,7 @@ onMounted(() => {
.statusItemLabel {
font-size: 0.7em;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
.menu {

View file

@ -193,7 +193,7 @@ function showMenu(ev: MouseEvent) {
}
.statsItemLabel {
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
font-size: 0.9em;
}

View file

@ -79,7 +79,7 @@ const props = defineProps<{
margin-right: 0.75em;
flex-shrink: 0;
text-align: center;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -49,7 +49,7 @@ defineProps<{
.description {
font-size: 0.85em;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
margin: 0 0 8px 0;
}
</style>

View file

@ -35,7 +35,7 @@ function focus() {
.caption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
&:empty {
display: none;

View file

@ -81,7 +81,7 @@ const emit = defineEmits<{
const displayBackButton = props.displayBackButton && window.history.state.key !== 'index' && window.history.length > 1 && inject('shouldBackButton', true);
//const viewId = inject(DI.viewId);
const injectedPageMetadata = inject(DI.pageMetadata);
const injectedPageMetadata = inject(DI.pageMetadata, ref(null));
const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value);
const hideTitle = computed(() => inject('shouldOmitHeaderTitle', false) || props.hideTitle);

View file

@ -10,7 +10,7 @@ export const DI = {
routerCurrentDepth: Symbol() as InjectionKey<number>,
router: Symbol() as InjectionKey<Router>,
mock: Symbol() as InjectionKey<boolean>,
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any>>>,
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any> | null>>,
viewId: Symbol() as InjectionKey<string>,
currentStickyTop: Symbol() as InjectionKey<Ref<number>>,
currentStickyBottom: Symbol() as InjectionKey<Ref<number>>,

View file

@ -724,7 +724,7 @@ definePage(() => ({
.roleItemSub {
padding: 6px 12px;
font-size: 85%;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
.roleUnassign {

View file

@ -66,7 +66,7 @@ const emit = defineEmits<{
(ev: 'update:tab', key: string);
}>();
const pageMetadata = inject(DI.pageMetadata);
const pageMetadata = inject(DI.pageMetadata, ref(null));
const el = useTemplateRef('el');
const tabHighlightEl = useTemplateRef('tabHighlightEl');

View file

@ -184,7 +184,7 @@ definePage(() => ({
.userItemSub {
padding: 6px 12px;
font-size: 85%;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
.userItemMainBody {

View file

@ -459,6 +459,6 @@ definePage(() => ({
<style lang="scss" module>
.subCaption {
font-size: 0.85em;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -75,6 +75,6 @@ function onDeleteClick() {
margin-right: 0.75em;
flex-shrink: 0;
text-align: center;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -247,7 +247,7 @@ definePage(() => ({
}
.uiInspectorUnShown {
color: var(--MI_THEME-fgTransparent);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.5);
}
.uiInspectorType {

View file

@ -351,7 +351,7 @@ async function search() {
width: 100%;
height: 100%;
padding: 12px;
border: 2px dashed var(--MI_THEME-fgTransparent);
border: 2px dashed color(from var(--MI_THEME-fg) srgb r g b / 0.5);
}
.userSelectButtonInner {

View file

@ -161,6 +161,6 @@ function del(ev: MouseEvent) {
.editorCaption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -285,6 +285,6 @@ definePage(() => ({
.editorCaption {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -42,7 +42,7 @@ import { instance } from '@/instance.js';
import { definePage, provideMetadataReceiver, provideReactiveMetadata } from '@/page.js';
import * as os from '@/os.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 { store } from '@/store.js';
import { signout } from '@/signout.js';

View file

@ -308,7 +308,7 @@ definePage(() => ({
.userItemSub {
padding: 6px 12px;
font-size: 85%;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
.userItemMainBody {

View file

@ -184,6 +184,6 @@ definePage(() => ({
.description {
font-size: 0.85em;
padding: 8px 0 0 0;
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -653,7 +653,7 @@ onUnmounted(() => {
> .heading {
text-align: left;
color: var(--MI_THEME-fgTransparent);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.5);
line-height: 1.5;
font-size: 85%;
}

View file

@ -67,7 +67,7 @@ export function migrateOldSettings() {
prefer.commit('collapseRenotes', store.s.collapseRenotes);
prefer.commit('rememberNoteVisibility', store.s.rememberNoteVisibility);
prefer.commit('uploadFolder', store.s.uploadFolder);
prefer.commit('menu', store.s.menu);
prefer.commit('menu', [...store.s.menu, 'chat']);
prefer.commit('statusbars', store.s.statusbars);
prefer.commit('pinnedUserLists', store.s.pinnedUserLists);
prefer.commit('serverDisconnectedBehavior', store.s.serverDisconnectedBehavior);

View file

@ -413,11 +413,16 @@ function onDrop(ev) {
font-size: 0.9em;
color: var(--MI_THEME-panelHeaderFg);
background: var(--MI_THEME-panelHeaderBg);
box-shadow: 0 0.5px 0 0 var(--MI_THEME-panelHeaderDivider);
cursor: pointer;
user-select: none;
}
@container style(--MI_THEME-panelHeaderBg: var(--MI_THEME-panel)) {
.header {
box-shadow: 0 0.5px 0 0 light-dark(#0002, #fff2);
}
}
.color {
position: absolute;
top: 12px;

File diff suppressed because it is too large Load diff

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

@ -73,6 +73,6 @@ defineExpose<WidgetComponentExpose>({
}
.text {
color: var(--MI_THEME-fgTransparentWeak);
color: color(from var(--MI_THEME-fg) srgb r g b / 0.75);
}
</style>

View file

@ -23,7 +23,8 @@ const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.s
*/
export const searchIndexes = [{
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',
}] satisfies SearchIndexOptions[];

View file

@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
"version": "2025.4.0-rc.0",
"version": "2025.4.0-rc.1",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",

166
pnpm-lock.yaml generated
View file

@ -1005,6 +1005,9 @@ importers:
'@vitest/coverage-v8':
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)(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':
specifier: 3.5.13
version: 3.5.13
@ -1032,6 +1035,9 @@ importers:
micromatch:
specifier: 4.0.8
version: 4.0.8
minimatch:
specifier: 10.0.1
version: 10.0.1
msw:
specifier: 2.7.3
version: 2.7.3(@types/node@22.13.11)(typescript@5.8.2)
@ -1358,7 +1364,7 @@ importers:
version: 9.1.0(eslint@9.22.0)
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@22.13.10)
version: 29.7.0(@types/node@22.13.15)
jest-worker:
specifier: ^29.7.0
version: 29.7.0
@ -1370,7 +1376,7 @@ importers:
version: 3.3.3
ts-jest:
specifier: ^29.1.1
version: 29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.10))(typescript@5.1.6)
version: 29.1.2(@babel/core@7.23.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.5))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.15))(typescript@5.1.6)
typedoc:
specifier: ^0.25.3
version: 0.25.13(typescript@5.1.6)
@ -8312,10 +8318,6 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@5.1.2:
resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==}
engines: {node: '>=10'}
minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
@ -8324,10 +8326,6 @@ packages:
resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
engines: {node: '>=16 || 14 >=14.17'}
minimatch@9.0.4:
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
engines: {node: '>=16 || 14 >=14.17'}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
@ -11927,56 +11925,26 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
@ -11987,78 +11955,36 @@ snapshots:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)':
dependencies:
'@babel/core': 7.24.7
'@babel/helper-plugin-utils': 7.22.5
optional: true
'@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5)':
dependencies:
'@babel/core': 7.23.5
@ -14624,7 +14550,7 @@ snapshots:
'@storybook/manager-api': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
'@storybook/preview-api': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
'@storybook/theming': 8.6.7(storybook@8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5))
'@vue/compiler-core': 3.5.12
'@vue/compiler-core': 3.5.13
storybook: 8.6.7(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@6.0.5)
ts-dedent: 2.2.0
type-fest: 2.19.0
@ -14650,7 +14576,7 @@ snapshots:
'@xhmikosr/bin-wrapper': 13.0.5
commander: 8.3.0
fast-glob: 3.3.3
minimatch: 9.0.4
minimatch: 9.0.5
piscina: 4.4.0
semver: 7.6.3
slash: 3.0.0
@ -15670,7 +15596,7 @@ snapshots:
'@vue/compiler-dom': 3.5.12
'@vue/shared': 3.5.12
computeds: 0.0.1
minimatch: 9.0.4
minimatch: 9.0.5
path-browserify: 1.0.1
vue-template-compiler: 2.7.14
optionalDependencies:
@ -15683,7 +15609,7 @@ snapshots:
'@vue/compiler-vue2': 2.7.16
'@vue/shared': 3.5.12
alien-signals: 1.0.7
minimatch: 9.0.4
minimatch: 9.0.5
muggle-string: 0.4.1
path-browserify: 1.0.1
optionalDependencies:
@ -16134,20 +16060,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
babel-jest@29.7.0(@babel/core@7.24.7):
dependencies:
'@babel/core': 7.24.7
'@jest/transform': 29.7.0
'@types/babel__core': 7.20.0
babel-plugin-istanbul: 6.1.1
babel-preset-jest: 29.6.3(@babel/core@7.24.7)
chalk: 4.1.2
graceful-fs: 4.2.11
slash: 3.0.0
transitivePeerDependencies:
- supports-color
optional: true
babel-plugin-istanbul@6.1.1:
dependencies:
'@babel/helper-plugin-utils': 7.22.5
@ -16181,36 +16093,12 @@ snapshots:
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.5)
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.5)
babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.7):
dependencies:
'@babel/core': 7.24.7
'@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7)
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7)
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7)
'@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7)
'@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7)
'@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7)
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7)
optional: true
babel-preset-jest@29.6.3(@babel/core@7.23.5):
dependencies:
'@babel/core': 7.23.5
babel-plugin-jest-hoist: 29.6.3
babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.5)
babel-preset-jest@29.6.3(@babel/core@7.24.7):
dependencies:
'@babel/core': 7.24.7
babel-plugin-jest-hoist: 29.6.3
babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.7)
optional: true
babel-walk@3.0.0-canary-5:
dependencies:
'@babel/types': 7.24.7
@ -18333,7 +18221,7 @@ snapshots:
dependencies:
foreground-child: 3.1.1
jackspeak: 2.3.6
minimatch: 9.0.4
minimatch: 9.0.5
minipass: 7.1.2
path-scurry: 1.10.1
@ -18341,7 +18229,7 @@ snapshots:
dependencies:
foreground-child: 3.1.1
jackspeak: 3.4.3
minimatch: 9.0.4
minimatch: 9.0.5
minipass: 7.1.2
package-json-from-dist: 1.0.0
path-scurry: 1.11.1
@ -18651,7 +18539,7 @@ snapshots:
ignore-walk@7.0.0:
dependencies:
minimatch: 9.0.4
minimatch: 9.0.5
ignore@5.3.1: {}
@ -20162,10 +20050,6 @@ snapshots:
dependencies:
brace-expansion: 1.1.11
minimatch@5.1.2:
dependencies:
brace-expansion: 2.0.1
minimatch@5.1.6:
dependencies:
brace-expansion: 2.0.1
@ -20174,10 +20058,6 @@ snapshots:
dependencies:
brace-expansion: 2.0.1
minimatch@9.0.4:
dependencies:
brace-expansion: 2.0.1
minimatch@9.0.5:
dependencies:
brace-expansion: 2.0.1
@ -21408,7 +21288,7 @@ snapshots:
readdir-glob@1.1.2:
dependencies:
minimatch: 5.1.2
minimatch: 5.1.6
readdirp@4.1.2: {}
@ -22314,7 +22194,7 @@ snapshots:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.4.5
minimatch: 9.0.4
minimatch: 9.0.5
text-decoding@1.0.0: {}
@ -22428,11 +22308,11 @@ snapshots:
ts-dedent@2.2.0: {}
ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.10))(typescript@5.1.6):
ts-jest@29.1.2(@babel/core@7.23.5)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.5))(esbuild@0.25.0)(jest@29.7.0(@types/node@22.13.15))(typescript@5.1.6):
dependencies:
bs-logger: 0.2.6
fast-json-stable-stringify: 2.1.0
jest: 29.7.0(@types/node@22.13.10)
jest: 29.7.0(@types/node@22.13.15)
jest-util: 29.7.0
json5: 2.2.3
lodash.memoize: 4.1.2
@ -22441,9 +22321,9 @@ snapshots:
typescript: 5.1.6
yargs-parser: 21.1.1
optionalDependencies:
'@babel/core': 7.24.7
'@babel/core': 7.23.5
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.24.7)
babel-jest: 29.7.0(@babel/core@7.23.5)
esbuild: 0.25.0
ts-map@1.0.3: {}
@ -22560,7 +22440,7 @@ snapshots:
dependencies:
lunr: 2.3.9
marked: 4.3.0
minimatch: 9.0.4
minimatch: 9.0.5
shiki: 0.14.7
typescript: 5.1.6
@ -22901,7 +22781,7 @@ snapshots:
vscode-languageclient@9.0.1:
dependencies:
minimatch: 5.1.2
minimatch: 5.1.6
semver: 7.6.3
vscode-languageserver-protocol: 3.17.5

View file

@ -28,3 +28,4 @@ onlyBuiltDependencies:
- utf-8-validate
- v-code-diff
- vue-demi
ignorePatchFailures: false

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) {