Skip to content

Commit 3ffbae1

Browse files
authoredFeb 11, 2025··
Automate creation of READMEs and example creation scripts (#27)
1 parent 5d77454 commit 3ffbae1

21 files changed

+672
-50
lines changed
 

‎.gitignore

+1
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

+11-8
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

+11-8
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

+12
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

+16
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

+36
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

+4
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

+30
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

+23
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

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './typescript';
+41
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+
}`;
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './vanilla_rspack_recipe';
2+
export * from './vanilla_webpack_recipe';
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { Recipe } from '../../recipe';
2+
import { CommandStep, CreateFileStep, MergeJsonStep } from '../../step';
3+
import { baseTSConfig, baseTypeScriptExample } from './common';
4+
5+
export class VanillaWebpackRecipe extends Recipe {
6+
constructor() {
7+
super(
8+
'typescript',
9+
'vanilla',
10+
'webpack',
11+
);
12+
13+
this.add(new CommandStep(
14+
'Create initial `package.json` (`npm` project settings)',
15+
['npm init --yes']
16+
));
17+
18+
this.add(new CommandStep(
19+
'Install dev dependencies',
20+
['npm install --save-dev typescript webpack webpack-cli webpack-dev-server ts-node ts-loader']
21+
));
22+
23+
this.add(new CreateFileStep(
24+
'Create typescript configuration `tsconfig.json`',
25+
'tsconfig.json',
26+
baseTSConfig
27+
));
28+
29+
this.add(new CreateFileStep(
30+
'Create webpack configuration `webpack.config.ts`',
31+
'webpack.config.ts',
32+
`import path from 'path';
33+
import webpack from 'webpack';
34+
import 'webpack-dev-server';
35+
36+
const config: webpack.Configuration = {
37+
entry: './src/index.ts',
38+
mode: 'development',
39+
module: {
40+
rules: [
41+
{ test: /\\.ts/, use: "ts-loader", exclude: /node_modules/ }
42+
],
43+
},
44+
output: { filename: 'bundle.js' },
45+
devServer: {
46+
static: {
47+
directory: path.join(__dirname, 'assets'),
48+
},
49+
port: 4500,
50+
},
51+
};
52+
53+
export default config;`)
54+
);
55+
56+
this.add(new CreateFileStep(
57+
'Create HTML file `assets/index.html`',
58+
'assets/index.html',
59+
`<!DOCTYPE html>
60+
<html>
61+
<head>
62+
<title>BokehJS example: typescript vanilla webpack</title>
63+
<script src="bundle.js"></script>
64+
</head>
65+
<body>
66+
<div id="target"></div>
67+
</body>
68+
</html>`)
69+
);
70+
71+
this.add(new CreateFileStep(
72+
'Create source typescript file `src/index.ts`',
73+
'src/index.ts',
74+
'console.log("Successfully loaded")'
75+
));
76+
77+
this.add(new MergeJsonStep(
78+
'Add `build` and `serve` commands to the `scripts` section of `package.json`',
79+
'package.json',
80+
`{
81+
"scripts": {
82+
"build": "webpack build",
83+
"serve": "webpack serve"
84+
}
85+
}`)
86+
);
87+
88+
this.add(new CommandStep(
89+
'Build and run basic example without any BokehJS',
90+
['npm install', 'npm run build', 'npm run serve'],
91+
'In a web browser navigate to http://localhost:4500/',
92+
true
93+
));
94+
95+
this.add(new CommandStep(
96+
'Add BokehJS dependency to this project. This assumes the package has been built and ' +
97+
'copied to the root directory of this repository as outlined in the top-level `README.md`.',
98+
['npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz']
99+
));
100+
101+
this.add(new CreateFileStep(
102+
'Replace contents of `src/index.ts` with code to create BokehJS plot',
103+
'src/index.ts',
104+
baseTypeScriptExample + '\n\ncreate_bokehjs_plot("#target");'
105+
));
106+
107+
this.add(new CommandStep(
108+
'Rebuild and serve',
109+
['npm install', 'npm run build', 'npm run serve'],
110+
'In a web browser navigate to http://localhost:4500/'
111+
));
112+
}
113+
}

‎recipes/src/runner.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { BashWriter, ReadmeWriter, Recipe, Writer } from '.';
2+
import * as allRecipes from './recipes/typescript';
3+
4+
const writers: Writer[] = [new BashWriter(), new ReadmeWriter()];
5+
6+
for (const cls of Object.values(allRecipes)) {
7+
const recipe: Recipe = new (cls as any)();
8+
console.log(`Recipe ${recipe.type} ${recipe.framework} ${recipe.bundler}`);
9+
10+
for (const writer of writers) {
11+
console.log(` Writing to ${writer.filename(recipe)}`);
12+
writer.write(recipe);
13+
}
14+
}

‎recipes/src/step.ts

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import * as fs from 'node:fs';
2+
import * as path from 'node:path';
3+
4+
import { fileExtension, languageFromExtension, removeBackticks } from './util';
5+
6+
/**
7+
* Single step of a recipe.
8+
*/
9+
export abstract class Step { //} implements IWriteVisitor {
10+
constructor(readonly description: string) {}
11+
12+
abstract writeToBash(fd: number, index: number): void;
13+
14+
abstract writeToReadme(fd: number, index: number): void;
15+
16+
protected writeDescriptionBash(fd: number, index: number, suffix: string = ''): void {
17+
fs.writeSync(fd, `\n# ${index+1}. ${removeBackticks(this.description)}${suffix}\n`);
18+
}
19+
20+
protected writeDescriptionReadme(fd: number, index: number, suffix: string = ''): void {
21+
fs.writeSync(fd, `\n${index+1}. ${this.description}${suffix}\n`);
22+
}
23+
24+
protected spacer = ' '; // Spacer for indented lines in README.
25+
}
26+
27+
/**
28+
* Step consisting of one or more shell commands.
29+
*/
30+
export class CommandStep extends Step {
31+
constructor(
32+
readonly description: string,
33+
readonly commands: string[],
34+
readonly postscript: string = '',
35+
readonly ignoreIfBash: boolean = false
36+
) {
37+
super(description);
38+
}
39+
40+
writeToBash(fd: number, index: number): void {
41+
this.writeDescriptionBash(fd, index);
42+
43+
const allPrefix = this.ignoreIfBash ? '# ' : '';
44+
for (const command of this.commands) {
45+
const prefix = command === 'npm run serve' ? '# ' : allPrefix;
46+
fs.writeSync(fd, prefix + command + '\n');
47+
}
48+
if (this.postscript) {
49+
fs.writeSync(fd, '# ' + this.postscript + '\n');
50+
}
51+
}
52+
53+
writeToReadme(fd: number, index: number): void {
54+
this.writeDescriptionReadme(fd, index);
55+
56+
const { spacer } = this;
57+
fs.writeSync(fd, '\n' + spacer + '```bash\n');
58+
for (const command of this.commands) {
59+
fs.writeSync(fd, spacer + command + '\n');
60+
}
61+
fs.writeSync(fd, spacer + '```\n');
62+
63+
if (this.postscript) {
64+
fs.writeSync(fd, '\n' + spacer + this.postscript + '\n');
65+
}
66+
}
67+
}
68+
69+
/**
70+
* Step to create a file.
71+
*/
72+
export class CreateFileStep extends Step {
73+
constructor(readonly description: string, readonly filename: string, readonly contents: string) {
74+
super(description);
75+
}
76+
77+
writeToBash(fd: number, index: number): void {
78+
this.writeDescriptionBash(fd, index);
79+
80+
const dirname = path.dirname(this.filename);
81+
if (dirname !== '.') {
82+
fs.writeSync(fd, `mkdir -p ${dirname}\n`);
83+
}
84+
85+
fs.writeSync(fd, `cat > ${this.filename} << EOF\n`);
86+
fs.writeSync(fd, this.contents);
87+
if (this.contents.at(-1) !== '\n') {
88+
fs.writeSync(fd, '\n');
89+
}
90+
fs.writeSync(fd, 'EOF\n');
91+
}
92+
93+
writeToReadme(fd: number, index: number): void {
94+
this.writeDescriptionReadme(fd, index, ' containing');
95+
96+
const { spacer } = this;
97+
const language = languageFromExtension(this.filename);
98+
fs.writeSync(fd, '\n' + spacer + '```' + language + '\n');
99+
for (const line of this.contents.split('\n')) {
100+
if (line) {
101+
fs.writeSync(fd, spacer + line + '\n');
102+
} else {
103+
fs.writeSync(fd, '\n');
104+
}
105+
}
106+
fs.writeSync(fd, spacer + '```\n');
107+
}
108+
}
109+
110+
/**
111+
* Step to create a file.
112+
*/
113+
export class MergeJsonStep extends Step {
114+
constructor(readonly description: string, readonly filename: string, readonly toMerge: string) {
115+
super(description);
116+
}
117+
118+
writeToBash(fd: number, index: number): void {
119+
this.writeDescriptionBash(fd, index);
120+
121+
const tempFilename = 'temp' + fileExtension(this.filename);
122+
fs.writeSync(fd, `cat > ${tempFilename} << EOF\n`);
123+
fs.writeSync(fd, this.toMerge);
124+
if (this.toMerge.at(-1) !== '\n') {
125+
fs.writeSync(fd, '\n');
126+
}
127+
fs.writeSync(fd, 'EOF\n');
128+
fs.writeSync(fd, `merge-json ${this.filename} ${tempFilename}\n`);
129+
fs.writeSync(fd, `rm ${tempFilename}\n`);
130+
}
131+
132+
writeToReadme(fd: number, index: number): void {
133+
this.writeDescriptionReadme(fd, index);
134+
135+
const { spacer } = this;
136+
const language = languageFromExtension(this.filename);
137+
fs.writeSync(fd, '\n' + spacer + '```' + language + '\n');
138+
for (const line of this.toMerge.split('\n')) {
139+
if (line) {
140+
fs.writeSync(fd, spacer + line + '\n');
141+
} else {
142+
fs.writeSync(fd, '\n');
143+
}
144+
}
145+
fs.writeSync(fd, spacer + '```\n');
146+
}
147+
}

