modernize frontend to target the same ES and TS standards as the rest of the app

This commit is contained in:
Hazelnoot 2025-10-06 00:01:01 -04:00
parent 0a5c9f79e5
commit 22f49db21f
21 changed files with 249 additions and 170 deletions

View file

@ -12,7 +12,7 @@ export const firstNameDict = [
'Ethan', 'Olivia', 'Jackson', 'Emma', 'Liam', 'Ava', 'Aiden', 'Sophia', 'Mason', 'Isabella', 'Ethan', 'Olivia', 'Jackson', 'Emma', 'Liam', 'Ava', 'Aiden', 'Sophia', 'Mason', 'Isabella',
'Noah', 'Mia', 'Lucas', 'Harper', 'Caleb', 'Abigail', 'Samuel', 'Emily', 'Logan', 'Noah', 'Mia', 'Lucas', 'Harper', 'Caleb', 'Abigail', 'Samuel', 'Emily', 'Logan',
'Madison', 'Benjamin', 'Chloe', 'Elijah', 'Grace', 'Alexander', 'Scarlett', 'William', 'Zoey', 'James', 'Lily', 'Madison', 'Benjamin', 'Chloe', 'Elijah', 'Grace', 'Alexander', 'Scarlett', 'William', 'Zoey', 'James', 'Lily',
] ];
/** /**
* AIで生成した無作為なラストネーム * AIで生成した無作為なラストネーム
@ -21,7 +21,7 @@ export const lastNameDict = [
'Anderson', 'Johnson', 'Thompson', 'Davis', 'Rodriguez', 'Smith', 'Patel', 'Williams', 'Lee', 'Brown', 'Anderson', 'Johnson', 'Thompson', 'Davis', 'Rodriguez', 'Smith', 'Patel', 'Williams', 'Lee', 'Brown',
'Garcia', 'Jackson', 'Martinez', 'Taylor', 'Harris', 'Nguyen', 'Miller', 'Jones', 'Wilson', 'Garcia', 'Jackson', 'Martinez', 'Taylor', 'Harris', 'Nguyen', 'Miller', 'Jones', 'Wilson',
'White', 'Thomas', 'Garcia', 'Martinez', 'Robinson', 'Turner', 'Lewis', 'Hall', 'King', 'Baker', 'Cooper', 'White', 'Thomas', 'Garcia', 'Martinez', 'Robinson', 'Turner', 'Lewis', 'Hall', 'King', 'Baker', 'Cooper',
] ];
/** /**
* AIで生成した無作為な国名 * AIで生成した無作為な国名
@ -30,7 +30,7 @@ export const countryDict = [
'Japan', 'Canada', 'Brazil', 'Australia', 'Italy', 'SouthAfrica', 'Mexico', 'Sweden', 'Russia', 'India', 'Japan', 'Canada', 'Brazil', 'Australia', 'Italy', 'SouthAfrica', 'Mexico', 'Sweden', 'Russia', 'India',
'Germany', 'Argentina', 'South Korea', 'France', 'Nigeria', 'Turkey', 'Spain', 'Egypt', 'Thailand', 'Germany', 'Argentina', 'South Korea', 'France', 'Nigeria', 'Turkey', 'Spain', 'Egypt', 'Thailand',
'Vietnam', 'Kenya', 'Saudi Arabia', 'Netherlands', 'Colombia', 'Poland', 'Chile', 'Malaysia', 'Ukraine', 'New Zealand', 'Peru', 'Vietnam', 'Kenya', 'Saudi Arabia', 'Netherlands', 'Colombia', 'Poland', 'Chile', 'Malaysia', 'Ukraine', 'New Zealand', 'Peru',
] ];
export function text(length: number = 10, seed?: string): string { export function text(length: number = 10, seed?: string): string {
let result = ""; let result = "";
@ -140,7 +140,7 @@ export function imageDataUrl(options?: {
throw new Error('Failed to get 2d context'); throw new Error('Failed to get 2d context');
} }
ctx.beginPath() ctx.beginPath();
const red = options?.color?.red ?? integer(0, 255, seed); const red = options?.color?.red ?? integer(0, 255, seed);
const green = options?.color?.green ?? integer(0, 255, seed); const green = options?.color?.green ?? integer(0, 255, seed);

View file

@ -4,7 +4,7 @@
*/ */
import { AISCRIPT_VERSION } from '@syuilo/aiscript'; import { AISCRIPT_VERSION } from '@syuilo/aiscript';
import type { entities } from 'misskey-js' import type { entities } from 'misskey-js';
import { date, imageDataUrl, text } from "./fake-utils.js"; import { date, imageDataUrl, text } from "./fake-utils.js";
export function abuseUserReport() { export function abuseUserReport() {
@ -124,7 +124,7 @@ export function galleryPost(isSensitive = false) {
isSensitive, isSensitive,
likedCount: 0, likedCount: 0,
isLiked: false, isLiked: false,
} };
} }
export function file(isSensitive = false) { export function file(isSensitive = false) {
@ -318,13 +318,13 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host: enti
export function inviteCode(isUsed = false, hasExpiration = false, isExpired = false, isCreatedBySystem = false) { export function inviteCode(isUsed = false, hasExpiration = false, isExpired = false, isCreatedBySystem = false) {
const date = new Date(); const date = new Date();
const createdAt = new Date(); const createdAt = new Date();
createdAt.setDate(date.getDate() - 1) createdAt.setDate(date.getDate() - 1);
const expiresAt = new Date(); const expiresAt = new Date();
if (isExpired) { if (isExpired) {
expiresAt.setHours(date.getHours() - 1) expiresAt.setHours(date.getHours() - 1);
} else { } else {
expiresAt.setHours(date.getHours() + 1) expiresAt.setHours(date.getHours() + 1);
} }
return { return {
@ -336,7 +336,7 @@ export function inviteCode(isUsed = false, hasExpiration = false, isExpired = fa
usedBy: isUsed ? userDetailed('3i3r2znx1v') : null, usedBy: isUsed ? userDetailed('3i3r2znx1v') : null,
usedAt: isUsed ? date.toISOString() : null, usedAt: isUsed ? date.toISOString() : null,
used: isUsed, used: isUsed,
} };
} }
export function role(params: { export function role(params: {
@ -385,7 +385,7 @@ export function role(params: {
values: [] values: []
}, },
policies: {}, policies: {},
} };
} }
export function emoji(params?: { export function emoji(params?: {
@ -401,7 +401,7 @@ export function emoji(params?: {
license?: string, license?: string,
isSensitive?: boolean, isSensitive?: boolean,
localOnly?: boolean, localOnly?: boolean,
roleIdsThatCanBeUsedThisEmojiAsReaction?: {id:string, name:string}[], roleIdsThatCanBeUsedThisEmojiAsReaction?: { id: string, name: string }[],
updatedAt?: string, updatedAt?: string,
}, seed?: string): entities.EmojiDetailedAdmin { }, seed?: string): entities.EmojiDetailedAdmin {
const _seed = seed ?? (params?.id ?? "DEFAULT_SEED"); const _seed = seed ?? (params?.id ?? "DEFAULT_SEED");
@ -409,7 +409,7 @@ export function emoji(params?: {
const name = params?.name ?? text(8, _seed); const name = params?.name ?? text(8, _seed);
const updatedAt = params?.updatedAt ?? date({}, _seed).toISOString(); const updatedAt = params?.updatedAt ?? date({}, _seed).toISOString();
const image = imageDataUrl({}, _seed) const image = imageDataUrl({}, _seed);
return { return {
id: id, id: id,
@ -426,5 +426,5 @@ export function emoji(params?: {
localOnly: params?.localOnly ?? false, localOnly: params?.localOnly ?? false,
roleIdsThatCanBeUsedThisEmojiAsReaction: params?.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [], roleIdsThatCanBeUsedThisEmojiAsReaction: params?.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [],
updatedAt: updatedAt, updatedAt: updatedAt,
} };
} }

View file

@ -72,7 +72,7 @@ const generator = {
break; break;
} }
default: { default: {
// @ts-ignore // @ts-expect-error ???
this[node.expression.type](node.expression, state); this[node.expression.type](node.expression, state);
break; break;
} }
@ -94,7 +94,7 @@ type SplitCamel<
: SplitCamel<XR, `${YC}${XH}`, YN> : SplitCamel<XR, `${YC}${XH}`, YN>
: YN; : YN;
// @ts-ignore // @ts-expect-error ???
type SplitKebab<T extends string> = T extends `${infer XH}-${infer XR}` type SplitKebab<T extends string> = T extends `${infer XH}-${infer XR}`
? [XH, ...SplitKebab<XR>] ? [XH, ...SplitKebab<XR>]
: [T]; : [T];
@ -110,7 +110,7 @@ type ToKebab<T extends readonly string[]> = T extends readonly [
? `${XH}${XR extends readonly string[] ? `-${ToKebab<XR>}` : ''}` ? `${XH}${XR extends readonly string[] ? `-${ToKebab<XR>}` : ''}`
: ''; : '';
// @ts-ignore // @ts-expect-error ???
type ToPascal<T extends readonly string[]> = T extends readonly [ type ToPascal<T extends readonly string[]> = T extends readonly [
infer XH extends string, infer XH extends string,
...infer XR extends readonly string[] ...infer XR extends readonly string[]
@ -474,5 +474,5 @@ function toStories(component: string): Promise<string> {
await Promise.all(components.map(async (component) => { await Promise.all(components.map(async (component) => {
const stories = component.replace(/\.vue$/, '.stories.ts'); const stories = component.replace(/\.vue$/, '.stories.ts');
await writeFile(stories, await toStories(component)); await writeFile(stories, await toStories(component));
})) }));
})(); })();

View file

@ -8,9 +8,9 @@ import { type SharedOptions, http, HttpResponse } from 'msw';
export const onUnhandledRequest = ((req, print) => { export const onUnhandledRequest = ((req, print) => {
const url = new URL(req.url); const url = new URL(req.url);
if (url.hostname !== 'localhost' || /^\/(?:client-assets\/|fluent-emojis?\/|iframe.html$|node_modules\/|src\/|sb-|static-assets\/|vite\/)/.test(url.pathname)) { if (url.hostname !== 'localhost' || /^\/(?:client-assets\/|fluent-emojis?\/|iframe.html$|node_modules\/|src\/|sb-|static-assets\/|vite\/)/.test(url.pathname)) {
return return;
} }
print.warning() print.warning();
}) satisfies SharedOptions['onUnhandledRequest']; }) satisfies SharedOptions['onUnhandledRequest'];
export const commonHandlers = [ export const commonHandlers = [

View file

@ -10,4 +10,4 @@ await writeFile(
new URL('locale.ts', import.meta.url), new URL('locale.ts', import.meta.url),
`export default ${JSON.stringify(locales['ja-JP'], undefined, 2)} as const;`, `export default ${JSON.stringify(locales['ja-JP'], undefined, 2)} as const;`,
'utf8', 'utf8',
) );

View file

@ -30,7 +30,7 @@ const keys = [
'd-u0', 'd-u0',
'rosepine', 'rosepine',
'rosepine-dawn', 'rosepine-dawn',
] ];
await Promise.all(keys.map((key) => readFile(new URL(`../../frontend-shared/themes/${key}.json5`, import.meta.url), 'utf8'))).then((sources) => { await Promise.all(keys.map((key) => readFile(new URL(`../../frontend-shared/themes/${key}.json5`, import.meta.url), 'utf8'))).then((sources) => {
writeFile( writeFile(

View file

@ -99,13 +99,13 @@ const preview = {
const channel = addons.getChannel(); const channel = addons.getChannel();
const resetIndexedDBPromise = globalThis.indexedDB?.databases const resetIndexedDBPromise = globalThis.indexedDB?.databases
? indexedDB.databases().then((r) => { ? indexedDB.databases().then((r) => {
for (var i = 0; i < r.length; i++) { for (let i = 0; i < r.length; i++) {
indexedDB.deleteDatabase(r[i].name!); indexedDB.deleteDatabase(r[i].name!);
} }
}).catch(() => {}) }).catch(() => {})
: Promise.resolve(); : Promise.resolve();
const resetDefaultStorePromise = import('../src/store').then(({ store }) => { const resetDefaultStorePromise = import('../src/store').then(({ store }) => {
// @ts-expect-error // @ts-expect-error ???
store.init(); store.init();
}).catch(() => {}); }).catch(() => {});
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => { Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {

View file

@ -0,0 +1,17 @@
{
"$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,31 +1,9 @@
{ {
"compilerOptions": { "$schema": "https://json.schemastore.org/tsconfig",
"target": "es2022", "files": [],
"module": "Node16", // WebStorm only reads one tsconfig per directory, so this tricks it into loading both.
"strict": true, "references": [
"allowUnusedLabels": false, { "path": "./tsconfig.gen.json" },
"allowUnreachableCode": false, { "path": "./tsconfig.vue.json" }
"exactOptionalPropertyTypes": true,
"noEmitOnError": false,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"checkJs": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"jsx": "react",
"jsxFactory": "h"
},
"files": [
"./changes.ts",
"./generate.tsx",
"./preload-locale.ts",
"./preload-theme.ts"
] ]
} }

View file

@ -0,0 +1,19 @@
{
"$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

@ -16,6 +16,9 @@ export default [
...pluginVue.configs['flat/recommended'], ...pluginVue.configs['flat/recommended'],
{ {
files: ['{src,test,js,@types}/**/*.{ts,vue}'], files: ['{src,test,js,@types}/**/*.{ts,vue}'],
ignores: [
'*.*',
],
plugins: { sharkey: { rules: { locale: localeRule } } }, plugins: { sharkey: { rules: { locale: localeRule } } },
languageOptions: { languageOptions: {
globals: { globals: {
@ -43,7 +46,7 @@ export default [
parserOptions: { parserOptions: {
extraFileExtensions: ['.vue'], extraFileExtensions: ['.vue'],
parser: tsParser, parser: tsParser,
project: ['./tsconfig.json'], project: ['./tsconfig.vue.json'],
sourceType: 'module', sourceType: 'module',
tsconfigRootDir: import.meta.dirname, tsconfigRootDir: import.meta.dirname,
}, },
@ -168,18 +171,77 @@ export default [
files: ['src/**/*.stories.ts'], files: ['src/**/*.stories.ts'],
rules: { rules: {
'no-restricted-globals': 'off', 'no-restricted-globals': 'off',
} },
},
{
files: [
".storybook/changes.ts",
".storybook/generate.tsx",
".storybook/preload-locale.ts",
".storybook/preload-theme.ts"
],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['.storybook/tsconfig.gen.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,
},
},
},
{
files: ['test/**/*.ts', 'test/**/*.js'],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['test/tsconfig.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
},
},
{
files: ['*.js', '*.ts', 'lib/**/*.ts', 'lib/**/*.js'],
languageOptions: {
parserOptions: {
parser: tsParser,
project: ['./tsconfig.scripts.json'],
sourceType: 'module',
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'import/no-default-export': 'off',
},
}, },
{ {
ignores: [ ignores: [
"**/lib/", '**/lib/',
"**/temp/", '**/temp/',
"**/built/", '**/built/',
"**/coverage/", '**/coverage/',
"**/node_modules/", '**/node_modules/',
"**/libopenmpt/", '**/libopenmpt/',
"**/storybook-static/", '**/storybook-static/',
"*.*", 'vue-shims.d.ts',
] 'assets/'
],
}, },
]; ];

View file

@ -8,6 +8,7 @@ import { walk } from '../node_modules/estree-walker/src/index.js';
import type * as estree from 'estree'; import type * as estree from 'estree';
import type * as estreeWalker from 'estree-walker'; import type * as estreeWalker from 'estree-walker';
import type { Plugin } from 'vite'; import type { Plugin } from 'vite';
import type { Identifier } from 'estree';
function isFalsyIdentifier(identifier: estree.Identifier): boolean { function isFalsyIdentifier(identifier: estree.Identifier): boolean {
return identifier.name === 'undefined' || identifier.name === 'NaN'; return identifier.name === 'undefined' || identifier.name === 'NaN';
@ -382,7 +383,7 @@ export function unwindCssModuleClassName(ast: estree.Node): void {
if (childNode.name !== ident) return; if (childNode.name !== ident) return;
this.replace({ this.replace({
type: 'Identifier', type: 'Identifier',
name: node.declarations[0].id.name, name: (node.declarations[0].id as Identifier).name,
}); });
}, },
}); });
@ -432,6 +433,7 @@ export function unwindCssModuleClassName(ast: estree.Node): void {
type: 'ArrayExpression', type: 'ArrayExpression',
elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)), elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)),
}], }],
optional: false,
}, },
}], }],
kind: 'const', kind: 'const',

View file

@ -3,12 +3,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
/// <reference lib="esnext" />
import { parse as vueSfcParse } from 'vue/compiler-sfc'; import { parse as vueSfcParse } from 'vue/compiler-sfc';
import { import {
createLogger, createLogger,
EnvironmentModuleGraph, type EnvironmentModuleGraph,
type LogErrorOptions, type LogErrorOptions,
type LogOptions, type LogOptions,
normalizePath, normalizePath,
@ -20,7 +18,7 @@ import { glob } from 'glob';
import JSON5 from 'json5'; import JSON5 from 'json5';
import MagicString, { SourceMap } 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.js';
import { minimatch } from 'minimatch'; import { minimatch } from 'minimatch';
import { import {
type AttributeNode, type AttributeNode,
@ -63,7 +61,7 @@ interface MarkerRelation {
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?: LogErrorOptions | unknown) => { }, error: (msg: string, options?: LogErrorOptions) => { },
}; };
let loggerInitialized = false; let loggerInitialized = false;
@ -470,7 +468,11 @@ export function collectFileMarkers(id: string, code: string): SearchIndexItem[]
return extractUsageInfoFromTemplateAst(descriptor.template?.ast, id); return extractUsageInfoFromTemplateAst(descriptor.template?.ast, id);
} catch (error) { } catch (error) {
logger.error(`Error analyzing file ${id}:`, error); logger.error(`Error analyzing file ${id}:`, {
error: error instanceof Error
? error
: new Error(`Unknown error of type ${typeof(error)}`, { cause: error }),
});
} }
return []; return [];

View file

@ -11,8 +11,12 @@
"chromatic": "chromatic", "chromatic": "chromatic",
"test": "vitest --run --globals", "test": "vitest --run --globals",
"test-and-coverage": "vitest --run --coverage --globals", "test-and-coverage": "vitest --run --coverage --globals",
"typecheck": "vue-tsc --noEmit", "typecheck-all": "pnpm run --no-bail typecheck:vue && pnpm run --no-bail typecheck:test && pnpm run --no-bail typecheck:scripts",
"eslint": "eslint --quiet \"{src,test,js,@types}/**/*.{js,jsx,ts,tsx,vue}\" --cache", "typecheck": "pnpm run typecheck:vue && pnpm run typecheck:test && pnpm run typecheck:scripts",
"typecheck:vue": "vue-tsc -p tsconfig.vue.json --noEmit",
"typecheck:test": "vue-tsc -p test/tsconfig.json --noEmit",
"typecheck:scripts": "tsc -p tsconfig.scripts.json --noEmit",
"eslint": "eslint --quiet --cache -c eslint.config.js .",
"lint": "pnpm typecheck && pnpm eslint" "lint": "pnpm typecheck && pnpm eslint"
}, },
"dependencies": { "dependencies": {
@ -58,7 +62,6 @@
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"throttle-debounce": "5.0.2", "throttle-debounce": "5.0.2",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"typescript": "5.9.2",
"uuid": "13.0.0", "uuid": "13.0.0",
"v-code-diff": "1.13.1", "v-code-diff": "1.13.1",
"vue": "3.5.21", "vue": "3.5.21",
@ -69,6 +72,7 @@
"cypress": "15.3.0" "cypress": "15.3.0"
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@misskey-dev/summaly": "npm:@transfem-org/summaly@5.2.3", "@misskey-dev/summaly": "npm:@transfem-org/summaly@5.2.3",
"@rollup/plugin-json": "6.1.0", "@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.2", "@rollup/plugin-replace": "6.0.2",
@ -138,6 +142,7 @@
"three": "0.180.0", "three": "0.180.0",
"tsc-alias": "1.8.16", "tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"typescript": "5.9.2",
"vite": "7.1.7", "vite": "7.1.7",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vitest": "3.2.4", "vitest": "3.2.4",

View file

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"lib": ["esnext", "webworker"], "lib": ["ES2022", "WebWorker", "Webworker.Iterable"],
"incremental": true "incremental": true
} }
} }

View file

@ -1,29 +1,9 @@
{ {
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../tsconfig.vue.json",
"compilerOptions": { "compilerOptions": {
"allowJs": true, "module": "NodeNext",
"noEmitOnError": false, "moduleResolution": "NodeNext",
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedParameters": false,
"noUnusedLocals": true,
"noFallthroughCasesInSwitch": true,
"declaration": false,
"sourceMap": true,
"target": "ES2022",
"module": "nodenext",
"moduleResolution": "nodenext",
"allowSyntheticDefaultImports": true,
"removeComments": false,
"noLib": false,
"strict": true,
"strictNullChecks": true,
"strictPropertyInitialization": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"resolveJsonModule": true,
"isolatedModules": true,
"skipLibCheck": true,
"incremental": true,
"baseUrl": "./", "baseUrl": "./",
"paths": { "paths": {
"@/*": ["../src/*"] "@/*": ["../src/*"]
@ -31,13 +11,8 @@
"typeRoots": [ "typeRoots": [
"../node_modules/@types" "../node_modules/@types"
], ],
"lib": [
"esnext",
"dom"
],
"types": ["node"] "types": ["node"]
}, },
"compileOnSave": false,
"include": [ "include": [
"./**/*.ts", "./**/*.ts",
"../src/**/*.vue" "../src/**/*.vue"

View file

@ -1,62 +1,9 @@
{ {
"compilerOptions": { "$schema": "https://json.schemastore.org/tsconfig",
"allowJs": true, "files": [],
"noEmitOnError": false, // WebStorm only reads one tsconfig per directory, so this tricks it into loading both.
"noImplicitAny": false, "references": [
"noImplicitReturns": true, { "path": "./tsconfig.scripts.json" },
"noUnusedParameters": false, { "path": "./tsconfig.vue.json" }
"noUnusedLocals": false,
"noFallthroughCasesInSwitch": true,
"declaration": false,
"sourceMap": false,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "Bundler",
"removeComments": false,
"noLib": false,
"strict": true,
"strictNullChecks": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"useDefineForClassFields": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@@/*": ["../frontend-shared/*"]
},
"typeRoots": [
"./@types",
"./node_modules/@types",
"./node_modules/@vue-macros",
"./node_modules"
],
"types": [
"vite/client",
"vitest/importMeta",
],
"lib": [
"esnext",
"dom",
"dom.iterable"
],
"jsx": "preserve"
},
"compileOnSave": false,
"include": [
"./lib/**/*.ts",
"./src/**/*.ts",
"./src/**/*.vue",
"./test/**/*.ts",
"./test/**/*.vue",
"./@types/**/*.ts"
],
"exclude": [
"node_modules",
".storybook/**/*"
] ]
} }

View file

@ -0,0 +1,26 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../shared/tsconfig.node.json",
"compilerOptions": {
"noImplicitAny": false,
"typeRoots": [
"./node_modules/@types",
"./node_modules"
],
"types": [
"vite/client",
"vitest/importMeta",
]
},
"include": [
"*.js",
"*.ts",
"lib/**/*.ts",
"lib/**/*.js"
],
"exclude": [
"node_modules",
".storybook/**/*",
"vue-shims.d.ts"
]
}

View file

@ -0,0 +1,35 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../shared/tsconfig.web.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"@@/*": ["../frontend-shared/*"]
},
"typeRoots": [
"./@types",
"./node_modules/@types",
"./node_modules/@vue-macros",
"./node_modules"
],
"types": [
"vite/client",
"vitest/importMeta"
],
"jsx": "preserve"
},
"include": [
"./lib/**/*.ts",
"./src/**/*.ts",
"./src/**/*.vue",
"./test/**/*.ts",
"./test/**/*.vue",
"./@types/**/*.ts",
"./vue-shims.d.ts"
],
"exclude": [
"node_modules",
".storybook/**/*",
"*.*"
]
}

View file

@ -2,20 +2,24 @@ import path from 'path';
import pluginReplace from '@rollup/plugin-replace'; import pluginReplace from '@rollup/plugin-replace';
import pluginVue from '@vitejs/plugin-vue'; import pluginVue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
import type { UserConfig } from 'vite'; import { pluginReplaceIcons } from 'frontend-shared/util/vite.replaceIcons.js';
import locales from '../../locales/index.js'; import locales from '../../locales/index.js';
import { localesVersion } from '../../locales/version.js'; import { localesVersion } from '../../locales/version.js';
import meta from '../../package.json'; import meta from '../../package.json' with { type: 'json' };
import packageInfo from './package.json' with { type: 'json' }; import packageInfo from './package.json' with { type: 'json' };
import tsconfigVue from './tsconfig.vue.json' with { type: 'json' };
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js'; import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
import pluginJson5 from './vite.json5.js'; import pluginJson5 from './vite.json5.js';
import pluginCreateSearchIndex from './lib/vite-plugin-create-search-index.js'; import pluginCreateSearchIndex from './lib/vite-plugin-create-search-index.js';
import type { TsconfigRaw } from 'esbuild';
import type { UserConfig } from 'vite';
import type { Options as SearchIndexOptions } from './lib/vite-plugin-create-search-index.js'; import type { Options as SearchIndexOptions } from './lib/vite-plugin-create-search-index.js';
import { pluginReplaceIcons } from './vite.replaceIcons.js';
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue', '.wasm']; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue', '.wasm'];
// https://github.com/rollup/plugins/issues/1541#issuecomment-3114729017
const fix = <T>(f: { default: T }): T => f as unknown as T;
/** /**
* *
*/ */
@ -110,7 +114,7 @@ export function getConfig(): UserConfig {
...pluginReplaceIcons(), ...pluginReplaceIcons(),
...process.env.NODE_ENV === 'production' ...process.env.NODE_ENV === 'production'
? [ ? [
pluginReplace({ fix(pluginReplace)({
preventAssignment: true, preventAssignment: true,
values: { values: {
'isChromatic()': JSON.stringify(false), 'isChromatic()': JSON.stringify(false),
@ -143,6 +147,7 @@ export function getConfig(): UserConfig {
}, },
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {
// @ts-expect-error This produces an error, but all example code has it
api: 'modern-compiler', api: 'modern-compiler',
}, },
}, },
@ -160,7 +165,13 @@ export function getConfig(): UserConfig {
_DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'), _DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'),
__VUE_OPTIONS_API__: true, __VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false, __VUE_PROD_DEVTOOLS__: false,
_RUFFLE_VERSION_: JSON.stringify(packageInfo.dependencies['@ruffle-rs/ruffle']) _RUFFLE_VERSION_: JSON.stringify(packageInfo.dependencies['@ruffle-rs/ruffle']),
},
esbuild: {
// https://github.com/vitejs/vite/discussions/8483#discussioncomment-14485974
// https://esbuild.github.io/api/#tsconfig-raw
tsconfigRaw: tsconfigVue as TsconfigRaw,
}, },
build: { build: {

View file

@ -1,9 +1,9 @@
// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json // Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json
import JSON5 from 'json5'; import JSON5 from 'json5';
import { Plugin } from 'rollup'; import type { Plugin } from 'rollup';
import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { createFilter, dataToEsm } from '@rollup/pluginutils';
import { RollupJsonOptions } from '@rollup/plugin-json'; import type { RollupJsonOptions } from '@rollup/plugin-json';
// json5 extends SyntaxError with additional fields (without subclassing) // json5 extends SyntaxError with additional fields (without subclassing)
// https://github.com/json5/json5/blob/de344f0619bda1465a6e25c76f1c0c3dda8108d9/lib/parse.js#L1111-L1112 // https://github.com/json5/json5/blob/de344f0619bda1465a6e25c76f1c0c3dda8108d9/lib/parse.js#L1111-L1112