Skip to content

Commit 3ffbae1

Browse files
authored
Automate creation of READMEs and example creation scripts (#27)
1 parent 5d77454 commit 3ffbae1

21 files changed

+672
-50
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
package-lock.json
33
ci/temp
44
bokeh-bokehjs-*.tgz
5+
dist/

ci/typescript/create_vanilla_rspack.sh

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ const config: Configuration = {
6060
export default config;
6161
EOF
6262

63-
# 5. Create HTML file
64-
mkdir assets
63+
# 5. Create HTML file assets/index.html
64+
mkdir -p assets
6565
cat > assets/index.html << EOF
6666
<!DOCTYPE html>
6767
<html>
@@ -75,13 +75,13 @@ cat > assets/index.html << EOF
7575
</html>
7676
EOF
7777

78-
# 6. Create source typescript file
79-
mkdir src
78+
# 6. Create source typescript file src/index.ts
79+
mkdir -p src
8080
cat > src/index.ts << EOF
8181
console.log("Successfully loaded")
8282
EOF
8383

84-
# 7. Add build and serve commands to package.json
84+
# 7. Add build and serve commands to the scripts section of package.json
8585
cat > temp.json << EOF
8686
{
8787
"scripts": {
@@ -97,11 +97,13 @@ rm temp.json
9797
# npm install
9898
# npm run build
9999
# npm run serve
100+
# In a web browser navigate to http://localhost:4500/
100101

101-
# 9. Add BokehJS dependency
102+
# 9. Add BokehJS dependency to this project. This assumes the package has been built and copied to the root directory of this repository as outlined in the top-level README.md.
102103
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz
103104

104-
# 10. Replace src/index.ts with code to create BokehJS plot
105+
# 10. Replace contents of src/index.ts with code to create BokehJS plot
106+
mkdir -p src
105107
cat > src/index.ts << EOF
106108
import * as Bokeh from "@bokeh/bokehjs";
107109
@@ -137,4 +139,5 @@ EOF
137139
# 11. Rebuild and serve
138140
npm install
139141
npm run build
140-
#npm run serve
142+
# npm run serve
143+
# In a web browser navigate to http://localhost:4500/

ci/typescript/create_vanilla_webpack.sh

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ const config: webpack.Configuration = {
6161
export default config;
6262
EOF
6363

64-
# 5. Create HTML file
65-
mkdir assets
64+
# 5. Create HTML file assets/index.html
65+
mkdir -p assets
6666
cat > assets/index.html << EOF
6767
<!DOCTYPE html>
6868
<html>
@@ -76,13 +76,13 @@ cat > assets/index.html << EOF
7676
</html>
7777
EOF
7878

79-
# 6. Create source typescript file
80-
mkdir src
79+
# 6. Create source typescript file src/index.ts
80+
mkdir -p src
8181
cat > src/index.ts << EOF
8282
console.log("Successfully loaded")
8383
EOF
8484

85-
# 7. Add build and serve commands to package.json
85+
# 7. Add build and serve commands to the scripts section of package.json
8686
cat > temp.json << EOF
8787
{
8888
"scripts": {
@@ -98,11 +98,13 @@ rm temp.json
9898
# npm install
9999
# npm run build
100100
# npm run serve
101+
# In a web browser navigate to http://localhost:4500/
101102

102-
# 9. Add BokehJS dependency
103+
# 9. Add BokehJS dependency to this project. This assumes the package has been built and copied to the root directory of this repository as outlined in the top-level README.md.
103104
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz
104105

105-
# 10. Replace src/index.ts with code to create BokehJS plot
106+
# 10. Replace contents of src/index.ts with code to create BokehJS plot
107+
mkdir -p src
106108
cat > src/index.ts << EOF
107109
import * as Bokeh from "@bokeh/bokehjs";
108110
@@ -138,4 +140,5 @@ EOF
138140
# 11. Rebuild and serve
139141
npm install
140142
npm run build
141-
#npm run serve
143+
# npm run serve
144+
# In a web browser navigate to http://localhost:4500/

recipes/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Code to create recipes. Each recipe is defined in a TypeScript class and can be written to both a
2+
README markdown file for humans to follow, and a `bash` script that can be used to automatically
3+
create the recipe.
4+
5+
To recreate all recipes:
6+
```bash
7+
npm install
8+
npm run build
9+
npm run create
10+
```
11+
12+
This will overwrite all existing recipes. If you are happy with the changes, `git commit` them.

recipes/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "recipes",
3+
"version": "1.0.0",
4+
"license": "BSD-3-Clause",
5+
"description": "Automated creation of recipe scripts and readme files",
6+
"main": "index.js",
7+
"types": "lib/index.d.ts",
8+
"scripts": {
9+
"build": "tsc",
10+
"create": "node dist/runner.js"
11+
},
12+
"devDependencies": {
13+
"@types/node": "^22.13.1",
14+
"typescript": "^5.7.3"
15+
}
16+
}

recipes/src/bash_writer.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as fs from 'node:fs';
2+
import * as path from 'node:path';
3+
4+
import { Recipe } from './recipe';
5+
import { Step } from './step';
6+
import { Writer } from './writer';
7+
8+
export class BashWriter extends Writer {
9+
filename(recipe: Recipe): string {
10+
return path.join(
11+
'..', 'ci', recipe.type, 'create_' + recipe.framework + '_' + recipe.bundler + '.sh');
12+
}
13+
14+
protected writeStep(fd: number, index: number, step: Step): void {
15+
step.writeToBash(fd, index);
16+
}
17+
18+
protected writePreable(fd: number, recipe: Recipe): void {
19+
fs.writeSync(fd, `#!/usr/bin/env bash
20+
21+
set -eux
22+
23+
export OUTPUT_DIRECTORY=../temp/${recipe.type}/${recipe.framework}_${recipe.bundler}
24+
25+
mkdir -p $OUTPUT_DIRECTORY
26+
cd $OUTPUT_DIRECTORY
27+
rm -rf *
28+
29+
function merge-json() {
30+
# merge the second json file into the first.
31+
TEMP_FILE=$(mktemp)
32+
jq '. * input' $1 $2 > TEMP_FILE && mv TEMP_FILE $1
33+
}
34+
`);
35+
}
36+
}

recipes/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './bash_writer';
2+
export * from './readme_writer';
3+
export * from './recipe';
4+
export * from './writer';

recipes/src/readme_writer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as fs from 'node:fs';
2+
import * as path from 'node:path';
3+
4+
import { Recipe } from './recipe';
5+
import { Step } from './step';
6+
import { Writer } from './writer';
7+
8+
export class ReadmeWriter extends Writer {
9+
filename(recipe: Recipe): string {
10+
return path.join('..', recipe.type, recipe.framework + '_' + recipe.bundler, 'README.md');
11+
}
12+
13+
protected writeStep(fd: number, index: number, step: Step): void {
14+
step.writeToReadme(fd, index);
15+
}
16+
17+
protected writePreable(fd: number, recipe: Recipe): void {
18+
const { type, bundler } = recipe;
19+
20+
let { details, framework } = recipe;
21+
const prefix = framework === 'vanilla' ? ' (no framework)' : '';
22+
framework = framework.charAt(0).toUpperCase() + framework.slice(1);
23+
24+
fs.writeSync(fd, `# ${framework}${prefix} ${bundler} ${type} example\n`);
25+
26+
if (details) {
27+
fs.writeSync(fd, '\n' + details + '\n');
28+
}
29+
}
30+
}

recipes/src/recipe.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Step } from './step';
2+
3+
/**
4+
* Abstract base class for recipe for making a BokehJS example, consisting of multiple steps.
5+
*/
6+
export abstract class Recipe {
7+
constructor(
8+
readonly type: string,
9+
readonly framework: string,
10+
readonly bundler: string,
11+
readonly details: string = ''
12+
) {}
13+
14+
protected add(step: Step): void {
15+
this._steps.push(step);
16+
}
17+
18+
get steps(): Step[] {
19+
return this._steps;
20+
}
21+
22+
private _steps: Step[] = [];
23+
}

recipes/src/recipes/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './typescript';
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
export const baseTSConfig =
2+
`{
3+
"compilerOptions": {
4+
"baseUrl": ".",
5+
"esModuleInterop": true,
6+
"moduleResolution": "node",
7+
"outDir": "./dist",
8+
"rootDir": "./src",
9+
"target": "ES2022"
10+
},
11+
"include": ["src"]
12+
}`;
13+
14+
export const baseTypeScriptExample =
15+
`import * as Bokeh from "@bokeh/bokehjs";
16+
17+
console.info("BokehJS version:", Bokeh.version);
18+
19+
function create_bokehjs_plot(target_id: string) {
20+
const source = new Bokeh.ColumnDataSource({data: { x: [0.1, 0.9], y: [0.1, 0.9], size: [40, 10] }});
21+
22+
const plot = Bokeh.Plotting.figure({
23+
title: "Example BokehJS plot", height: 500, width: 500,
24+
x_range: [0, 1], y_range: [0, 1], sizing_mode: "stretch_width",
25+
});
26+
27+
plot.scatter({ field: "x" }, { field: "y" }, {source, size: { field: "size" }});
28+
29+
const button = new Bokeh.Widgets.Button({label: "Click me to add a point", button_type: "primary"});
30+
function button_callback() {
31+
const data = source.data as any;
32+
data.x.push(Math.random());
33+
data.y.push(Math.random());
34+
data.size.push(10 + Math.random()*30);
35+
source.change.emit();
36+
}
37+
button.on_click(button_callback);
38+
39+
const column = new Bokeh.Column({children: [plot, button], sizing_mode: "stretch_width"});
40+
Bokeh.Plotting.show(column, target_id);
41+
}`;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './vanilla_rspack_recipe';
2+
export * from './vanilla_webpack_recipe';
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Recipe } from '../../recipe';
2+
import { CommandStep, CreateFileStep, MergeJsonStep } from '../../step';
3+
import { baseTSConfig, baseTypeScriptExample } from './common';
4+
5+
export class VanillaRspackRecipe extends Recipe {
6+
constructor() {
7+
super(
8+
'typescript',
9+
'vanilla',
10+
'rspack',
11+
'This is almost identical to the vanilla webpack example, as `rspack` is designed to be a ' +
12+
'drop-in replacement for `webpack`.'
13+
);
14+
15+
this.add(new CommandStep(
16+
'Create initial `package.json` (`npm` project settings)',
17+
['npm init --yes']
18+
));
19+
20+
this.add(new CommandStep(
21+
'Install dev dependencies',
22+
['npm install --save-dev typescript @rspack/core @rspack/cli ts-node ts-loader']
23+
));
24+
25+
this.add(new CreateFileStep(
26+
'Create typescript configuration `tsconfig.json`',
27+
'tsconfig.json',
28+
baseTSConfig
29+
));
30+
31+
this.add(new CreateFileStep(
32+
'Create rspack configuration `rspack.config.ts`',
33+
'rspack.config.ts',
34+
`import path from 'path';
35+
import { Configuration } from '@rspack/cli';
36+
37+
const config: Configuration = {
38+
entry: './src/index.ts',
39+
mode: 'development',
40+
module: {
41+
rules: [
42+
{ test: /\\.ts/, use: "ts-loader", exclude: /node_modules/ }
43+
],
44+
},
45+
output: { filename: 'bundle.js' },
46+
devServer: {
47+
static: {
48+
directory: path.join(__dirname, 'assets'),
49+
},
50+
port: 4500,
51+
},
52+
};
53+
54+
export default config;`)
55+
);
56+
57+
this.add(new CreateFileStep(
58+
'Create HTML file `assets/index.html`',
59+
'assets/index.html',
60+
`<!DOCTYPE html>
61+
<html>
62+
<head>
63+
<title>BokehJS example: typescript vanilla rspack</title>
64+
<script src="bundle.js"></script>
65+
</head>
66+
<body>
67+
<div id="target"></div>
68+
</body>
69+
</html>`)
70+
);
71+
72+
this.add(new CreateFileStep(
73+
'Create source typescript file `src/index.ts`',
74+
'src/index.ts',
75+
'console.log("Successfully loaded")'
76+
));
77+
78+
this.add(new MergeJsonStep(
79+
'Add `build` and `serve` commands to the `scripts` section of `package.json`',
80+
'package.json',
81+
`{
82+
"scripts": {
83+
"build": "rspack build",
84+
"serve": "rspack serve"
85+
}
86+
}`)
87+
);
88+
89+
this.add(new CommandStep(
90+
'Build and run basic example without any BokehJS',
91+
['npm install', 'npm run build', 'npm run serve'],
92+
'In a web browser navigate to http://localhost:4500/',
93+
true
94+
));
95+
96+
this.add(new CommandStep(
97+
'Add BokehJS dependency to this project. This assumes the package has been built and ' +
98+
'copied to the root directory of this repository as outlined in the top-level `README.md`.',
99+
['npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz']
100+
));
101+
102+
this.add(new CreateFileStep(
103+
'Replace contents of `src/index.ts` with code to create BokehJS plot',
104+
'src/index.ts',
105+
baseTypeScriptExample + '\n\ncreate_bokehjs_plot("#target");'
106+
));
107+
108+
this.add(new CommandStep(
109+
'Rebuild and serve',
110+
['npm install', 'npm run build', 'npm run serve'],
111+
'In a web browser navigate to http://localhost:4500/'
112+
));
113+
}
114+
}

0 commit comments

Comments
 (0)