diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml new file mode 100644 index 000000000..3a37d19e7 --- /dev/null +++ b/.github/workflows/javascript.yml @@ -0,0 +1,27 @@ +name: JavaScript + +on: + push: + branches: ['main'] + paths: ['codes/javascript/**/*.js'] + pull_request: + branches: ['main'] + paths: ['codes/javascript/**/*.js'] + workflow_dispatch: + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + - name: Run JavaScript Code + run: deno run -A codes/javascript/test_all.js diff --git a/.github/workflows/typescript.yml b/.github/workflows/typescript.yml index 0dc3db042..1b6172101 100644 --- a/.github/workflows/typescript.yml +++ b/.github/workflows/typescript.yml @@ -14,7 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/codes/javascript/test_all.js b/codes/javascript/test_all.js new file mode 100644 index 000000000..b43ef49f5 --- /dev/null +++ b/codes/javascript/test_all.js @@ -0,0 +1,63 @@ +import { bold, brightRed } from 'jsr:@std/fmt/colors'; +import { expandGlob } from 'jsr:@std/fs'; +import { relative, resolve } from 'jsr:@std/path'; + +/** + * @typedef {import('jsr:@std/fs').WalkEntry} WalkEntry + * @type {WalkEntry[]} + */ +const entries = []; + +for await (const entry of expandGlob( + resolve(import.meta.dirname, './chapter_*/*.js') +)) { + entries.push(entry); +} + +/** @type {{ status: Promise; stderr: ReadableStream; }[]} */ +const processes = []; + +for (const file of entries) { + const execute = new Deno.Command('node', { + args: [relative(import.meta.dirname, file.path)], + cwd: import.meta.dirname, + stdin: 'piped', + stdout: 'piped', + stderr: 'piped', + }); + + const process = execute.spawn(); + processes.push({ status: process.status, stderr: process.stderr }); +} + +const results = await Promise.all( + processes.map(async (item) => { + const status = await item.status; + return { status, stderr: item.stderr }; + }) +); + +/** @type {ReadableStream[]} */ +const errors = []; + +for (const result of results) { + if (!result.status.success) { + errors.push(result.stderr); + } +} + +console.log(`Tested ${entries.length} files`); +console.log(`Found exception in ${errors.length} files`); + +if (errors.length) { + console.log(); + + for (const error of errors) { + const reader = error.getReader(); + const { value } = await reader.read(); + const decoder = new TextDecoder(); + console.log(`${bold(brightRed('error'))}: ${decoder.decode(value)}`); + } + + throw new Error('Test failed'); +}