Lint and so on

This commit is contained in:
2025-12-03 11:36:00 +01:00
parent e3c437c027
commit 38b0bc0437
23 changed files with 1315 additions and 185 deletions

2
.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
dist
pnpm-lock.yaml

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"useTabs": true,
"singleQuote": true
}

View File

@@ -1,3 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode"]
"recommendations": ["svelte.svelte-vscode"]
}

View File

@@ -42,6 +42,6 @@ If you have state that's important to retain within a component, consider creati
```ts
// store.ts
// An extremely simple external store
import { writable } from 'svelte/store'
export default writable(0)
import { writable } from 'svelte/store';
export default writable(0);
```

40
eslint.config.js Normal file
View File

@@ -0,0 +1,40 @@
import js from '@eslint/js';
import ts from 'typescript-eslint';
import svelte from 'eslint-plugin-svelte';
import prettier from 'eslint-config-prettier';
import globals from 'globals';
export default ts.config(
js.configs.recommended,
...ts.configs.recommended,
...svelte.configs['flat/recommended'],
prettier,
...svelte.configs['flat/prettier'],
{
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},
{
files: ['**/*.svelte', '**/*.svelte.ts'],
languageOptions: {
parserOptions: {
parser: ts.parser,
extraFileExtensions: ['.svelte'],
},
},
},
{
files: ['**/*.svelte.ts'],
languageOptions: {
parser: ts.parser,
},
},
{ ignores: ['dist/'] },
);

View File

@@ -1,13 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>buboard</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>buboard</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,41 +1,50 @@
{
"name": "buboard",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tsconfig/svelte": "^5.0.6",
"@types/node": "^24.10.1",
"svelte": "^5.43.8",
"svelte-check": "^4.3.4",
"typescript": "~5.9.3",
"vite": "npm:rolldown-vite@7.2.5"
},
"pnpm": {
"overrides": {
"vite": "npm:rolldown-vite@7.2.5"
}
},
"dependencies": {
"@codemirror/commands": "^6.10.0",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-html": "^6.4.11",
"@codemirror/language": "^6.11.3",
"@codemirror/state": "^6.5.2",
"@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.38.8",
"@lezer/highlight": "^1.2.3",
"@replit/codemirror-emacs": "^6.1.0",
"@replit/codemirror-vim": "^6.3.0",
"codemirror": "^6.0.2",
"jszip": "^3.10.1",
"lucide-svelte": "^0.555.0"
}
"name": "buboard",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json",
"lint": "eslint .",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tsconfig/svelte": "^5.0.6",
"@types/node": "^24.10.1",
"eslint": "^9.39.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.13.0",
"globals": "^16.5.0",
"prettier": "^3.7.4",
"svelte": "^5.43.8",
"svelte-check": "^4.3.4",
"typescript": "~5.9.3",
"typescript-eslint": "^8.48.1",
"vite": "npm:rolldown-vite@7.2.5"
},
"pnpm": {
"overrides": {
"vite": "npm:rolldown-vite@7.2.5"
}
},
"dependencies": {
"@codemirror/commands": "^6.10.0",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-html": "^6.4.11",
"@codemirror/language": "^6.11.3",
"@codemirror/state": "^6.5.2",
"@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.38.8",
"@lezer/highlight": "^1.2.3",
"@replit/codemirror-emacs": "^6.1.0",
"@replit/codemirror-vim": "^6.3.0",
"codemirror": "^6.0.2",
"jszip": "^3.10.1",
"lucide-svelte": "^0.555.0"
}
}

