Skip to content

Commit

Permalink
Automate creation of READMEs and example creation scripts (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianthomas23 authored Feb 11, 2025
1 parent 5d77454 commit 3ffbae1
Show file tree
Hide file tree
Showing 21 changed files with 672 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
package-lock.json
ci/temp
bokeh-bokehjs-*.tgz
dist/
19 changes: 11 additions & 8 deletions ci/typescript/create_vanilla_rspack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ const config: Configuration = {
export default config;
EOF

# 5. Create HTML file
mkdir assets
# 5. Create HTML file assets/index.html
mkdir -p assets
cat > assets/index.html << EOF
<!DOCTYPE html>
<html>
Expand All @@ -75,13 +75,13 @@ cat > assets/index.html << EOF
</html>
EOF

# 6. Create source typescript file
mkdir src
# 6. Create source typescript file src/index.ts
mkdir -p src
cat > src/index.ts << EOF
console.log("Successfully loaded")
EOF

# 7. Add build and serve commands to package.json
# 7. Add build and serve commands to the scripts section of package.json
cat > temp.json << EOF
{
"scripts": {
Expand All @@ -97,11 +97,13 @@ rm temp.json
# npm install
# npm run build
# npm run serve
# In a web browser navigate to http://localhost:4500/

# 9. Add BokehJS dependency
# 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.
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz

# 10. Replace src/index.ts with code to create BokehJS plot
# 10. Replace contents of src/index.ts with code to create BokehJS plot
mkdir -p src
cat > src/index.ts << EOF
import * as Bokeh from "@bokeh/bokehjs";
Expand Down Expand Up @@ -137,4 +139,5 @@ EOF
# 11. Rebuild and serve
npm install
npm run build
#npm run serve
# npm run serve
# In a web browser navigate to http://localhost:4500/
19 changes: 11 additions & 8 deletions ci/typescript/create_vanilla_webpack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const config: webpack.Configuration = {
export default config;
EOF

# 5. Create HTML file
mkdir assets
# 5. Create HTML file assets/index.html
mkdir -p assets
cat > assets/index.html << EOF
<!DOCTYPE html>
<html>
Expand All @@ -76,13 +76,13 @@ cat > assets/index.html << EOF
</html>
EOF

# 6. Create source typescript file
mkdir src
# 6. Create source typescript file src/index.ts
mkdir -p src
cat > src/index.ts << EOF
console.log("Successfully loaded")
EOF

# 7. Add build and serve commands to package.json
# 7. Add build and serve commands to the scripts section of package.json
cat > temp.json << EOF
{
"scripts": {
Expand All @@ -98,11 +98,13 @@ rm temp.json
# npm install
# npm run build
# npm run serve
# In a web browser navigate to http://localhost:4500/

# 9. Add BokehJS dependency
# 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.
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz

# 10. Replace src/index.ts with code to create BokehJS plot
# 10. Replace contents of src/index.ts with code to create BokehJS plot
mkdir -p src
cat > src/index.ts << EOF
import * as Bokeh from "@bokeh/bokehjs";
Expand Down Expand Up @@ -138,4 +140,5 @@ EOF
# 11. Rebuild and serve
npm install
npm run build
#npm run serve
# npm run serve
# In a web browser navigate to http://localhost:4500/
12 changes: 12 additions & 0 deletions recipes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Code to create recipes. Each recipe is defined in a TypeScript class and can be written to both a
README markdown file for humans to follow, and a `bash` script that can be used to automatically
create the recipe.

To recreate all recipes:
```bash
npm install
npm run build
npm run create
```

This will overwrite all existing recipes. If you are happy with the changes, `git commit` them.
16 changes: 16 additions & 0 deletions recipes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "recipes",
"version": "1.0.0",
"license": "BSD-3-Clause",
"description": "Automated creation of recipe scripts and readme files",
"main": "index.js",
"types": "lib/index.d.ts",
"scripts": {
"build": "tsc",
"create": "node dist/runner.js"
},
"devDependencies": {
"@types/node": "^22.13.1",
"typescript": "^5.7.3"
}
}
36 changes: 36 additions & 0 deletions recipes/src/bash_writer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as fs from 'node:fs';
import * as path from 'node:path';

import { Recipe } from './recipe';
import { Step } from './step';
import { Writer } from './writer';

export class BashWriter extends Writer {
filename(recipe: Recipe): string {
return path.join(
'..', 'ci', recipe.type, 'create_' + recipe.framework + '_' + recipe.bundler + '.sh');
}

protected writeStep(fd: number, index: number, step: Step): void {
step.writeToBash(fd, index);
}

protected writePreable(fd: number, recipe: Recipe): void {
fs.writeSync(fd, `#!/usr/bin/env bash
set -eux
export OUTPUT_DIRECTORY=../temp/${recipe.type}/${recipe.framework}_${recipe.bundler}
mkdir -p $OUTPUT_DIRECTORY
cd $OUTPUT_DIRECTORY
rm -rf *
function merge-json() {
# merge the second json file into the first.
TEMP_FILE=$(mktemp)
jq '. * input' $1 $2 > TEMP_FILE && mv TEMP_FILE $1
}
`);
}
}
4 changes: 4 additions & 0 deletions recipes/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './bash_writer';
export * from './readme_writer';
export * from './recipe';
export * from './writer';
30 changes: 30 additions & 0 deletions recipes/src/readme_writer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as fs from 'node:fs';
import * as path from 'node:path';

import { Recipe } from './recipe';
import { Step } from './step';
import { Writer } from './writer';

export class ReadmeWriter extends Writer {
filename(recipe: Recipe): string {
return path.join('..', recipe.type, recipe.framework + '_' + recipe.bundler, 'README.md');
}

protected writeStep(fd: number, index: number, step: Step): void {
step.writeToReadme(fd, index);
}

protected writePreable(fd: number, recipe: Recipe): void {
const { type, bundler } = recipe;

let { details, framework } = recipe;
const prefix = framework === 'vanilla' ? ' (no framework)' : '';
framework = framework.charAt(0).toUpperCase() + framework.slice(1);

fs.writeSync(fd, `# ${framework}${prefix} ${bundler} ${type} example\n`);

if (details) {
fs.writeSync(fd, '\n' + details + '\n');
}
}
}
23 changes: 23 additions & 0 deletions recipes/src/recipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Step } from './step';

/**
* Abstract base class for recipe for making a BokehJS example, consisting of multiple steps.
*/
export abstract class Recipe {
constructor(
readonly type: string,
readonly framework: string,
readonly bundler: string,
readonly details: string = ''
) {}

protected add(step: Step): void {
this._steps.push(step);
}

get steps(): Step[] {
return this._steps;
}

private _steps: Step[] = [];
}
1 change: 1 addition & 0 deletions recipes/src/recipes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './typescript';
41 changes: 41 additions & 0 deletions recipes/src/recipes/typescript/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const baseTSConfig =
`{
"compilerOptions": {
"baseUrl": ".",
"esModuleInterop": true,
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"target": "ES2022"
},
"include": ["src"]
}`;

export const baseTypeScriptExample =
`import * as Bokeh from "@bokeh/bokehjs";
console.info("BokehJS version:", Bokeh.version);
function create_bokehjs_plot(target_id: string) {
const source = new Bokeh.ColumnDataSource({data: { x: [0.1, 0.9], y: [0.1, 0.9], size: [40, 10] }});
const plot = Bokeh.Plotting.figure({
title: "Example BokehJS plot", height: 500, width: 500,
x_range: [0, 1], y_range: [0, 1], sizing_mode: "stretch_width",
});
plot.scatter({ field: "x" }, { field: "y" }, {source, size: { field: "size" }});
const button = new Bokeh.Widgets.Button({label: "Click me to add a point", button_type: "primary"});
function button_callback() {
const data = source.data as any;
data.x.push(Math.random());
data.y.push(Math.random());
data.size.push(10 + Math.random()*30);
source.change.emit();
}
button.on_click(button_callback);
const column = new Bokeh.Column({children: [plot, button], sizing_mode: "stretch_width"});
Bokeh.Plotting.show(column, target_id);
}`;
2 changes: 2 additions & 0 deletions recipes/src/recipes/typescript/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './vanilla_rspack_recipe';
export * from './vanilla_webpack_recipe';
114 changes: 114 additions & 0 deletions recipes/src/recipes/typescript/vanilla_rspack_recipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Recipe } from '../../recipe';
import { CommandStep, CreateFileStep, MergeJsonStep } from '../../step';
import { baseTSConfig, baseTypeScriptExample } from './common';

export class VanillaRspackRecipe extends Recipe {
constructor() {
super(
'typescript',
'vanilla',
'rspack',
'This is almost identical to the vanilla webpack example, as `rspack` is designed to be a ' +
'drop-in replacement for `webpack`.'
);

this.add(new CommandStep(
'Create initial `package.json` (`npm` project settings)',
['npm init --yes']
));

this.add(new CommandStep(
'Install dev dependencies',
['npm install --save-dev typescript @rspack/core @rspack/cli ts-node ts-loader']
));

this.add(new CreateFileStep(
'Create typescript configuration `tsconfig.json`',
'tsconfig.json',
baseTSConfig
));

this.add(new CreateFileStep(
'Create rspack configuration `rspack.config.ts`',
'rspack.config.ts',
`import path from 'path';
import { Configuration } from '@rspack/cli';
const config: Configuration = {
entry: './src/index.ts',
mode: 'development',
module: {
rules: [
{ test: /\\.ts/, use: "ts-loader", exclude: /node_modules/ }
],
},
output: { filename: 'bundle.js' },
devServer: {
static: {
directory: path.join(__dirname, 'assets'),
},
port: 4500,
},
};
export default config;`)
);

this.add(new CreateFileStep(
'Create HTML file `assets/index.html`',
'assets/index.html',
`<!DOCTYPE html>
<html>
<head>
<title>BokehJS example: typescript vanilla rspack</title>
<script src="bundle.js"></script>
</head>
<body>
<div id="target"></div>
</body>
</html>`)
);

this.add(new CreateFileStep(
'Create source typescript file `src/index.ts`',
'src/index.ts',
'console.log("Successfully loaded")'
));

this.add(new MergeJsonStep(
'Add `build` and `serve` commands to the `scripts` section of `package.json`',
'package.json',
`{
"scripts": {
"build": "rspack build",
"serve": "rspack serve"
}
}`)
);

this.add(new CommandStep(
'Build and run basic example without any BokehJS',
['npm install', 'npm run build', 'npm run serve'],
'In a web browser navigate to http://localhost:4500/',
true
));

this.add(new CommandStep(
'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`.',
['npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz']
));

this.add(new CreateFileStep(
'Replace contents of `src/index.ts` with code to create BokehJS plot',
'src/index.ts',
baseTypeScriptExample + '\n\ncreate_bokehjs_plot("#target");'
));

this.add(new CommandStep(
'Rebuild and serve',
['npm install', 'npm run build', 'npm run serve'],
'In a web browser navigate to http://localhost:4500/'
));
}
}
Loading

0 comments on commit 3ffbae1

Please sign in to comment.