diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ead5241 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,542 @@ +{ + "name": "CI", + "on": { + "pull_request": {}, + "merge_group": {} + }, + "jobs": { + "ubuntu-intel": { + "runs-on": "ubuntu-24.04", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "uses": "oven-sh/setup-bun@v2", + "with": { + "bun-version": "1.3.14" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g ./*.tgz" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "ubuntu-arm": { + "runs-on": "ubuntu-24.04-arm", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "uses": "oven-sh/setup-bun@v2", + "with": { + "bun-version": "1.3.14" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g ./*.tgz" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "macos-intel": { + "runs-on": "macos-26-intel", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "uses": "oven-sh/setup-bun@v2", + "with": { + "bun-version": "1.3.14" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g ./*.tgz" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "macos-arm": { + "runs-on": "macos-26", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "uses": "oven-sh/setup-bun@v2", + "with": { + "bun-version": "1.3.14" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g ./*.tgz" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "windows-intel": { + "runs-on": "windows-2025", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "uses": "oven-sh/setup-bun@v2", + "with": { + "bun-version": "1.3.14" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g (Get-ChildItem *.tgz).FullName" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "windows-arm": { + "runs-on": "windows-11-arm", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "run": "npm install -g @typescript/native-preview@7.0.0-dev.20260606.1" + }, + { + "uses": "denoland/setup-deno@v2", + "with": { + "deno-version": "2.8.2" + } + }, + { + "run": "irm bun.sh/install.ps1 | iex; \"$env:USERPROFILE\\.bun\\bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append" + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + }, + { + "run": "tsgo" + }, + { + "run": "npm pack" + }, + { + "run": "npm install -g (Get-ChildItem *.tgz).FullName" + }, + { + "run": "npm uninstall file-server-example -g" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "deno install --frozen" + }, + { + "run": "deno task test" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + }, + { + "run": "bun install --frozen-lockfile" + }, + { + "run": "bun test --timeout 20000" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + }, + "node24": { + "runs-on": "ubuntu-24.04", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "24.16.0" + } + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx tsc" + }, + { + "run": "npm test" + }, + { + "run": "node --test" + }, + { + "run": "npm run cov" + } + ] + }, + "playwright": { + "runs-on": "ubuntu-24.04", + "steps": [ + { + "uses": "actions/setup-node@v6", + "with": { + "node-version": "26.3.0" + } + }, + { + "uses": "actions/cache@v5", + "with": { + "path": "~/.cache/ms-playwright", + "key": "ubuntu-24.04-playwright-1.60.0" + } + }, + { + "run": "npm install -g playwright@1.60.0" + }, + { + "run": "playwright install-deps" + }, + { + "run": "playwright install" + }, + { + "uses": "actions/checkout@v6" + }, + { + "run": "npm ci" + }, + { + "run": "npx playwright test --browser=chromium" + }, + { + "run": "npx playwright test --browser=firefox" + }, + { + "run": "npx playwright test --browser=webkit" + }, + { + "run": "git reset --hard HEAD && git clean -fdx" + } + ] + } + } +} \ No newline at end of file diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml deleted file mode 100644 index b3e6ca9..0000000 --- a/.github/workflows/node.js.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs - -name: Node.js CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [24.x, 25.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm test diff --git a/all.test.ts b/all.test.ts new file mode 100644 index 0000000..3a4a9df --- /dev/null +++ b/all.test.ts @@ -0,0 +1 @@ +import 'functionalscript/fs/emergent_testing/all.test.js' diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..1a61f69 --- /dev/null +++ b/bun.lock @@ -0,0 +1,29 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "name": "file-server-example", + "dependencies": { + "functionalscript": "0.29.0", + }, + "devDependencies": { + "@playwright/test": "1.60.0", + "typescript": "6.0.3", + }, + }, + }, + "packages": { + "@playwright/test": ["@playwright/test@1.60.0", "", { "dependencies": { "playwright": "1.60.0" }, "bin": { "playwright": "cli.js" } }, "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag=="], + + "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + + "functionalscript": ["functionalscript@0.29.0", "", { "bin": { "fjs": "fs/fjs/module.js" } }, "sha512-aOeHI0tAdHBa27bW89nS067dlCU52cVhiSodxtfc4CH+KdlLgae6tuHZY6XuhR5E8e1hLVvhbxOYRrMe9CuXTA=="], + + "playwright": ["playwright@1.60.0", "", { "dependencies": { "playwright-core": "1.60.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA=="], + + "playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="], + + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..3639e47 --- /dev/null +++ b/deno.lock @@ -0,0 +1,53 @@ +{ + "version": "5", + "specifiers": { + "npm:@playwright/test@1.60.0": "1.60.0", + "npm:functionalscript@0.29.0": "0.29.0", + "npm:typescript@6.0.3": "6.0.3" + }, + "npm": { + "@playwright/test@1.60.0": { + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "dependencies": [ + "playwright" + ], + "bin": true + }, + "fsevents@2.3.2": { + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "os": ["darwin"], + "scripts": true + }, + "functionalscript@0.29.0": { + "integrity": "sha512-aOeHI0tAdHBa27bW89nS067dlCU52cVhiSodxtfc4CH+KdlLgae6tuHZY6XuhR5E8e1hLVvhbxOYRrMe9CuXTA==", + "bin": true + }, + "playwright-core@1.60.0": { + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "bin": true + }, + "playwright@1.60.0": { + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dependencies": [ + "playwright-core" + ], + "optionalDependencies": [ + "fsevents" + ], + "bin": true + }, + "typescript@6.0.3": { + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "bin": true + } + }, + "workspace": { + "packageJson": { + "dependencies": [ + "npm:@playwright/test@1.60.0", + "npm:functionalscript@0.29.0", + "npm:typescript@6.0.3" + ] + } + } +} diff --git a/package-lock.json b/package-lock.json index 105a782..cd305b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,28 +9,92 @@ "version": "0.0.0", "license": "MIT", "dependencies": { - "functionalscript": "^0.11.10" + "functionalscript": "0.29.0" }, "devDependencies": { - "typescript": "^5.9.3" + "@playwright/test": "1.60.0", + "typescript": "6.0.3" + } + }, + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/functionalscript": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/functionalscript/-/functionalscript-0.11.10.tgz", - "integrity": "sha512-T71tKFD/a49HbjDKL5IZ061+5TfH62FGgekfdXrMUjbh/mUOHW5TMjn9nTp9z/VuWXRfDHlIZZROXlQCuPt/gg==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/functionalscript/-/functionalscript-0.29.0.tgz", + "integrity": "sha512-aOeHI0tAdHBa27bW89nS067dlCU52cVhiSodxtfc4CH+KdlLgae6tuHZY6XuhR5E8e1hLVvhbxOYRrMe9CuXTA==", "license": "MIT", "bin": { - "fjs": "fjs/module.js" + "fjs": "fs/fjs/module.js" + }, + "engines": { + "node": ">=24" + } + }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" }, "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 27c3d63..dcdddfa 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,15 @@ "main": "server.f.ts", "scripts": { "test": "tsc && fjs t", - "start": "fjs r ./server.f.ts" + "start": "fjs r ./server.f.ts", + "update": "npx npm-check-updates -u && npm install && deno install && bun install && fjs i", + "cov": "node --test --experimental-test-coverage --test-coverage-include=**/*.f.ts" }, "dependencies": { - "functionalscript": "^0.11.10" + "functionalscript": "0.29.0" }, "devDependencies": { - "typescript": "^5.9.3" + "@playwright/test": "1.60.0", + "typescript": "6.0.3" } } diff --git a/proof.f.ts b/proof.f.ts new file mode 100644 index 0000000..f953991 --- /dev/null +++ b/proof.f.ts @@ -0,0 +1,65 @@ +import { assert, assertEq } from 'functionalscript/fs/asserts/module.f.js' +import { utf8, utf8ToString } from 'functionalscript/fs/text/module.f.js' +import { vec8 } from 'functionalscript/fs/types/bit_vec/module.f.js' +import type { IncomingMessage } from 'functionalscript/fs/effects/node/module.f.js' +import { virtual, emptyState } from 'functionalscript/fs/effects/node/virtual/module.f.js' +import { listener } from './server.f.ts' + +const request = (url: string): IncomingMessage => ({ + method: 'GET', + url, + headers: {}, + body: vec8(0n), +}) + +const runRequest = (url: string, root = emptyState.root) => + virtual({ ...emptyState, root })(listener(request(url))) + +const bodyText = (url: string, root = emptyState.root) => { + const [state, response] = runRequest(url, root) + return [state, response, utf8ToString(response.body)] as const +} + +const includes = (s: string) => (part: string) => { + assert(s.includes(part), [part, s]) +} + +export const proof = { + servesFiles: () => { + const file = utf8('body { color: green; }\n') + const [state, response] = runRequest('/main.css', { 'main.css': file }) + + assertEq(response.status, 200) + assertEq(utf8ToString(response.body), 'body { color: green; }\n') + includes(state.stdout)('reading ./main.css\n') + includes(state.stdout)('served: 23 bytes\n') + }, + ignoresQueryString: () => { + const file = utf8('ok') + const [_, response] = runRequest('/main.css?cache=bust', { 'main.css': file }) + + assertEq(response.status, 200) + assertEq(utf8ToString(response.body), 'ok') + }, + rendersDirectoryListing: () => { + const [state, response, body] = bodyText('/docs', { + docs: { + 'a.txt': utf8('A'), + nested: {}, + }, + }) + + assertEq(response.status, 200) + includes(body)('') + includes(body)('
a.txt\nnested/\n
') + includes(state.stdout)('reading ./docs\n') + includes(state.stdout)('served: ') + }, + missingPaths404: () => { + const [state, response] = runRequest('/missing') + + assertEq(response.status, 404) + assertEq(utf8ToString(response.body), '404 not found') + assertEq(state.stdout, 'reading ./missing\nserved: 13 bytes\n') + }, +} diff --git a/server.f.ts b/server.f.ts index c842f5b..02c0d13 100644 --- a/server.f.ts +++ b/server.f.ts @@ -1,6 +1,6 @@ -import { utf8 } from 'functionalscript/text/module.f.js' -import { length, type Vec } from 'functionalscript/types/bit_vec/module.f.js' -import { pure } from 'functionalscript/types/effects/module.f.js' +import { utf8 } from 'functionalscript/fs/text/module.f.js' +import { empty, length, type Vec } from 'functionalscript/fs/types/bit_vec/module.f.js' +import { pure } from 'functionalscript/fs/effects/module.f.js' import { createServer, listen, @@ -12,11 +12,11 @@ import { readdir, type IoResult, type Dirent, -} from 'functionalscript/types/effects/node/module.f.js' -import { htmlToString } from 'functionalscript/html/module.f.js' -import { concat } from 'functionalscript/path/module.f.js' +} from 'functionalscript/fs/effects/node/module.f.js' +import { htmlUtf8 } from 'functionalscript/fs/html/module.f.js' +import { concat } from 'functionalscript/fs/path/module.f.js' -const listener = ({ url }: IncomingMessage) => { +export const listener = ({ url }: IncomingMessage) => { const path = url.split('?')[0] ?? '' const file = '.' + path @@ -25,22 +25,14 @@ const listener = ({ url }: IncomingMessage) => { return [['a', { href }, name + (isFile ? '' : '/')], '\n'] as const } - const dirPage = (v: readonly Dirent[]) => htmlToString( - ['html', - ['head', - ['link', { rel: 'stylesheet', href: '/main.css' }] - ], - ['body', - ['pre', - ...v.flatMap(dirLink) - ] - ] - ]) + const dirPage = (v: readonly Dirent[]) => htmlUtf8 + (['link', { rel: 'stylesheet', href: '/main.css' }]) + (['pre', ...v.flatMap(dirLink)]) const orReadDir = (r: IoResult) => r[0] === 'ok' ? pure(r) : readdir(file, {}) - .step(([s, v]) => pure([s, utf8(s === 'ok' ? dirPage(v) : '')] as const)) + .step(([s, v]) => pure([s, s === 'ok' ? dirPage(v) : empty] as const)) return log(`reading ${file}`) .step(() => readFile(file)) diff --git a/tsconfig.json b/tsconfig.json index de92c5e..44fd1a8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,8 +35,9 @@ // Recommended Options "strict": true, "jsx": "react-jsx", - "verbatimModuleSyntax": true, - "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowImportingTsExtensions": true, + "isolatedModules": true, "noUncheckedSideEffectImports": true, "moduleDetection": "force", "skipLibCheck": true,