Skip to content

Commit 355b769

Browse files
committed
feat(create-itk-wasm): initial addition
Also make improvements to itk-wasm so the default output will successfully build and run smoke tests out-of-the-box.
1 parent 246f8ff commit 355b769

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3130
-260
lines changed

examples/mean-squares-versor-registration/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"build:micromamba": "itk-wasm pnpm-script build:micromamba",
2828
"build:python:versionSync": "itk-wasm pnpm-script build:python:versionSync",
2929
"publish:python": "itk-wasm pnpm-script publish:python",
30-
"test:data:download": "dam download test/data test/data.tar.gz bafkreiha6oye3fd5cxfadnua5r2jlkaco2xuyeek454d2ihiffsx7rauqe https://placeholder",
30+
"test:data:download": "dam download test/data test/data.tar.gz bafkreicshtctpbmvs4a6jn5pvk2mb6by5vtf2gwx47bulifejtyakhkugy ",
3131
"test:data:pack": "dam pack test/data test/data.tar.gz",
3232
"test:python:wasi": "itk-wasm pnpm-script test:python:wasi",
3333
"test:pyodide:download:emscripten": "itk-wasm pnpm-script test:pyodide:download:emscripten",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// eslint-disable-next-line no-undef
2+
module.exports = {
3+
extends: 'standard',
4+
parser: '@typescript-eslint/parser',
5+
plugins: ['@typescript-eslint'],
6+
root: true,
7+
env: { es2022: true }
8+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist/
2+
test/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# create-itk-wasm
2+
3+
CLI to create a new [ITK-Wasm](https://wasm.itk.org) project or add a pipeline to an existing project.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"name": "create-itk-wasm",
3+
"version": "1.0.1",
4+
"description": "CLI to create a new ITK-Wasm project or add a pipeline to an existing project.",
5+
"type": "module",
6+
"exports": {
7+
".": {
8+
"node": "./dist/generate-project.js",
9+
"default": "./dist/generate-project.js"
10+
}
11+
},
12+
"bin": {
13+
"create-itk-wasm": "./dist/create-itk-wasm.js"
14+
},
15+
"scripts": {
16+
"build": "tsc --pretty",
17+
"build:watch": "tsc --pretty --watch",
18+
"lint": "prettier --check .",
19+
"lint:fix": "prettier --write .",
20+
"test": "pnpm test:help && pnpm test:defaultPipeline && pnpm test:imagePipeline && pnpm test:meshPipeline && pnpm test:polyDataPipeline",
21+
"test:defaultPipeline": "shx rm -rf test/default && node dist/create-itk-wasm.js -o test/default -n \"default-pipeline\" -a \"Test Monkey\" -d \"Default pipeline description\" --pipeline-name default-pipeline --pipeline-description \"Default pipeline description\" -r \"http://test.repo\" --pipeline-inputs \"default-input:string:A default input\" --pipeline-parameters \"a-double-param:double:A double param\" --pipeline-outputs \"a-json-output:JsonCompatible:A JSON compatible output\" --no-input --build-and-test",
22+
"test:imagePipeline": "shx rm -rf test/image && node dist/create-itk-wasm.js -o test/image -n \"image-pipeline\" -a \"Test Monkey\" -d \"Image pipeline description\" --pipeline-name image-pipeline --pipeline-description \"Image pipeline description\" -r \"http://test.repo\" --pipeline-inputs \"input-image:Image:An input image\" --pipeline-parameters \"a-float-param:float:A float param\" --pipeline-outputs \"output-image:Image:An output image\" --pipeline-dispatch Image --no-input --build-and-test",
23+
"test:meshPipeline": "shx rm -rf test/mesh && node dist/create-itk-wasm.js -o test/mesh -n \"mesh-pipeline\" -a \"Test Monkey\" -d \"Mesh pipeline description\" --pipeline-name mesh-pipeline --pipeline-description \"Mesh pipeline description\" -r \"http://test.repo\" --pipeline-inputs \"input-mesh:Mesh:An input mesh\" --pipeline-parameters \"a-float-param:float:A float param\" --pipeline-outputs \"output-mesh:Mesh:An output mesh\" --pipeline-dispatch Mesh --no-input --build-and-test",
24+
"test:polyDataPipeline": "shx rm -rf test/poly-data && node dist/create-itk-wasm.js -o test/poly-data -n \"poly-data-pipeline\" -a \"Test Monkey\" -d \"PolyData pipeline description\" --pipeline-name poly-data-pipeline --pipeline-description \"PolyData pipeline description\" -r \"http://test.repo\" --pipeline-inputs \"input-poly-data:PolyData:An input poly-data\" --pipeline-parameters \"a-float-param:float:A float param\" --pipeline-outputs \"output-poly-data:PolyData:An output poly-data\" --pipeline-dispatch PolyData --no-input --build-and-test",
25+
"test:help": "node dist/create-itk-wasm.js --help"
26+
},
27+
"homepage": "https://wasm.itk.org/",
28+
"bugs": {
29+
"url": "https://github.com/InsightSoftwareConsortium/itk-wasm/issues"
30+
},
31+
"repository": {
32+
"type": "git",
33+
"url": "https://github.com/InsightSoftwareConsortium/itk-wasm.git"
34+
},
35+
"keywords": [
36+
"itk",
37+
"imaging",
38+
"wasm",
39+
"webassembly",
40+
"wasi",
41+
"io",
42+
"medical",
43+
"scientific"
44+
],
45+
"author": "Insight Software Consortium",
46+
"license": "Apache-2.0",
47+
"dependencies": {
48+
"@commander-js/extra-typings": "^12.0.0",
49+
"chalk": "^5.3.0",
50+
"commander": "^12.0.0",
51+
"figlet": "^1.7.0",
52+
"inquirer": "^9.2.14",
53+
"node-emoji": "^2.1.3",
54+
"validate-npm-package-name": "^5.0.0",
55+
"xstate": "^5.6.2"
56+
},
57+
"devDependencies": {
58+
"@types/figlet": "^1.5.8",
59+
"@types/inquirer": "^9.0.7",
60+
"@types/node": "^20.11.16",
61+
"@types/validate-npm-package-name": "^4.0.2",
62+
"eslint": "^8.56.0",
63+
"eslint-config-standard": "^17.1.0",
64+
"prettier": "^3.2.5",
65+
"prettier-config-standard": "^7.0.0",
66+
"shx": "^0.3.4",
67+
"typescript": "^5.3.3"
68+
},
69+
"prettier": "prettier-config-standard"
70+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { spawnSync } from 'child_process'
2+
3+
import die from './die.js'
4+
5+
function buildAndTest(directory: string) {
6+
const command = ['install', '&&', 'pnpm', 'build', '&&', 'pnpm', 'test']
7+
const pnpmProcess = spawnSync('pnpm', command, {
8+
env: process.env,
9+
stdio: 'inherit',
10+
shell: true,
11+
cwd: directory
12+
})
13+
if (pnpmProcess.status !== 0) {
14+
console.error(pnpmProcess.error)
15+
die(`Failed to build and test in ${directory}`)
16+
}
17+
process.exit(pnpmProcess.status)
18+
}
19+
20+
export default buildAndTest
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function camelCase(param: string): string {
2+
// make any alphabets that follows '-' an uppercase character, and remove the corresponding hyphen
3+
let cameledParam = param.replace(/-([a-z])/g, (kk) => {
4+
return kk[1].toUpperCase()
5+
})
6+
7+
// remove all non-alphanumeric characters
8+
const outParam = cameledParam.replace(/([^0-9a-z])/gi, '')
9+
10+
// check if resulting string is empty
11+
if (outParam === '') {
12+
console.error(`Resulting string is empty.`)
13+
}
14+
return outParam
15+
}
16+
17+
export default camelCase
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env node
2+
3+
import figlet from 'figlet'
4+
import chalk from 'chalk'
5+
import { createActor, waitFor } from 'xstate'
6+
7+
import die from './die.js'
8+
import ProjectSpec from './project-spec.js'
9+
import PipelineSpec from './pipeline-spec.js'
10+
import parseCliArgs from './parse-cli-args.js'
11+
import generateProject from './generate/project.js'
12+
import readFilesystemDefaults from './read-filesystem-defaults.js'
13+
import inquireMachine from './inquire/machine.js'
14+
import buildAndTest from './build-and-test.js'
15+
16+
async function main() {
17+
let pipelines: PipelineSpec[] = []
18+
19+
let { noInput, doBuildAndTest, project, pipeline } = parseCliArgs()
20+
if (pipeline) {
21+
pipelines.push(pipeline)
22+
}
23+
24+
project = readFilesystemDefaults(project)
25+
26+
if (project.name && !project.typescriptPackageName) {
27+
project.typescriptPackageName = project.name
28+
}
29+
if (project.name && !project.pythonPackageName) {
30+
project.pythonPackageName = project.name
31+
}
32+
if (!project.license) {
33+
project.license = 'Apache-2.0'
34+
}
35+
36+
if (noInput) {
37+
if (pipelines.length === 0) {
38+
die('When using --no-input, at least one pipeline must be specified.')
39+
}
40+
generateProject(project, pipelines, true)
41+
if (doBuildAndTest) {
42+
buildAndTest(project.directory)
43+
}
44+
process.exit(0)
45+
}
46+
47+
console.log(
48+
chalk.blueBright(figlet.textSync('ITK-Wasm', { horizontalLayout: 'full' }))
49+
)
50+
51+
const inquireActor = createActor(inquireMachine, {
52+
input: { project, pipelines }
53+
})
54+
inquireActor.start()
55+
const snapshot = await waitFor(
56+
inquireActor,
57+
(snapshot) => {
58+
const complete = !!snapshot.output
59+
return complete
60+
},
61+
{ timeout: 10e8 }
62+
)
63+
interface Output {
64+
project: ProjectSpec
65+
pipelines: PipelineSpec[]
66+
}
67+
const output = snapshot.output as Output
68+
project = output.project
69+
pipelines = output.pipelines
70+
71+
generateProject(project, pipelines, true)
72+
if (doBuildAndTest) {
73+
buildAndTest(project.directory)
74+
}
75+
}
76+
77+
main()
78+
.then(() => {
79+
process.exit(0)
80+
})
81+
.catch((error) => {
82+
die(error)
83+
})
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import chalk from 'chalk'
2+
3+
function die(message: string) {
4+
console.error(`\n😵 ${chalk.red(message)}`)
5+
process.exit(1)
6+
}
7+
8+
export default die

0 commit comments

Comments
 (0)