fix storybook lint/built

This commit is contained in:
Hazelnoot 2025-10-07 19:51:28 -04:00
parent 3b2ece2fcf
commit 8a74f79378
18 changed files with 157 additions and 110 deletions

View file

@ -3,10 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { HttpResponse, http } from 'msw';
import { HttpResponse } from 'msw';
import type { DefaultBodyType, HttpResponseResolver, JsonBodyType, PathParams } from 'msw';
import seedrandom from 'seedrandom';
import { action } from '@storybook/addon-actions';
import { action } from 'storybook/actions';
function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] {
const rng = seedrandom(seed);
@ -30,7 +30,9 @@ export function getChartResolver(fields: string[], option?: { accumulate?: boole
action(`GET ${request.url}`)();
const limitParam = new URL(request.url).searchParams.get('limit');
const limit = limitParam ? parseInt(limitParam) : 30;
const res = {};
// What the *fuck* is the type of this object???
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const res: any = {};
for (const field of fields) {
const layers = field.split('.');
let current = res;

View file

@ -220,6 +220,11 @@ export function federationInstance(): entities.FederationInstance {
themeColor: '',
infoUpdatedAt: '',
latestRequestReceivedAt: '',
isMediaSilenced: false,
rejectReports: false,
rejectQuotes: false,
isBubbled: false,
mandatoryCW: null,
};
}
@ -240,6 +245,13 @@ export function note(id = 'somenoteid'): entities.Note {
reactionCount: 0,
renoteCount: 0,
repliesCount: 0,
threadId: '',
userHost: null,
isMutingThread: false,
isMutingNote: false,
isFavorited: false,
isRenoted: false,
bypassSilence: false,
};
}
@ -254,10 +266,27 @@ export function userLite(id = 'someuserid', username = 'miskist', host: entities
avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay',
avatarDecorations: [],
emojis: {},
createdAt: '',
updatedAt: null,
lastFetchedAt: null,
approved: false,
description: null,
isAdmin: false,
isModerator: false,
isSystem: false,
noindex: false,
enableRss: false,
mandatoryCW: null,
isSilenced: false,
bypassSilence: false,
followersCount: 0,
followingCount: 0,
notesCount: 0,
attributionDomains: [],
};
}
export function userDetailed(id = 'someuserid', username = 'miskist', host: entities.UserDetailed['host'] = 'misskey-hub.net', name: entities.UserDetailed['name'] = 'Misskey User'): entities.UserDetailed {
function userDetailed(id = 'someuserid', username = 'miskist', host: entities.UserDetailed['host'] = 'misskey-hub.net', name: entities.UserDetailed['name'] = 'Misskey User'): entities.UserDetailed {
return {
...userLite(id, username, host, name),
bannerBlurhash: 'eQA^IW^-MH8w9tE8I=S^o{$*R4RikXtSxutRozjEnNR.RQadoyozog',
@ -312,9 +341,17 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host: enti
alsoKnownAs: null,
notify: 'none',
memo: null,
backgroundUrl: null,
backgroundId: null,
backgroundBlurhash: null,
listenbrainz: null,
canChat: true,
chatScope: 'none',
};
}
export default userDetailed;
export function inviteCode(isUsed = false, hasExpiration = false, isExpired = false, isCreatedBySystem = false) {
const date = new Date();
const createdAt = new Date();
@ -382,9 +419,10 @@ export function role(params: {
condFormula: {
id: '',
type: 'or',
values: []
values: [],
},
policies: {},
preserveAssignmentOnMoveAccount: true,
};
}

View file

@ -23,7 +23,7 @@ interface ImportDeclaration extends estree.ImportDeclaration {
const generator = {
...GENERATOR,
ImportDeclaration(node: ImportDeclaration, state: State) {
ImportDeclaration(node: ImportDeclaration, state: State): void {
state.write('import ');
if (node.kind === 'type') state.write('type ');
const { specifiers } = node;
@ -63,7 +63,7 @@ const generator = {
state.write(';');
},
SatisfiesExpression(node: SatisfiesExpression, state: State) {
SatisfiesExpression(node: SatisfiesExpression, state: State): void {
switch (node.expression.type) {
case 'ArrowFunctionExpression': {
state.write('(');
@ -72,7 +72,7 @@ const generator = {
break;
}
default: {
// @ts-expect-error ???
// @ts-expect-error Produces "Expression produces a union type that is too complex to represent" for some reason
this[node.expression.type](node.expression, state);
break;
}
@ -94,7 +94,6 @@ type SplitCamel<
: SplitCamel<XR, `${YC}${XH}`, YN>
: YN;
// @ts-expect-error ???
type SplitKebab<T extends string> = T extends `${infer XH}-${infer XR}`
? [XH, ...SplitKebab<XR>]
: [T];
@ -110,7 +109,6 @@ type ToKebab<T extends readonly string[]> = T extends readonly [
? `${XH}${XR extends readonly string[] ? `-${ToKebab<XR>}` : ''}`
: '';
// @ts-expect-error ???
type ToPascal<T extends readonly string[]> = T extends readonly [
infer XH extends string,
...infer XR extends readonly string[]
@ -126,6 +124,7 @@ function h<T extends estree.Node>(
return Object.assign(props || {}, { type }) as T;
}
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace h.JSX {
type Element = estree.Node;
type IntrinsicElements = {

View file

@ -0,0 +1,3 @@
import locales from '../../../locales/index.js';
export default locales['ja-JP'] as const;

View file

@ -7,7 +7,7 @@ import { createRequire } from 'node:module';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { StorybookConfig } from '@storybook/vue3-vite';
import { type Plugin, mergeConfig } from 'vite';
import { mergeConfig } from 'vite';
import turbosnap from 'vite-plugin-turbosnap';
const require = createRequire(import.meta.url);
@ -29,19 +29,20 @@ const config = {
options: {},
},
docs: {
// @ts-expect-error This seems to be wrong, but I can't find what the alternative might be.
autodocs: 'tag',
},
core: {
disableTelemetry: true,
},
async viteFinal(config) {
const replacePluginForIsChromatic = config.plugins?.findIndex((plugin: Plugin) => plugin && plugin.name === 'replace') ?? -1;
const replacePluginForIsChromatic = config.plugins?.findIndex(plugin => plugin && 'name' in plugin && plugin.name === 'replace') ?? -1;
if (~replacePluginForIsChromatic) {
config.plugins?.splice(replacePluginForIsChromatic, 1);
}
//pluginsからcreateSearchIndexを削除、複数あるかもしれないので全て削除
config.plugins = config.plugins?.filter((plugin: Plugin) => plugin && plugin.name !== 'createSearchIndex') ?? [];
config.plugins = config.plugins?.filter(plugin => plugin && 'name' in plugin && plugin.name !== 'createSearchIndex') ?? [];
return mergeConfig(config, {
plugins: [

View file

@ -3,7 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { type SharedOptions, http, HttpResponse } from 'msw';
import { http, HttpResponse } from 'msw';
import type { SharedOptions } from 'msw';
export const onUnhandledRequest = ((req, print) => {
const url = new URL(req.url);

View file

@ -1,3 +0,0 @@
{
"type": "module"
}

View file

@ -7,7 +7,7 @@ import { writeFile } from 'node:fs/promises';
import locales from '../../../locales/index.js';
await writeFile(
new URL('locale.ts', import.meta.url),
`export default ${JSON.stringify(locales['ja-JP'], undefined, 2)} as const;`,
new URL('locale.js', import.meta.url),
`export default ${JSON.stringify(locales['ja-JP'], undefined, 2)};`,
'utf8',
);

View file

@ -34,12 +34,12 @@ const keys = [
await Promise.all(keys.map((key) => readFile(new URL(`../../frontend-shared/themes/${key}.json5`, import.meta.url), 'utf8'))).then((sources) => {
writeFile(
new URL('./themes.ts', import.meta.url),
new URL('./themes.js', import.meta.url),
`export default ${JSON.stringify(
Object.fromEntries(sources.map((source, i) => [keys[i], JSON5.parse(source)])),
undefined,
2,
)} as const;`,
'utf8'
)};`,
'utf8',
);
});

View file

@ -5,13 +5,15 @@
import { FORCE_RE_RENDER, FORCE_REMOUNT } from '@storybook/core-events';
import { addons } from '@storybook/preview-api';
import { type Preview, setup } from '@storybook/vue3';
import { setup } from '@storybook/vue3';
import isChromatic from 'chromatic/isChromatic';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { userDetailed } from './fakes.js';
import userDetailed from './fakes.js';
import locale from './locale.js';
import { commonHandlers, onUnhandledRequest } from './mocks.js';
import themes from './themes.js';
import type { Preview } from '@storybook/vue3';
import type * as MisskeyOS from '../src/os.js';
import '../src/style.scss';
const appInitialized = Symbol();
@ -19,13 +21,13 @@ const appInitialized = Symbol();
let lastStory: string | null = null;
let moduleInitialized = false;
let unobserve = () => {};
let misskeyOS = null;
let misskeyOS: typeof MisskeyOS | null = null;
function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
unobserve();
const theme = themes[window.document.documentElement.dataset.misskeyTheme];
const theme = themes[window.document.documentElement.dataset.misskeyTheme as string];
if (theme) {
applyTheme(themes[window.document.documentElement.dataset.misskeyTheme]);
applyTheme(themes[window.document.documentElement.dataset.misskeyTheme as string]);
} else {
applyTheme(themes['l-light']);
}
@ -33,9 +35,9 @@ function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
for (const entry of entries) {
if (entry.attributeName === 'data-misskey-theme') {
const target = entry.target as HTMLElement;
const theme = themes[target.dataset.misskeyTheme];
const theme = themes[target.dataset.misskeyTheme as string];
if (theme) {
applyTheme(themes[target.dataset.misskeyTheme]);
applyTheme(themes[target.dataset.misskeyTheme as string]);
} else {
target.removeAttribute('style');
}
@ -97,7 +99,7 @@ const preview = {
} else {
lastStory = context.id;
const channel = addons.getChannel();
const resetIndexedDBPromise = globalThis.indexedDB?.databases
const resetIndexedDBPromise = (globalThis.indexedDB as IDBFactory | undefined)?.databases
? indexedDB.databases().then((r) => {
for (let i = 0; i < r.length; i++) {
indexedDB.deleteDatabase(r[i].name!);
@ -105,7 +107,6 @@ const preview = {
}).catch(() => {})
: Promise.resolve();
const resetDefaultStorePromise = import('../src/store').then(({ store }) => {
// @ts-expect-error ???
store.init();
}).catch(() => {});
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {
@ -122,12 +123,12 @@ const preview = {
}
return story;
},
(Story, context) => {
(_, context) => {
return {
setup() {
return {
context,
popups: misskeyOS.popups,
popups: misskeyOS?.popups,
};
},
template:

View file

@ -0,0 +1,3 @@
import type { Theme } from '../src/theme.js';
export default {} as Record<string, Theme>;

View file

@ -1,17 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../tsconfig.vue.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"jsxFactory": "h"
},
"files": [
"./changes.ts",
"./generate.tsx",
"./preload-locale.ts",
"./preload-theme.ts"
]
}

View file

@ -1,9 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"files": [],
// WebStorm only reads one tsconfig per directory, so this tricks it into loading both.
"references": [
{ "path": "./tsconfig.gen.json" },
{ "path": "./tsconfig.vue.json" }
]
}

View file

@ -1,19 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../tsconfig.vue.json",
"compilerOptions": {
"jsx": "preserve"
},
"include": [
"**/*.js",
"**/*.jsx",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"./changes.ts",
"./generate.tsx",
"./preload-locale.ts",
"./preload-theme.ts"
]
}

View file

@ -15,9 +15,14 @@ export default [
},
...pluginVue.configs['flat/recommended'],
{
files: ['{src,test,js,@types}/**/*.{ts,vue}'],
files: ['{src,test,js,@types}/**/*.{ts,vue}', '.storybook/**/*.ts', '.storybook/**/*.tsx', '.storybook/**/*.js', '.storybook/**/*.jsx'],
ignores: [
'*.*',
'.storybook/changes.ts',
'.storybook/main.ts',
'.storybook/generate.tsx',
'.storybook/preload-locale.ts',
'.storybook/preload-theme.ts',
],
plugins: { sharkey: { rules: { locale: localeRule } } },
languageOptions: {
@ -46,7 +51,7 @@ export default [
parserOptions: {
extraFileExtensions: ['.vue'],
parser: tsParser,
project: ['./tsconfig.vue.json'],
project: ['tsconfig.vue.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
@ -173,37 +178,31 @@ export default [
'no-restricted-globals': 'off',
},
},
{
files: ['.storybook/**/*.ts', '.storybook/**/*.tsx', '.storybook/**/*.js', '.storybook/**/*.jsx'],
rules: {
'import/no-default-export': 'off',
'no-restricted-globals': 'off',
},
},
{
files: [
".storybook/changes.ts",
".storybook/generate.tsx",
".storybook/preload-locale.ts",
".storybook/preload-theme.ts"
'.storybook/changes.ts',
'.storybook/main.ts',
'.storybook/generate.tsx',
'.storybook/preload-locale.ts',
'.storybook/preload-theme.ts',
],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['.storybook/tsconfig.gen.json'],
project: ['tsconfig.storybook.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['.storybook/**/*.ts', '.storybook/**/*.tsx', '.storybook/**/*.js', '.storybook/**/*.jsx'],
ignores: [
".storybook/changes.ts",
".storybook/generate.tsx",
".storybook/preload-locale.ts",
".storybook/preload-theme.ts"
],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['.storybook/tsconfig.vue.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
rules: {
'import/no-default-export': 'off',
},
},
{
@ -233,15 +232,15 @@ export default [
},
{
ignores: [
'**/lib/',
'**/temp/',
'**/built/',
'**/coverage/',
'**/node_modules/',
'**/libopenmpt/',
'**/storybook-static/',
'**/lib',
'**/temp',
'**/built',
'**/coverage',
'**/node_modules',
'**/libopenmpt',
'**/storybook-static',
'vue-shims.d.ts',
'assets/'
'assets',
],
},
];

View file

@ -4,6 +4,8 @@
// WebStorm only reads one tsconfig per directory, so this tricks it into loading both.
"references": [
{ "path": "./tsconfig.scripts.json" },
{ "path": "./tsconfig.vue.json" }
{ "path": "./tsconfig.vue.json" },
{ "path": "./tsconfig.vue.storybook.json" },
{ "path": "./tsconfig.storybook.json" }
]
}

View file

@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../shared/tsconfig.node.jsonc",
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h"
},
"files": [
".storybook/changes.ts",
".storybook/main.ts",
".storybook/generate.tsx",
".storybook/preload-locale.ts",
".storybook/preload-theme.ts"
]
}

View file

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.vue.json",
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"include": [
"./lib/**/*.ts",
"./src/**/*.ts",
"./src/**/*.vue",
"./test/**/*.ts",
"./test/**/*.vue",
"./@types/**/*.ts",
"./vue-shims.d.ts",
".storybook/**/*.js",
".storybook/**/*.jsx",
".storybook/**/*.ts",
".storybook/**/*.tsx"
],
"exclude": [
"node_modules",
"eslint.config.js",
"vite.*",
".storybook/changes.ts",
".storybook/main.ts",
".storybook/generate.tsx",
".storybook/preload-locale.ts",
".storybook/preload-theme.ts"
]
}