feat: install moo and use in toy example (#2)

I failed to find a satisfactory way to compile and import moo.js with
  fixed specifiers, so finally I just gave up and patched the distributed
  moo code to be an es6 module. Very ugly but it works.

Resolves #1.

Reviewed-on: #2
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
Glen Whitney 2023-09-01 21:32:25 +00:00 committed by Glen Whitney
parent 67a07e2000
commit e0861ea157
11 changed files with 88 additions and 25 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
# Object files # Object files
build build
dist dist
deps
# Editor backups # Editor backups
*~ *~

View File

@ -22,7 +22,7 @@ or from a script
```js ```js
(async () => { (async () => {
const vrml1to97 = await import('vrml1to97') const vrml1to97 = await import('./dist/vrml1to97/index.js')
const vrml1spec = '# VRML 1.0 ....' const vrml1spec = '# VRML 1.0 ....'
const vrml97spec = vrml1to97.convert(vrml1spec) const vrml97spec = vrml1to97.convert(vrml1spec)
})() })()

10
etc/streamToString.js Normal file
View File

@ -0,0 +1,10 @@
export async function streamToString(stream) {
// lets have a ReadableStream as a stream variable
const chunks = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
return Buffer.concat(chunks).toString("utf-8");
}

View File

@ -5,8 +5,8 @@
<title>vrml1to97 test</title> <title>vrml1to97 test</title>
<script> <script>
(async () => { (async () => {
const vrml1to97 = await import('../dist/index.js') const vrml1to97 = await import('../dist/vrml1to97/index.js')
console.log(vrml1to97.convert('test')) console.log(vrml1to97.convert('if (moo) cows // hurray'))
})() })()
</script> </script>
</head> </head>

View File

@ -1,18 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
import {convert} from './index.js' import {convert} from './vrml1to97/index.js'
import {stdin, argv} from 'node:process' import {stdin, argv} from 'node:process'
import {streamToString} from './streamToString.js'
async function streamToString(stream) {
// lets have a ReadableStream as a stream variable
const chunks = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
return Buffer.concat(chunks).toString("utf-8");
}
if (argv.length > 2) { if (argv.length > 2) {
console.log('Usage: vrml1to97 < old.wrl > shinynew.wrl') console.log('Usage: vrml1to97 < old.wrl > shinynew.wrl')

View File

@ -4,11 +4,21 @@
description: 'JavaScript converter from VRML 1 to VRML97', description: 'JavaScript converter from VRML 1 to VRML97',
scripts: { scripts: {
test: 'echo "Error: no test specified" && exit 1', test: 'echo "Error: no test specified" && exit 1',
build_ts: 'civet -c -o build/.ts src/*civet', // Use civet to create .ts files from the source:
build_js: 'tsc', build_ts: 'mkdir -p build && civet -c -o build/.ts src/*civet',
// These next three steps get all dependencies into one place for convenience:
build_deps1: 'mkdir -p deps',
// Strip the UMD header so that es6 can import:
build_deps2: 'node tools/modulize.mjs < node_modules/moo/moo.js > deps/moo.js',
// Give Typescript the info it needs:
build_deps3: 'cp node_modules/@types/moo/index.d.ts deps/moo.d.ts',
// Use the Typescript compiler to create the final .js files:
build_js: 'tsc && mkdir -p dist/deps && cp deps/*.js dist/deps',
// And finally add the executable and minimal package.json
build_etc: 'cp etc/*.js* dist', build_etc: 'cp etc/*.js* dist',
build: 'pnpm --sequential /build_/', build: 'pnpm --sequential /build_/',
try: 'pnpm build && node dist/example.js', try: 'pnpm build && node dist/vrml1to97/example.js',
clean: 'rm -r build dist deps'
}, },
keywords: [ keywords: [
'javascript', 'javascript',
@ -27,7 +37,11 @@
}, },
devDependencies: { devDependencies: {
'@danielx/civet': '^0.6.26', '@danielx/civet': '^0.6.26',
'@types/moo': '^0.5.6',
'http-server': '^14.1.1', 'http-server': '^14.1.1',
typescript: '^5.2.2', typescript: '^5.2.2',
}, },
dependencies: {
moo: '^0.5.2',
},
} }

View File

@ -4,10 +4,18 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
dependencies:
moo:
specifier: ^0.5.2
version: 0.5.2
devDependencies: devDependencies:
'@danielx/civet': '@danielx/civet':
specifier: ^0.6.26 specifier: ^0.6.26
version: 0.6.26 version: 0.6.26
'@types/moo':
specifier: ^0.5.6
version: 0.5.6
http-server: http-server:
specifier: ^14.1.1 specifier: ^14.1.1
version: 14.1.1 version: 14.1.1
@ -48,6 +56,10 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
dev: true dev: true
/@types/moo@0.5.6:
resolution: {integrity: sha512-Q60hZhulhl2Ox4LjbJvhH+HzsKrwzLPjEB8dZw0fK1MH2HyOLe6LDou68yTfsWasxGv7DPZe5VNM5vgpzOa2nw==}
dev: true
/ansi-styles@4.3.0: /ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -233,6 +245,10 @@ packages:
minimist: 1.2.8 minimist: 1.2.8
dev: true dev: true
/moo@0.5.2:
resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==}
dev: false
/ms@2.1.3: /ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
dev: true dev: true

View File

@ -1,2 +1,2 @@
{convert} from ./index.js {convert} from ./index.js
console.log convert 'bar' console.log convert 'while (10) cows\nmoo'

View File

@ -1,14 +1,37 @@
moo from ../deps/moo.js
type Tree = {[key:string]: string | Tree} type Tree = {[key:string]: string | Tree}
lexer := moo.compile
WS: /[ \t]+/
comment: /\/\/.*?$/
number: /0|[1-9][0-9]*/
string: /"(?:\\["\\]|[^\n"\\])*"/
lparen: '('
rparen: ')'
keyword: 'while if else moo cows'.split(' ')
NL:
match: /\n/
lineBreaks: true
export function tree97(vrml1: string): Tree export function tree97(vrml1: string): Tree
{converted: 'foo'} tree: Tree := {}
for tok, index of lexer.reset vrml1
if tok.type then tree[`${index}`] = {tok.type, tok.value}
tree
function render(t: string | Tree): string function render(t: string | Tree): string
if typeof t is 'string' if typeof t is 'string'
return t return t
if result := t.converted result .= ''
render result for item of Object.values t
else '<Conversion failed>' if typeof item is 'string' then result += item + ' '
else switch item.type
'WS' // ignore
'NL'
result += "\n"
else result += render(item.type) + ' '
result
export function convert(vrml1: string): string export function convert(vrml1: string): string
render tree97 vrml1 render tree97 vrml1

9
tools/modulize.mjs Normal file
View File

@ -0,0 +1,9 @@
import {stdin, argv} from 'node:process'
import {streamToString} from '../etc/streamToString.js'
const preamble = `// ES6 Module converted from https://github.com/no-context/moo
export default (((f) => f())(function () {
`
const umd = await streamToString(stdin)
const realStart = umd.indexOf(" 'use strict'")
console.log(preamble + umd.substring(realStart))

View File

@ -5,8 +5,8 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"esModuleInterop": true, "esModuleInterop": true,
"declaration": true, "declaration": true,
"rootDir": "./build", "rootDir": "build",
"outDir": "./dist" "outDir": "dist/vrml1to97"
}, },
"ts-node": { "ts-node": {
"transpileOnly": true, "transpileOnly": true,