diff --git a/.prettierignore b/.prettierignore index ab1e283..85bb9e9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,5 +2,9 @@ node_modules/ out/ package-lock.json +# Ignore code generated into our project by langium based on our grammar. +generated/ +syntaxes/ + # Ignore examples for now because they have syntax errors we're testing, prettier can't parse them. examples/ diff --git a/bin/cli b/bin/cli deleted file mode 100755 index f0a5258..0000000 --- a/bin/cli +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require("../out/cli").default(); \ No newline at end of file diff --git a/bin/cli.js b/bin/cli.js new file mode 100755 index 0000000..1838fbf --- /dev/null +++ b/bin/cli.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../out/cli/index.js').default() diff --git a/examples/st.d.ts b/examples/st.d.ts new file mode 100644 index 0000000..ed36d7e --- /dev/null +++ b/examples/st.d.ts @@ -0,0 +1,3 @@ +type i32 = number; +type f32 = number; +type f64 = number; diff --git a/examples/tsconfig.json b/examples/tsconfig.json new file mode 100644 index 0000000..e0ae827 --- /dev/null +++ b/examples/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + // Compiler setup + "target": "ES6", + "module": "esnext", + "lib": ["ESNext"], + "sourceMap": true, + "outDir": "out", + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + + // Type checking + "strict": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "noImplicitOverride": true, + + "importsNotUsedAsValues": "error" + }, + "include": ["./**/*.ts"], + "exclude": ["out", "node_modules"] +} diff --git a/package.json b/package.json index 731ed8d..c29e683 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "src" ], "bin": { - "bytescript-cli": "./bin/cli" + "bs": "./bin/cli.js" }, "main": "./out/extension.js", "scripts": { @@ -53,9 +53,11 @@ "langium:watch": "langium generate --watch", "format:all": "prettier --write .", "wat2wasm": "wat2wasm generated/poc1.wat -o generated/poc1.wasm", - "test": "npm run test:compile && npm run test:node && echo 'Tests passed!'", - "test:compile": "./bin/cli compile examples/basic/poc1.ts && npm run wat2wasm", - "test:node": "node tests/node/test.mjs" + "wtr": "web-test-runner tests/browser/*.ts --node-resolve", + "test": "npm run lint && npm run test:compile && npm run test:node && npm run test:browser && echo 'Tests passed!'", + "test:compile": "./bin/cli.js compile examples/basic/poc1.ts && npm run wat2wasm", + "test:node": "node tests/node/test.mjs", + "test:browser": "npm run wtr" }, "dependencies": { "chalk": "^4.1.2", @@ -64,13 +66,17 @@ "langium": "~1.0.0", "vscode-languageclient": "^8.0.2", "vscode-languageserver": "^8.0.2", - "vscode-uri": "^3.0.2" + "vscode-uri": "^3.0.2", + "wdeasync": "^0.1.118" }, "devDependencies": { + "@open-wc/testing": "^3.1.8", "@types/node": "^14.17.3", "@types/vscode": "^1.56.0", "@typescript-eslint/eslint-plugin": "^5.28.0", "@typescript-eslint/parser": "^5.28.0", + "@web/dev-server-esbuild": "^0.4.1", + "@web/test-runner": "^0.16.1", "binaryen": "^113.0.0", "eslint": "^8.17.0", "langium-cli": "~1.0.0", diff --git a/src/cli/cli-util.ts b/src/cli/cli-util.ts index d41099b..d759e51 100644 --- a/src/cli/cli-util.ts +++ b/src/cli/cli-util.ts @@ -2,7 +2,9 @@ import chalk from 'chalk' import path from 'path' import fs from 'fs' import type {AstNode, LangiumDocument, LangiumServices} from 'langium' -import {URI} from 'vscode-uri' +import * as vscodeUri from 'vscode-uri' + +const {URI} = vscodeUri export async function extractDocument(fileName: string, services: LangiumServices): Promise { const extensions = services.LanguageMetaData.fileExtensions diff --git a/src/cli/generator.ts b/src/cli/generator.ts index 0f8001e..e1f0c02 100644 --- a/src/cli/generator.ts +++ b/src/cli/generator.ts @@ -7,12 +7,12 @@ import { isExportedFunctionDeclaration, isOriginalFunctionDeclaration, isReturnStatement, -} from '../language-server/generated/ast' -import {extractDestinationAndName} from './cli-util' -import {isBinaryExpressionSum} from '../language-server/types/types' -import {getType} from '../language-server/types/types' -import {isI32NumberType} from '../language-server/types/descriptions' -import {isBinaryExpressionProduct} from '../language-server/types/types' +} from '../language-server/generated/ast.js' +import {extractDestinationAndName} from './cli-util.js' +import {isBinaryExpressionSum} from '../language-server/types/types.js' +import {getType} from '../language-server/types/types.js' +import {isI32NumberType} from '../language-server/types/descriptions.js' +import {isBinaryExpressionProduct} from '../language-server/types/types.js' export function generateWasm(topLevel: TopLevel, filePath: string, destination: string | undefined): string { const data = extractDestinationAndName(filePath, destination) diff --git a/src/cli/index.ts b/src/cli/index.ts index 87f0acf..754dfa9 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,17 +1,20 @@ -import chalk from 'chalk' +import {green} from 'chalk' import {Command} from 'commander' -import type {TopLevel} from '../language-server/generated/ast' -import {ByteScriptLanguageMetaData} from '../language-server/generated/module' -import {createByteScriptServices} from '../language-server/bytescript-module' -import {extractAstNode} from './cli-util' -import {generateWasm} from './generator' -import {NodeFileSystem} from 'langium/node' +import type {TopLevel} from '../language-server/generated/ast.js' +import {ByteScriptLanguageMetaData} from '../language-server/generated/module.js' +import {createByteScriptServices} from '../language-server/bytescript-module.js' +import {extractAstNode} from './cli-util.js' +import {generateWasm} from './generator.js' +import {NodeFileSystem} from 'langium/node.js' + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const pkg = require('../../package.json') export async function generate(fileName: string, opts: GenerateOptions): Promise { const services = createByteScriptServices(NodeFileSystem).ByteScript const ast = await extractAstNode(fileName, services) const generatedFilePath = generateWasm(ast, fileName, opts.destination) - console.log(chalk.green(`Build successful: ${generatedFilePath}`)) + console.log(green(`Build successful: ${generatedFilePath}`)) } export type GenerateOptions = { @@ -21,9 +24,7 @@ export type GenerateOptions = { export default function (): void { const program = new Command() - program - // eslint-disable-next-line @typescript-eslint/no-var-requires - .version(require('../../package.json').version) + program.version(pkg.version) const fileExtensions = ByteScriptLanguageMetaData.fileExtensions.join(', ') program diff --git a/src/extension.ts b/src/extension.ts index df13b98..70faf91 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' import * as path from 'path' -import {LanguageClient, LanguageClientOptions, ServerOptions, TransportKind} from 'vscode-languageclient/node' +import {LanguageClient, LanguageClientOptions, ServerOptions, TransportKind} from 'vscode-languageclient/node.js' let client: LanguageClient diff --git a/src/language-server/bytescript-module.ts b/src/language-server/bytescript-module.ts index b2df9f6..49cf62a 100644 --- a/src/language-server/bytescript-module.ts +++ b/src/language-server/bytescript-module.ts @@ -8,9 +8,9 @@ import { Module, PartialLangiumServices, } from 'langium' -import {ByteScriptGeneratedModule, ByteScriptGeneratedSharedModule} from './generated/module' -import {ByteScriptValidator, registerValidationChecks} from './bytescript-validator' -import {ByteScriptScopeProvider} from './bytescript-scope' +import {ByteScriptGeneratedModule, ByteScriptGeneratedSharedModule} from './generated/module.js' +import {ByteScriptValidator, registerValidationChecks} from './bytescript-validator.js' +import {ByteScriptScopeProvider} from './bytescript-scope.js' /** * Declaration of custom services - add your own service classes here. diff --git a/src/language-server/bytescript-scope.ts b/src/language-server/bytescript-scope.ts new file mode 100644 index 0000000..2f0e23f --- /dev/null +++ b/src/language-server/bytescript-scope.ts @@ -0,0 +1,6 @@ +import {DefaultScopeProvider} from 'langium' + +export class ByteScriptScopeProvider extends DefaultScopeProvider { + // TODO we'll need to fill this in to provide scope for some cases, but the + // DefaultScopeProvider is currently good enough for the initial PoC. +} diff --git a/src/language-server/bytescript-validator.ts b/src/language-server/bytescript-validator.ts index e7aafac..31f04cf 100644 --- a/src/language-server/bytescript-validator.ts +++ b/src/language-server/bytescript-validator.ts @@ -14,16 +14,16 @@ import { Block, ArrowReturnExpression, TypeDeclaration, -} from './generated/ast' -import type {ByteScriptServices} from './bytescript-module' +} from './generated/ast.js' +import type {ByteScriptServices} from './bytescript-module.js' import { getType, isAssignable, isBinaryExpressionAssignment, isBinaryExpressionProduct, isBinaryExpressionSum, -} from './types/types' -import {TypeInferenceError, isTypeInferenceError, TypeDescription, typeToString} from './types/descriptions' +} from './types/types.js' +import {TypeInferenceError, isTypeInferenceError, TypeDescription, typeToString} from './types/descriptions.js' /** * Register custom validation checks. diff --git a/src/language-server/main.ts b/src/language-server/main.ts index ce794bc..b1bec22 100644 --- a/src/language-server/main.ts +++ b/src/language-server/main.ts @@ -1,7 +1,7 @@ import {startLanguageServer} from 'langium' -import {NodeFileSystem} from 'langium/node' -import {createConnection, ProposedFeatures} from 'vscode-languageserver/node' -import {createByteScriptServices} from './bytescript-module' +import {NodeFileSystem} from 'langium/node.js' +import {createConnection, ProposedFeatures} from 'vscode-languageserver/node.js' +import {createByteScriptServices} from './bytescript-module.js' // Create a connection to the client const connection = createConnection(ProposedFeatures.all) diff --git a/src/language-server/types/descriptions.ts b/src/language-server/types/descriptions.ts index 90ed427..a55f108 100644 --- a/src/language-server/types/descriptions.ts +++ b/src/language-server/types/descriptions.ts @@ -1,5 +1,5 @@ import type {AstNode} from 'langium' -import type {Identifier, NumberLiteral, TypeExpression} from '../generated/ast' +import type {Identifier, NumberLiteral, TypeExpression} from '../generated/ast.js' export type TypeDescription = NumberType | FunctionType | TypeInferenceError diff --git a/src/language-server/types/types.ts b/src/language-server/types/types.ts index daf3387..e58070c 100644 --- a/src/language-server/types/types.ts +++ b/src/language-server/types/types.ts @@ -13,7 +13,7 @@ import { isIdentifier, isBinaryExpression, isParameter, -} from '../generated/ast' +} from '../generated/ast.js' import { createTypeInferenceError, createF64NumberType, @@ -22,7 +22,7 @@ import { createLiteralNumberType, FunctionTypeParameter, TypeDescription, -} from './descriptions' +} from './descriptions.js' const types = new Map() diff --git a/tests/browser/test.ts b/tests/browser/test.ts new file mode 100644 index 0000000..4442717 --- /dev/null +++ b/tests/browser/test.ts @@ -0,0 +1,12 @@ +import {expect} from '@open-wc/testing' + +describe('poc1', () => { + it('add sums up 2 numbers', async () => { + const wasmModule = await WebAssembly.instantiateStreaming(await fetch('/generated/poc1.wasm')) + + const {add} = wasmModule.instance.exports as {add(a: number, b: number): number} + + expect(add(1, 1)).to.equal(2) + expect(add(3, 12)).to.equal(15) + }) +}) diff --git a/tests/node/test.mjs b/tests/node/test.mjs index 7bdec28..4cbd40d 100644 --- a/tests/node/test.mjs +++ b/tests/node/test.mjs @@ -8,3 +8,5 @@ const {add} = wasmModule.instance.exports const sum = add(5, 6) console.assert(sum === 11, 'expected 5+6 = 11') + +console.log('Node test passed!') diff --git a/web-test-runner.config.mjs b/web-test-runner.config.mjs new file mode 100644 index 0000000..c8179f6 --- /dev/null +++ b/web-test-runner.config.mjs @@ -0,0 +1,5 @@ +import {esbuildPlugin} from '@web/dev-server-esbuild' + +export default { + plugins: [esbuildPlugin({ts: true})], +}