997
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@
</script>
<svelte:head>
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html `<style>${appState.manifest.appCss}</style>`}
</svelte:head>
@@ -65,7 +66,7 @@
<button class="show-ui" onclick={() => (interfaceHidden = false)} title="Show interface">
<Eye size={14} />
</button>
{#each ['1', '2', '3', '4', '5', '6', '7', '8', '9'] as key}
{#each ['1', '2', '3', '4', '5', '6', '7', '8', '9'] as key (key)}
<button
class="flag"
class:filled={appState.hasFlag(key)}

View File

@@ -1,6 +1,7 @@
@font-face {
font-family: 'Departure Mono';
src: url('/fonts/DepartureMono-Regular.woff2') format('woff2'),
src:
url('/fonts/DepartureMono-Regular.woff2') format('woff2'),
url('/fonts/DepartureMono-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { SvelteMap } from 'svelte/reactivity';
import type { Item } from './types';
import { state as appState } from './state.svelte';
import { calculateCenterOffset, constrainToAspectRatio } from './geometry';
@@ -11,7 +12,7 @@
let isResizing = $state(false);
let isRotating = $state(false);
let dragStart = { x: 0, y: 0, itemX: 0, itemY: 0 };
let dragStartPositions: Map<string, { x: number; y: number }> = new Map();
let dragStartPositions: SvelteMap<string, { x: number; y: number }> = new SvelteMap();
let resizeStart = { x: 0, y: 0, width: 0, height: 0, itemX: 0, itemY: 0, corner: '', aspectRatio: 1 };
let rotateStart = { angle: 0, startAngle: 0 };
@@ -55,7 +56,7 @@
itemX: item.x,
itemY: item.y
};
dragStartPositions = new Map();
dragStartPositions = new SvelteMap();
for (const id of appState.selectedIds) {
const selectedItem = appState.getItem(id);
if (selectedItem) {

View File

@@ -92,7 +92,7 @@
const x = -state.viewport.x / state.viewport.zoom + 400;
const y = -state.viewport.y / state.viewport.zoom + 300;
const img = new Image();
const img = document.createElement('img');
img.onload = () => {
state.addAsset(assetId, { blob: file, url, filename: file.name });
state.addItem({

View File

@@ -64,7 +64,7 @@
<span class="app-name">Buboard</span>
<Palette />
<div class="flags">
{#each flagKeys as key}
{#each flagKeys as key (key)}
<button
class="flag"
class:filled={state.hasFlag(key)}

View File

@@ -7,7 +7,7 @@ export function calculateCenterOffset(
corner: string,
deltaWidth: number,
deltaHeight: number,
rotation: number
rotation: number,
): Point {
const rad = (rotation * Math.PI) / 180;
const cos = Math.cos(rad);
@@ -24,14 +24,14 @@ export function calculateCenterOffset(
return {
x: localDx * cos - localDy * sin,
y: localDx * sin + localDy * cos
y: localDx * sin + localDy * cos,
};
}
export function constrainToAspectRatio(
newWidth: number,
newHeight: number,
aspectRatio: number
aspectRatio: number,
): { width: number; height: number } {
const newRatio = newWidth / newHeight;
@@ -47,13 +47,13 @@ export function detectRotationCorner(
localY: number,
halfWidth: number,
halfHeight: number,
zoneRadius: number
zoneRadius: number,
): string | null {
const corners: Record<string, Point> = {
nw: { x: -halfWidth, y: -halfHeight },
ne: { x: halfWidth, y: -halfHeight },
sw: { x: -halfWidth, y: halfHeight },
se: { x: halfWidth, y: halfHeight }
se: { x: halfWidth, y: halfHeight },
};
const isInsideBounds =
@@ -71,8 +71,10 @@ export function detectRotationCorner(
if (dist > zoneRadius || dist < 3) continue;
const isOutwardX = (name.includes('w') && dx < 0) || (name.includes('e') && dx > 0);
const isOutwardY = (name.includes('n') && dy < 0) || (name.includes('s') && dy > 0);
const isOutwardX =
(name.includes('w') && dx < 0) || (name.includes('e') && dx > 0);
const isOutwardY =
(name.includes('n') && dy < 0) || (name.includes('s') && dy > 0);
if (isOutwardX || isOutwardY) return name;
}

View File

@@ -2,7 +2,10 @@ import JSZip from 'jszip';
import type { Manifest, AssetStore } from './types';
import { state } from './state.svelte';
export async function exportBoard(): Promise<{ success: boolean; error?: string }> {
export async function exportBoard(): Promise<{
success: boolean;
error?: string;
}> {
try {
const zip = new JSZip();
const assetsFolder = zip.folder('assets');
@@ -12,7 +15,7 @@ export async function exportBoard(): Promise<{ success: boolean; error?: string
version: 1,
items: state.manifest.items.map((item) => ({ ...item })),
sharedCss: state.manifest.sharedCss,
appCss: state.manifest.appCss
appCss: state.manifest.appCss,
};
for (const item of exportManifest.items) {
@@ -31,7 +34,7 @@ export async function exportBoard(): Promise<{ success: boolean; error?: string
const blob = await zip.generateAsync({
type: 'blob',
compression: 'DEFLATE',
compressionOptions: { level: 9 }
compressionOptions: { level: 9 },
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
@@ -41,28 +44,35 @@ export async function exportBoard(): Promise<{ success: boolean; error?: string
URL.revokeObjectURL(url);
return { success: true };
} catch (e) {
return { success: false, error: e instanceof Error ? e.message : 'Export failed' };
return {
success: false,
error: e instanceof Error ? e.message : 'Export failed',
};
}
}
export async function importBoard(file: File): Promise<{ success: boolean; error?: string }> {
export async function importBoard(
file: File,
): Promise<{ success: boolean; error?: string }> {
try {
const zip = await JSZip.loadAsync(file);
const manifestFile = zip.file('manifest.json');
if (!manifestFile) throw new Error('Invalid .bub file: missing manifest.json');
if (!manifestFile)
throw new Error('Invalid .bub file: missing manifest.json');
const manifestJson = await manifestFile.async('string');
const raw = JSON.parse(manifestJson);
if (raw.version !== 1) throw new Error(`Unsupported manifest version: ${raw.version}`);
if (raw.version !== 1)
throw new Error(`Unsupported manifest version: ${raw.version}`);
const manifest: Manifest = {
version: 1,
items: raw.items,
sharedCss: raw.sharedCss ?? '',
appCss: raw.appCss ?? '',
flags: raw.flags ?? {}
flags: raw.flags ?? {},
};
const assets: AssetStore = {};
@@ -70,7 +80,9 @@ export async function importBoard(file: File): Promise<{ success: boolean; error
for (const item of manifest.items) {
if (item.assetId) {
const assetFiles = zip.folder('assets')?.file(new RegExp(`^${item.assetId}\\.`));
const assetFiles = zip
.folder('assets')
?.file(new RegExp(`^${item.assetId}\\.`));
if (assetFiles && assetFiles.length > 0) {
const assetFile = assetFiles[0];
const blob = await assetFile.async('blob');
@@ -92,6 +104,9 @@ export async function importBoard(file: File): Promise<{ success: boolean; error
state.load(manifest, assets);
return { success: true };
} catch (e) {
return { success: false, error: e instanceof Error ? e.message : 'Import failed' };
return {
success: false,
error: e instanceof Error ? e.message : 'Import failed',
};
}
}

View File

@@ -1,4 +1,5 @@
import type { Item, Manifest, Asset, AssetStore, Viewport, PositionFlag } from './types';
import { SvelteSet } from 'svelte/reactivity';
import type { Item, Manifest, Asset, AssetStore, Viewport } from './types';
const STORAGE_KEY = 'buboard';
@@ -68,11 +69,11 @@ function createState() {
items: [],
sharedCss: DEFAULT_SHARED_CSS,
appCss: DEFAULT_APP_CSS,
flags: {}
flags: {},
});
let assets = $state<AssetStore>({});
let viewport = $state<Viewport>({ x: 0, y: 0, zoom: 1 });
let selectedIds = $state<Set<string>>(new Set());
let selectedIds = new SvelteSet<string>();
let editingId = $state<string | null>(null);
let editingGlobal = $state<boolean>(false);
let focusedId = $state<string | null>(null);
@@ -81,8 +82,10 @@ function createState() {
let saveTimeout: ReturnType<typeof setTimeout> | null = null;
let animationId: number | null = null;
let maxZIndex = $derived(
manifest.items.length > 0 ? Math.max(...manifest.items.map((i) => i.zIndex)) : 0
const maxZIndex = $derived(
manifest.items.length > 0
? Math.max(...manifest.items.map((i) => i.zIndex))
: 0,
);
async function save() {
@@ -92,7 +95,7 @@ function createState() {
for (const [id, asset] of Object.entries(assets)) {
storedAssets[id] = {
dataUrl: await blobToDataUrl(asset.blob),
filename: asset.filename
filename: asset.filename,
};
}
const stored: StoredState = { manifest, assets: storedAssets };
@@ -168,11 +171,11 @@ function createState() {
}
function select(id: string | null) {
selectedIds = new Set(id ? [id] : []);
selectedIds = new SvelteSet(id ? [id] : []);
}
function toggleSelection(id: string) {
const newSet = new Set(selectedIds);
const newSet = new SvelteSet(selectedIds);
if (newSet.has(id)) {
newSet.delete(id);
} else {
@@ -182,7 +185,7 @@ function createState() {
}
function clearSelection() {
selectedIds = new Set();
selectedIds = new SvelteSet();
}
function edit(id: string | null) {
@@ -219,19 +222,27 @@ function createState() {
function copySelected() {
if (selectedIds.size === 0) return;
const items = manifest.items.filter((i) => selectedIds.has(i.id));
clipboard = items.map(({ id, ...rest }) => rest);
clipboard = items.map(({ id: _id, ...rest }) => rest);
}
function pasteItems(x: number, y: number): string[] {
if (clipboard.length === 0) return [];
const newIds: string[] = [];
const centerX = clipboard.reduce((sum, i) => sum + i.x, 0) / clipboard.length;
const centerY = clipboard.reduce((sum, i) => sum + i.y, 0) / clipboard.length;
const centerX =
clipboard.reduce((sum, i) => sum + i.x, 0) / clipboard.length;
const centerY =
clipboard.reduce((sum, i) => sum + i.y, 0) / clipboard.length;
for (const item of clipboard) {
const id = crypto.randomUUID();
const offsetX = item.x - centerX;
const offsetY = item.y - centerY;
addItem({ ...item, id, x: x + offsetX, y: y + offsetY, zIndex: maxZIndex + 1 });
addItem({
...item,
id,
x: x + offsetX,
y: y + offsetY,
zIndex: maxZIndex + 1,
});
newIds.push(id);
}
return newIds;
@@ -316,7 +327,11 @@ function createState() {
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
}
function animateViewport(targetX: number, targetY: number, targetZoom: number) {
function animateViewport(
targetX: number,
targetY: number,
targetZoom: number,
) {
if (animationId) cancelAnimationFrame(animationId);
const startX = viewport.x;
@@ -358,11 +373,11 @@ function createState() {
items: [],
sharedCss: DEFAULT_SHARED_CSS,
appCss: DEFAULT_APP_CSS,
flags: {}
flags: {},
};
assets = {};
viewport = { x: 0, y: 0, zoom: 1 };
selectedIds = new Set();
selectedIds = new SvelteSet();
editingId = null;
editingGlobal = false;
focusedId = null;
@@ -374,7 +389,7 @@ function createState() {
manifest = newManifest;
assets = newAssets;
viewport = { x: 0, y: 0, zoom: 1 };
selectedIds = new Set();
selectedIds = new SvelteSet();
editingId = null;
editingGlobal = false;
focusedId = null;
@@ -438,7 +453,7 @@ function createState() {
clearFlag,
gotoFlag,
reset,
load
load,
};
}

View File

@@ -3,7 +3,9 @@ import { syntaxHighlighting, HighlightStyle } from '@codemirror/language';
import { tags } from '@lezer/highlight';
function getVar(name: string, fallback: string): string {
const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
const value = getComputedStyle(document.documentElement)
.getPropertyValue(name)
.trim();
return value || fallback;
}
@@ -27,104 +29,145 @@ export function createTheme() {
'&': {
backgroundColor: surface,
color: '#abb2bf',
height: '100%'
height: '100%',
},
'.cm-scroller': {
overflow: 'auto',
fontFamily: "'Departure Mono', monospace"
fontFamily: "'Departure Mono', monospace",
},
'.cm-content': {
caretColor: accent
caretColor: accent,
},
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: accent
borderLeftColor: accent,
},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection':
{
backgroundColor: '#3E4451'
backgroundColor: '#3E4451',
},
'.cm-panels': {
backgroundColor: surface,
color: '#abb2bf'
color: '#abb2bf',
},
'.cm-panels.cm-panels-top': {
borderBottom: `1px solid ${border}`
borderBottom: `1px solid ${border}`,
},
'.cm-panels.cm-panels-bottom': {
borderTop: `1px solid ${border}`
borderTop: `1px solid ${border}`,
},
'.cm-searchMatch': {
backgroundColor: '#72a1ff59',
outline: `1px solid ${border}`
outline: `1px solid ${border}`,
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: '#6199ff2f'
backgroundColor: '#6199ff2f',
},
'.cm-activeLine': {
backgroundColor: '#2c313c50'
backgroundColor: '#2c313c50',
},
'.cm-selectionMatch': {
backgroundColor: '#aafe661a'
backgroundColor: '#aafe661a',
},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: '#bad0f847'
backgroundColor: '#bad0f847',
},
'.cm-gutters': {
backgroundColor: surface,
color: textDim,
border: 'none'
border: 'none',
},
'.cm-activeLineGutter': {
backgroundColor: '#2c313c50'
backgroundColor: '#2c313c50',
},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: textDim
color: textDim,
},
'.cm-tooltip': {
border: 'none',
backgroundColor: surface
backgroundColor: surface,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
borderBottomColor: 'transparent',
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: surface,
borderBottomColor: surface
borderBottomColor: surface,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
backgroundColor: accent,
color: text
}
}
color: text,
},
},
},
{ dark: true }
{ dark: true },
);
const highlighting = HighlightStyle.define([
{ tag: tags.keyword, color: keyword },
{ tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], color: variable },
{
tag: [
tags.name,
tags.deleted,
tags.character,
tags.propertyName,
tags.macroName,
],
color: variable,
},
{ tag: [tags.function(tags.variableName), tags.labelName], color: func },
{ tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], color: number },
{
tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)],
color: number,
},
{ tag: [tags.definition(tags.name), tags.separator], color: '#abb2bf' },
{ tag: [tags.typeName, tags.className, tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], color: number },
{ tag: [tags.operator, tags.operatorKeyword, tags.url, tags.escape, tags.regexp, tags.link, tags.special(tags.string)], color: operator },
{
tag: [
tags.typeName,
tags.className,
tags.number,
tags.changed,
tags.annotation,
tags.modifier,
tags.self,
tags.namespace,
],
color: number,
},
{
tag: [
tags.operator,
tags.operatorKeyword,
tags.url,
tags.escape,
tags.regexp,
tags.link,
tags.special(tags.string),
],
color: operator,
},
{ tag: [tags.meta, tags.comment], color: comment, fontStyle: 'italic' },
{ tag: tags.strong, fontWeight: 'bold' },
{ tag: tags.emphasis, fontStyle: 'italic' },
{ tag: tags.strikethrough, textDecoration: 'line-through' },
{ tag: tags.link, color: comment, textDecoration: 'underline' },
{ tag: tags.heading, fontWeight: 'bold', color: variable },
{ tag: [tags.atom, tags.bool, tags.special(tags.variableName)], color: number },
{ tag: [tags.processingInstruction, tags.string, tags.inserted], color: string },
{
tag: [tags.atom, tags.bool, tags.special(tags.variableName)],
color: number,
},
{
tag: [tags.processingInstruction, tags.string, tags.inserted],
color: string,
},
{ tag: tags.invalid, color: '#ff0000' },
{ tag: tags.tagName, color: variable },
{ tag: tags.attributeName, color: number },
{ tag: tags.attributeValue, color: string },
{ tag: tags.propertyName, color: func }
{ tag: tags.propertyName, color: func },
]);
return [theme, syntaxHighlighting(highlighting)];

View File

@@ -1,9 +1,9 @@
import { mount } from 'svelte'
import './app.css'
import App from './App.svelte'
import { mount } from 'svelte';
import './app.css';
import App from './App.svelte';
const app = mount(App, {
target: document.getElementById('app')!,
})
target: document.getElementById('app')!,
});
export default app
export default app;

View File

@@ -1,8 +1,8 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import("@sveltejs/vite-plugin-svelte").SvelteConfig} */
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
}
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
};

View File

@@ -1,21 +1,21 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"module": "ESNext",
"types": ["svelte", "vite/client"],
"noEmit": true,
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files.
*/
"allowJs": true,
"checkJs": true,
"moduleDetection": "force"
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"module": "ESNext",
"types": ["svelte", "vite/client"],
"noEmit": true,
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files.
*/
"allowJs": true,
"checkJs": true,
"moduleDetection": "force"
},
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
}

View File

@@ -1,7 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@@ -1,26 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
// https://vite.dev/config/
export default defineConfig({
plugins: [svelte()],
})
plugins: [svelte()],
});