‎recipes/src/util.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as path from 'node:path';
2+
3+
export function fileExtension(filename: string): string {
4+
const extension = path.extname(filename);
5+
return extension === '.' ? '' : extension;
6+
}
7+
8+
export function languageFromExtension(filename: string): string {
9+
const extension = fileExtension(filename);
10+
switch (extension) {
11+
case '.html': {
12+
return 'html';
13+
}
14+
case '.json': {
15+
return 'json';
16+
}
17+
case '.ts': {
18+
return 'typescript';
19+
}
20+
default: {
21+
return '';
22+
}
23+
}
24+
}
25+
26+
export function removeBackticks(text: string): string {
27+
return text.replaceAll('`', '');
28+
}

‎recipes/src/writer.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as fs from 'node:fs';
2+
3+
import { Recipe } from './recipe';
4+
import { Step } from './step';
5+
6+
export abstract class Writer {
7+
abstract filename(recipe: Recipe): string;
8+
9+
write(recipe: Recipe) {
10+
const filename = this.filename(recipe);
11+
const fd = fs.openSync(filename, 'w');
12+
13+
this.writePreable(fd, recipe);
14+
15+
for (let i = 0; i < recipe.steps.length; i++) {
16+
this.writeStep(fd, i, recipe.steps[i]);
17+
}
18+
19+
fs.closeSync(fd);
20+
}
21+
22+
protected abstract writeStep(fd: number, index: number, step: Step): void;
23+
24+
protected abstract writePreable(fd: number, recipe: Recipe): void;
25+
}

