Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ if (arg === 'chat') {
console.log(packageJson.version)
} else if (!arg) {
serve(process.cwd(), undefined) // current directory
} else if (arg.match(/^https?:\/\//)) {
} else if (/^https?:\/\//.exec(arg)) {
serve(undefined, arg) // url
} else {
// resolve file or directory
Expand Down
6 changes: 3 additions & 3 deletions bin/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function handleRequest(req, serveDirectory) {
*/
async function handleStatic(filePath, range) {
const stats = await fs.stat(filePath).catch(() => undefined)
if (!stats || !stats.isFile()) {
if (!stats?.isFile()) {
return { status: 404, content: 'not found' }
}
const contentLength = stats.size
Expand Down Expand Up @@ -164,7 +164,7 @@ async function handleStatic(filePath, range) {
*/
async function handleHead(filePath) {
const stats = await fs.stat(filePath).catch(() => undefined)
if (!stats || !stats.isFile()) {
if (!stats?.isFile()) {
console.error(`file not found ${filePath}`)
return { status: 404, content: 'not found' }
}
Expand Down Expand Up @@ -271,7 +271,7 @@ function startServer(port, path) {
if (result.contentType) headers['Content-Type'] = result.contentType
if (status === 301 && typeof content === 'string') {
// handle redirect
headers['Location'] = content
headers.Location = content
content = ''
}
// compress content
Expand Down
6 changes: 3 additions & 3 deletions bin/streamConverters.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export async function pipe(input, output) {
export function readStreamToReadableStream(fsStream) {
return new ReadableStream({
start(/** @type {ReadableStreamDefaultController} */ controller) {
fsStream.on('data', (chunk) => controller.enqueue(chunk))
fsStream.on('end', () => controller.close())
fsStream.on('error', (error) => controller.error(error))
fsStream.on('data', (chunk) => { controller.enqueue(chunk) })
fsStream.on('end', () => { controller.close() })
fsStream.on('error', (error) => { controller.error(error) })
},
cancel() {
fsStream.destroy()
Expand Down
115 changes: 55 additions & 60 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,22 @@ import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import globals from 'globals'
import tseslint from 'typescript-eslint'
import typescript from 'typescript-eslint'

/** @type {import('eslint').Linter.Config.RulesRecord} */
const sharedJsRules = {
'arrow-spacing': 'error',
camelcase: 'off',
'comma-spacing': 'error',
'comma-dangle': ['error', 'always-multiline'],
'eol-last': 'error',
eqeqeq: 'error',
'func-style': ['error', 'declaration'],
indent: ['error', 2],
'no-constant-condition': 'off',
'no-extra-parens': 'error',
'no-multi-spaces': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-trailing-spaces': 'error',
'no-unused-vars': 'off',
'no-useless-concat': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'error',
'object-curly-spacing': ['error', 'always'],
'prefer-const': 'warn',
'prefer-destructuring': ['warn', {
object: true,
array: false,
}],
'prefer-promise-reject-errors': 'error',
quotes: ['error', 'single'],
'require-await': 'warn',
semi: ['error', 'never'],

'sort-imports': ['error', {
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
}],

'space-infix-ops': 'error',
}

/** @type {import('eslint').Linter.Config.RulesRecord} */
const sharedTsRules = {
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/require-await': 'warn',
}

export default tseslint.config(
{ ignores: ['coverage/', 'dist/', 'lib/', 'packages/'] },
export default typescript.config(
{ ignores: ['coverage/', 'dist/', 'lib/'] },
{
settings: { react: { version: '18.3' } },
extends: [javascript.configs.recommended, ...tseslint.configs.strictTypeChecked, ...tseslint.configs.stylisticTypeChecked],
extends: [javascript.configs.recommended, ...typescript.configs.strictTypeChecked, ...typescript.configs.stylisticTypeChecked],
files: ['**/*.{ts,tsx,js}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
project: ['./tsconfig.json', './tsconfig.eslint.json'],
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
'react': react,
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
Expand All @@ -80,11 +31,55 @@ export default tseslint.config(
{ allowConstantExport: true },
],
...javascript.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...sharedJsRules,
...sharedTsRules,
'no-extra-parens': 'warn',
...typescript.configs.recommended.rules,
// javascript
'arrow-spacing': 'error',
camelcase: 'off',
'comma-spacing': 'error',
'comma-dangle': ['error', {
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'never',
}],
'eol-last': 'error',
eqeqeq: 'error',
'func-style': ['error', 'declaration'],
indent: ['error', 2],
'no-constant-condition': 'off',
'no-extra-parens': 'error',
'no-multi-spaces': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-trailing-spaces': 'error',
'no-undef': 'error',
'no-unused-vars': 'off',
'no-useless-concat': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'error',
'object-curly-spacing': ['error', 'always'],
'prefer-const': 'warn',
'prefer-destructuring': ['warn', {
object: true,
array: false,
}],
'prefer-promise-reject-errors': 'error',
quotes: ['error', 'single'],
'require-await': 'warn',
semi: ['error', 'never'],
'sort-imports': ['error', {
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
}],
'space-infix-ops': 'error',
// typescript
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/require-await': 'warn',
},
settings: { react: { version: 'detect' } },
},
{
files: ['test/**/*.{ts,tsx}', '*.{js,ts}'],
Expand All @@ -98,7 +93,7 @@ export default tseslint.config(
},
{
files: ['**/*.js'],
...tseslint.configs.disableTypeChecked,
...typescript.configs.disableTypeChecked,
},
{
files: ['bin/**/*.js', 'test/bin/**/*.js'],
Expand All @@ -107,5 +102,5 @@ export default tseslint.config(
...globals.node,
},
},
},
}
)
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@
],
"scripts": {
"build:types": "tsc -b",
"build:lib": "vite build -c vite.lib.config.ts",
"build:app": "vite build -c vite.app.config.ts",
"build:lib": "vite build -c vite.lib.config.js",
"build:app": "vite build -c vite.app.config.js",
"build": "run-s build:lib build:types build:app",
"coverage": "vitest run -c vite.lib.config.ts --coverage --coverage.include=src --coverage.include=bin",
"coverage": "vitest run -c vite.lib.config.js --coverage --coverage.include=src --coverage.include=bin",
"dev": "run-p -l watch:ts watch:vite watch:serve",
"lint": "eslint .",
"prepublishOnly": "npm run build",
"serve": "node bin/cli.js",
"preserve": "npm run build",
"test": "vitest run -c vite.lib.config.ts",
"test": "vitest run -c vite.lib.config.js",
"typecheck": "tsc --noEmit",
"url": "run-p -l watch:ts watch:vite watch:url",
"watch:ts": "tsc --watch",
Expand Down
2 changes: 1 addition & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ if (!root) throw new Error('missing root element')
createRoot(root).render(
<StrictMode>
<App />
</StrictMode>,
</StrictMode>
)
2 changes: 1 addition & 1 deletion src/components/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Breadcrumb({ source, config, children }: BreadcrumbProps
return <nav className='top-header top-header-divided'>
<div className='path'>
{source.sourceParts.map((part, depth) =>
<a href={config?.routes?.getSourceRouteUrl?.({ sourceId: part.sourceId }) ?? ''} key={depth}>{part.text}</a>,
<a href={config?.routes?.getSourceRouteUrl?.({ sourceId: part.sourceId }) ?? ''} key={depth}>{part.text}</a>
)}
</div>
{children}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Folder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export default function Folder({ source, config }: FolderProps) {
</span>
</>}
</a>
</li>,
</li>
)}
</ul>}
{files?.length === 0 && <div className='center'>No files</div>}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Json.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function JsonObject({ obj, label }: { obj: object, label?: string }): ReactNode
{Object.entries(obj).map(([key, value]) =>
<li key={key}>
<Json json={value as unknown} label={key} />
</li>,
</li>
)}
</ul>
<div className={styles.object}>{'}'}</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function Markdown({ text, className }: MarkdownProps) {
function applyRegex(
currentText: ReactNode[],
regex: RegExp,
renderFn: (match: RegExpExecArray) => ReactNode,
renderFn: (match: RegExpExecArray) => ReactNode
) {
const newResult: ReactNode[] = []
for (const segment of currentText) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/tableProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function parquetDataFrame(from: AsyncBufferFrom, metadata: FileMetaData):
for (let i = rowStart; i < rowEnd; i++) {
data[i]?.index.resolve(i)
for (const [key, value] of Object.entries(
groupData[i - rowStart],
groupData[i - rowStart]
)) {
data[i]?.cells[key].resolve(value)
}
Expand Down Expand Up @@ -91,7 +91,7 @@ export function parquetDataFrame(from: AsyncBufferFrom, metadata: FileMetaData):
}).catch((error: unknown) => {
console.error(
'Error fetching sort index or resolving sorted rows',
error,
error
)
})

Expand Down
2 changes: 1 addition & 1 deletion src/lib/workers/parquetWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ self.onmessage = async ({ data }: {
throw new Error('sortIndex requires all rows')
const sortColumn = await parquetQuery({ metadata, file, columns: [orderBy], compressors })
const indices = Array.from(sortColumn, (_, index) => index).sort((a, b) =>
compare<unknown>(sortColumn[a][orderBy], sortColumn[b][orderBy]),
compare<unknown>(sortColumn[a][orderBy], sortColumn[b][orderBy])
)
postIndicesMessage({ indices, queryId })
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/workers/parquetWorkerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function getWorker() {
const pendingQueryAgent = pending.get(data.queryId)
if (!pendingQueryAgent) {
console.warn(
`Unexpected: no pending promise found for queryId: ${data.queryId.toString()}`,
`Unexpected: no pending promise found for queryId: ${data.queryId.toString()}`
)
return
}
Expand Down
6 changes: 3 additions & 3 deletions test/components/File.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const config: RoutesConfig = {
// Mock fetch
const text = vi.fn()
const headers = { get: vi.fn() }
global.fetch = vi.fn(() => Promise.resolve({ text, headers } as unknown as Response))
globalThis.fetch = vi.fn(() => Promise.resolve({ text, headers } as unknown as Response))

describe('File Component', () => {
it('renders a local file path', async () => {
Expand All @@ -25,7 +25,7 @@ describe('File Component', () => {
assert(source?.kind === 'file')

const { getByText } = await act(() => render(
<File source={source} config={config}/>,
<File source={source} config={config}/>
))

expect(getByText('/')).toBeDefined()
Expand All @@ -51,7 +51,7 @@ describe('File Component', () => {
assert(source?.kind === 'file')

const { getAllByRole } = await act(() => render(
<File source={source} config={config} />,
<File source={source} config={config} />
))

const links = getAllByRole('link')
Expand Down
2 changes: 1 addition & 1 deletion test/components/Folder.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const config: RoutesConfig = {
},
}

global.fetch = vi.fn()
globalThis.fetch = vi.fn()

describe('Folder Component', () => {
test.for([
Expand Down
4 changes: 2 additions & 2 deletions test/components/viewers/ImageView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react'
import { describe, expect, it, vi } from 'vitest'
import { ImageView, getHyperparamSource } from '../../../src/index.js'

global.fetch = vi.fn()
globalThis.fetch = vi.fn()

describe('ImageView Component', () => {
it('renders the image correctly', async () => {
Expand All @@ -18,7 +18,7 @@ describe('ImageView Component', () => {
assert(source?.kind === 'file')

const { findByRole, findByText } = render(
<ImageView source={source} setError={console.error} />,
<ImageView source={source} setError={console.error} />
)

// wait for asynchronous image loading
Expand Down
4 changes: 2 additions & 2 deletions test/components/viewers/MarkdownView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react'
import { describe, expect, it, vi } from 'vitest'
import { MarkdownView, getHyperparamSource } from '../../../src/index.js'

global.fetch = vi.fn()
globalThis.fetch = vi.fn()

describe('MarkdownView Component', () => {
it('renders markdown correctly', async () => {
Expand All @@ -18,7 +18,7 @@ describe('MarkdownView Component', () => {
assert(source?.kind === 'file')

const { findByText } = render(
<MarkdownView source={source} setError={console.error} />,
<MarkdownView source={source} setError={console.error} />
)

expect(fetch).toHaveBeenCalled()
Expand Down
2 changes: 1 addition & 1 deletion test/lib/sources/httpSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, expect, it, test, vi } from 'vitest'
import { getHttpSource } from '../../../src/lib/sources/httpSource.js'

global.fetch = vi.fn()
globalThis.fetch = vi.fn()

describe('getHttpSource', () => {
test.for([
Expand Down
2 changes: 1 addition & 1 deletion test/lib/sources/hyperparamSource.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assert, describe, expect, it, test, vi } from 'vitest'
import { HyperparamFileMetadata, getHyperparamSource } from '../../../src/lib/sources/hyperparamSource.js'

global.fetch = vi.fn()
globalThis.fetch = vi.fn()

describe('getHyperparamSource', () => {
const endpoint = 'http://localhost:3000'
Expand Down
Loading