diff --git a/package.json b/package.json index 5c97c9bb..77841577 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "prepack": "npx svelte-package", "release-next": "npm version prerelease --preid next && npm publish && git push && git push --tags && sleep 1 && npm dist-tag add svelteplot@$(npm view . version) next", "docs": "npm run build && cd build && rsync --recursive . vis4.net:svelteplot/alpha0/", - "screenshots": "node screenshot-examples.js" + "screenshots": "node screenshot-examples.js", + "check-js-extensions": "node scripts/check-js-extensions.js src" }, "exports": { ".": { diff --git a/scripts/check-js-extensions.js b/scripts/check-js-extensions.js new file mode 100755 index 00000000..4ea9db11 --- /dev/null +++ b/scripts/check-js-extensions.js @@ -0,0 +1,138 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ + +/** + * This script checks for missing .js extensions in import statements. + * It helps identify issues with ESM imports where TypeScript requires .js extensions. + */ + +import { readFile, readdir, stat } from 'fs/promises'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Convert file:// URLs to paths +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Regular expressions to match import statements without .js extensions +const regexImportFrom = + /import\s+(?:type\s+)?(?:{[^}]*}|\*\s+as\s+[^;]*|[^;{]*)\s+from\s+['"]([^'"]*)['"]/g; +const regexExportFrom = + /export\s+(?:type\s+)?(?:{[^}]*}|\*\s+as\s+[^;]*)\s+from\s+['"]([^'"]*)['"]/g; + +// Skip node_modules and build directories +const excludedDirs = ['node_modules', 'build', '.svelte-kit', 'dist', '.git', 'examples', 'tests']; + +// Only check certain file types +const includedExtensions = ['.ts', '.js', '.svelte']; + +// Paths that should have .js extensions (relative paths and alias paths) +const shouldHaveJsExtension = (importPath) => { + // Skip Svelte imports + if (importPath.endsWith('.svelte')) return false; + + // Skip npm package imports (those that don't start with . or /) + if ( + !importPath.startsWith('.') && + !importPath.startsWith('/') && + !importPath.startsWith('$lib') + ) + return false; + + // Skip imports with extensions already + if (path.extname(importPath)) return false; + + return true; +}; + +async function* walkDirectory(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + if (!excludedDirs.includes(entry.name)) { + yield* walkDirectory(fullPath); + } + } else if (includedExtensions.includes(path.extname(entry.name))) { + yield fullPath; + } + } +} + +async function checkFile(filePath) { + const content = await readFile(filePath, 'utf8'); + const issues = []; + + // Find all import statements + let match; + + // Check import statements + regexImportFrom.lastIndex = 0; + while ((match = regexImportFrom.exec(content)) !== null) { + const importPath = match[1]; + if (shouldHaveJsExtension(importPath)) { + issues.push({ + line: content.substring(0, match.index).split('\n').length, + importPath, + statement: match[0] + }); + } + } + + // Check export from statements + regexExportFrom.lastIndex = 0; + while ((match = regexExportFrom.exec(content)) !== null) { + const importPath = match[1]; + if (shouldHaveJsExtension(importPath)) { + issues.push({ + line: content.substring(0, match.index).split('\n').length, + importPath, + statement: match[0] + }); + } + } + + return { filePath, issues }; +} + +async function main() { + const rootDir = process.argv[2] || process.cwd(); + console.log(`Checking for missing .js extensions in ${rootDir}...\n`); + + let totalIssues = 0; + let filesWithIssues = 0; + + for await (const filePath of walkDirectory(rootDir)) { + const { issues } = await checkFile(filePath); + + if (issues.length > 0) { + console.log(`\x1b[33m${filePath}\x1b[0m`); + filesWithIssues++; + + for (const issue of issues) { + totalIssues++; + console.log( + ` Line ${issue.line}: Missing .js extension in import: ${issue.importPath}` + ); + console.log(` ${issue.statement}`); + } + console.log(''); + } + } + + if (totalIssues === 0) { + console.log('\x1b[32mNo missing .js extensions found!\x1b[0m'); + } else { + console.log( + `\x1b[31mFound ${totalIssues} missing .js extensions in ${filesWithIssues} files.\x1b[0m` + ); + process.exit(1); + } +} + +main().catch((err) => { + console.error('Error:', err); + process.exit(1); +}); diff --git a/src/lib/Plot.svelte b/src/lib/Plot.svelte index 840120b0..2db722c5 100644 --- a/src/lib/Plot.svelte +++ b/src/lib/Plot.svelte @@ -12,7 +12,7 @@ + + + + + + d < 0 ? 'negative' : 'positive'} /> + + + diff --git a/src/routes/examples/axis/ticks-inside.svelte b/src/routes/examples/axis/ticks-inside.svelte new file mode 100644 index 00000000..43faecac --- /dev/null +++ b/src/routes/examples/axis/ticks-inside.svelte @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/src/routes/features/markers/+page.md b/src/routes/features/markers/+page.md index 87f690a3..a4c724fa 100644 --- a/src/routes/features/markers/+page.md +++ b/src/routes/features/markers/+page.md @@ -88,7 +88,7 @@ Note that for the interpolation methods `basis`, `bundle`, and `step`, the marke import { Plot, LineY, Dot } from 'svelteplot'; import Slider from '$lib/ui/Slider.svelte'; import Select from '$lib/ui/Select.svelte'; - import type { CurveName } from '$lib/types.js'; + import type { CurveName } from '$lib/types/index.js'; // curve demo const numbers = [ @@ -134,7 +134,7 @@ You can also specify a custom marker icon using the `marker` snippet: ```svelte live diff --git a/src/routes/marks/line/CO2Decades.svelte b/src/routes/marks/line/CO2Decades.svelte index dd364b87..e16f6904 100644 --- a/src/routes/marks/line/CO2Decades.svelte +++ b/src/routes/marks/line/CO2Decades.svelte @@ -1,5 +1,5 @@ diff --git a/src/routes/transforms/interval/+page.md b/src/routes/transforms/interval/+page.md index 9914781f..1c205b83 100644 --- a/src/routes/transforms/interval/+page.md +++ b/src/routes/transforms/interval/+page.md @@ -33,7 +33,7 @@ In contrast, a [rectY](/marks/rect) mark with the interval option and the day in ```svelte live diff --git a/src/tests/dot.test.svelte b/src/tests/dot.test.svelte index 07762711..a892a88d 100644 --- a/src/tests/dot.test.svelte +++ b/src/tests/dot.test.svelte @@ -1,5 +1,5 @@