‎recipes/tsconfig.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true,
4+
"module": "nodenext",
5+
"outDir": "./dist",
6+
"rootDir": "./src",
7+
"target": "ES2022"
8+
},
9+
"include": ["src"]
10+
}

‎typescript/vanilla_rspack/README.md

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
21
# Vanilla (no framework) rspack typescript example
32

4-
This is almost identical to the vanilla webpack example, as `rspack` is designed to be a drop-in
5-
replacement for `webpack`.
3+
This is almost identical to the vanilla webpack example, as `rspack` is designed to be a drop-in replacement for `webpack`.
64

75
1. Create initial `package.json` (`npm` project settings)
86

@@ -16,7 +14,7 @@ replacement for `webpack`.
1614
npm install --save-dev typescript @rspack/core @rspack/cli ts-node ts-loader
1715
```
1816

19-
3. Create typescript configuration `tsconfig.json` containing:
17+
3. Create typescript configuration `tsconfig.json` containing
2018

2119
```json
2220
{
@@ -32,7 +30,7 @@ replacement for `webpack`.
3230
}
3331
```
3432

35-
4. Create webpack configuration `rspack.config.ts` containing:
33+
4. Create rspack configuration `rspack.config.ts` containing
3634

3735
```typescript
3836
import path from 'path';
@@ -58,7 +56,7 @@ replacement for `webpack`.
5856
export default config;
5957
```
6058
61-
5. Create HTML file `assets/index.html` containing:
59+
5. Create HTML file `assets/index.html` containing
6260
6361
```html
6462
<!DOCTYPE html>
@@ -73,18 +71,20 @@ replacement for `webpack`.
7371
</html>
7472
```
7573
76-
6. Create source typescript file `src/index.ts` containing:
74+
6. Create source typescript file `src/index.ts` containing
7775
78-
```ts
76+
```typescript
7977
console.log("Successfully loaded")
8078
```
8179
82-
7. Add build and serve commands to the `scripts` section of `package.json`:
80+
7. Add `build` and `serve` commands to the `scripts` section of `package.json`
8381
8482
```json
85-
"scripts": {
86-
"build": "rspack build",
87-
"serve": "rspack serve"
83+
{
84+
"scripts": {
85+
"build": "rspack build",
86+
"serve": "rspack serve"
87+
}
8888
}
8989
```
9090
@@ -96,16 +96,15 @@ replacement for `webpack`.
9696
npm run serve
9797
```
9898
99-
In a web browser navigate to http://localhost:4500/
99+
In a web browser navigate to http://localhost:4500/
100100
101-
9. Add BokehJS dependency to the project. This assumes the package has been built and copied to the
102-
root directory of this repository as outlined in the top-level README.md.
101+
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`.
103102
104103
```bash
105104
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz
106105
```
107106
108-
10. Remove contents of `src/index.ts` and replace with code to create BokehJS plot:
107+
10. Replace contents of `src/index.ts` with code to create BokehJS plot containing
109108
110109
```typescript
111110
import * as Bokeh from "@bokeh/bokehjs";
@@ -144,7 +143,7 @@ replacement for `webpack`.
144143
```bash
145144
npm install
146145
npm run build
147-
#npm run serve
146+
npm run serve
148147
```
149148
150-
In a web browser navigate to http://localhost:4500/
149+
In a web browser navigate to http://localhost:4500/

‎typescript/vanilla_webpack/README.md

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# Vanilla (no framework) webpack typescript example
32

43
1. Create initial `package.json` (`npm` project settings)
@@ -13,7 +12,7 @@
1312
npm install --save-dev typescript webpack webpack-cli webpack-dev-server ts-node ts-loader
1413
```
1514

16-
3. Create typescript configuration `tsconfig.json` containing:
15+
3. Create typescript configuration `tsconfig.json` containing
1716

1817
```json
1918
{
@@ -29,7 +28,7 @@
2928
}
3029
```
3130

32-
4. Create webpack configuration `webpack.config.ts` containing:
31+
4. Create webpack configuration `webpack.config.ts` containing
3332

3433
```typescript
3534
import path from 'path';
@@ -56,7 +55,7 @@
5655
export default config;
5756
```
5857
59-
5. Create HTML file `assets/index.html` containing:
58+
5. Create HTML file `assets/index.html` containing
6059
6160
```html
6261
<!DOCTYPE html>
@@ -71,18 +70,20 @@
7170
</html>
7271
```
7372
74-
6. Create source typescript file `src/index.ts` containing:
73+
6. Create source typescript file `src/index.ts` containing
7574
76-
```ts
75+
```typescript
7776
console.log("Successfully loaded")
7877
```
7978
80-
7. Add build and serve commands to the `scripts` section of `package.json`:
79+
7. Add `build` and `serve` commands to the `scripts` section of `package.json`
8180
8281
```json
83-
"scripts": {
84-
"build": "webpack build",
85-
"serve": "webpack serve"
82+
{
83+
"scripts": {
84+
"build": "webpack build",
85+
"serve": "webpack serve"
86+
}
8687
}
8788
```
8889
@@ -94,16 +95,15 @@
9495
npm run serve
9596
```
9697
97-
In a web browser navigate to http://localhost:4500/
98+
In a web browser navigate to http://localhost:4500/
9899
99-
9. Add BokehJS dependency to the project. This assumes the package has been built and copied to the
100-
root directory of this repository as outlined in the top-level README.md.
100+
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`.
101101
102102
```bash
103103
npm install ../../../../bokeh-bokehjs-3.7.0-dev.5.tgz
104104
```
105105
106-
10. Remove contents of `src/index.ts` and replace with code to create BokehJS plot:
106+
10. Replace contents of `src/index.ts` with code to create BokehJS plot containing
107107
108108
```typescript
109109
import * as Bokeh from "@bokeh/bokehjs";
@@ -142,7 +142,7 @@
142142
```bash
143143
npm install
144144
npm run build
145-
#npm run serve
145+
npm run serve
146146
```
147147
148-
In a web browser navigate to http://localhost:4500/
148+
In a web browser navigate to http://localhost:4500/

0 commit comments

Comments
 (0)
Please sign in to comment.