create-leaderboard-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +185 -0
- package/dist/templates/index-ts.js +137 -0
- package/dist/templates/package-json.js +31 -0
- package/dist/templates/readme.js +59 -0
- package/dist/templates/test-ts.js +97 -0
- package/dist/templates/tsconfig.js +31 -0
- package/dist/templates/vitest-config.js +14 -0
- package/dist/types.js +4 -0
- package/package.json +35 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Create Leaderboard Plugin CLI Tool
|
|
4
|
+
*
|
|
5
|
+
* Generates a new leaderboard plugin project structure
|
|
6
|
+
*/
|
|
7
|
+
import { readFile } from "fs/promises";
|
|
8
|
+
import { join, resolve } from "path";
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync } from "fs";
|
|
10
|
+
import prompts from "prompts";
|
|
11
|
+
import { generatePackageJson } from "./templates/package-json";
|
|
12
|
+
import { generateTsConfig } from "./templates/tsconfig";
|
|
13
|
+
import { generateVitestConfig } from "./templates/vitest-config";
|
|
14
|
+
import { generateIndexTs } from "./templates/index-ts";
|
|
15
|
+
import { generateTestTs } from "./templates/test-ts";
|
|
16
|
+
import { generateReadme } from "./templates/readme";
|
|
17
|
+
/**
|
|
18
|
+
* Validate plugin name format (alphanumeric + hyphens, no spaces)
|
|
19
|
+
*/
|
|
20
|
+
function validatePluginName(name) {
|
|
21
|
+
return /^[a-z0-9-]+$/.test(name) && name.length > 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get default author from root package.json or environment
|
|
25
|
+
*/
|
|
26
|
+
async function getDefaultAuthor() {
|
|
27
|
+
try {
|
|
28
|
+
const rootPackageJsonPath = resolve(process.cwd(), "package.json");
|
|
29
|
+
if (existsSync(rootPackageJsonPath)) {
|
|
30
|
+
const content = await readFile(rootPackageJsonPath, "utf-8");
|
|
31
|
+
const pkg = JSON.parse(content);
|
|
32
|
+
if (pkg.author) {
|
|
33
|
+
return pkg.author;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Ignore errors
|
|
39
|
+
}
|
|
40
|
+
return "Open Healthcare Network";
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Prompt user for plugin information
|
|
44
|
+
*/
|
|
45
|
+
async function promptUser() {
|
|
46
|
+
const defaultAuthor = await getDefaultAuthor();
|
|
47
|
+
const response = await prompts([
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
name: "pluginName",
|
|
51
|
+
message: "Plugin name (e.g., 'github', 'slack'):",
|
|
52
|
+
validate: (value) => {
|
|
53
|
+
if (!value)
|
|
54
|
+
return "Plugin name is required";
|
|
55
|
+
if (!validatePluginName(value)) {
|
|
56
|
+
return "Plugin name must contain only lowercase letters, numbers, and hyphens";
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: "text",
|
|
63
|
+
name: "description",
|
|
64
|
+
message: "Plugin description:",
|
|
65
|
+
validate: (value) => {
|
|
66
|
+
if (!value)
|
|
67
|
+
return "Description is required";
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: "text",
|
|
73
|
+
name: "author",
|
|
74
|
+
message: "Author:",
|
|
75
|
+
initial: defaultAuthor,
|
|
76
|
+
validate: (value) => {
|
|
77
|
+
if (!value)
|
|
78
|
+
return "Author is required";
|
|
79
|
+
return true;
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
if (!response.pluginName || !response.description || !response.author) {
|
|
84
|
+
console.error("Creation cancelled.");
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
pluginName: response.pluginName,
|
|
89
|
+
description: response.description,
|
|
90
|
+
author: response.author,
|
|
91
|
+
packageName: `@leaderboard/plugin-${response.pluginName}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create directory structure
|
|
96
|
+
*/
|
|
97
|
+
function createDirectoryStructure(pluginDir) {
|
|
98
|
+
const dirs = [
|
|
99
|
+
pluginDir,
|
|
100
|
+
join(pluginDir, "src"),
|
|
101
|
+
join(pluginDir, "src", "__tests__"),
|
|
102
|
+
];
|
|
103
|
+
for (const dir of dirs) {
|
|
104
|
+
if (!existsSync(dir)) {
|
|
105
|
+
mkdirSync(dir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Generate plugin files
|
|
111
|
+
*/
|
|
112
|
+
function generateFiles(pluginDir, options) {
|
|
113
|
+
// package.json
|
|
114
|
+
writeFileSync(join(pluginDir, "package.json"), generatePackageJson(options), "utf-8");
|
|
115
|
+
// tsconfig.json
|
|
116
|
+
writeFileSync(join(pluginDir, "tsconfig.json"), generateTsConfig(), "utf-8");
|
|
117
|
+
// vitest.config.ts
|
|
118
|
+
writeFileSync(join(pluginDir, "vitest.config.ts"), generateVitestConfig(), "utf-8");
|
|
119
|
+
// src/index.ts
|
|
120
|
+
writeFileSync(join(pluginDir, "src", "index.ts"), generateIndexTs(options), "utf-8");
|
|
121
|
+
// src/__tests__/plugin.test.ts
|
|
122
|
+
writeFileSync(join(pluginDir, "src", "__tests__", "plugin.test.ts"), generateTestTs(options), "utf-8");
|
|
123
|
+
// README.md
|
|
124
|
+
writeFileSync(join(pluginDir, "README.md"), generateReadme(options), "utf-8");
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Main function
|
|
128
|
+
*/
|
|
129
|
+
async function main() {
|
|
130
|
+
console.log("Create Leaderboard Plugin\n");
|
|
131
|
+
// Show usage if help flag is provided
|
|
132
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
133
|
+
console.log("Usage: pnpm create-leaderboard-plugin [target-directory]");
|
|
134
|
+
console.log("\nArguments:");
|
|
135
|
+
console.log(" target-directory Directory where the plugin will be created (default: current directory)");
|
|
136
|
+
console.log("\nExamples:");
|
|
137
|
+
console.log(" pnpm create-leaderboard-plugin .");
|
|
138
|
+
console.log(" pnpm create-leaderboard-plugin ../../plugins/slack");
|
|
139
|
+
console.log(" pnpm create-leaderboard-plugin my-plugin");
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
142
|
+
// Get target directory from command line args (default to current directory)
|
|
143
|
+
const targetArg = process.argv[2] || ".";
|
|
144
|
+
const targetDir = resolve(process.cwd(), targetArg);
|
|
145
|
+
// Check if target directory exists and is not empty
|
|
146
|
+
if (existsSync(targetDir)) {
|
|
147
|
+
const files = readdirSync(targetDir);
|
|
148
|
+
if (files.length > 0) {
|
|
149
|
+
console.error(`Error: Directory "${targetArg}" is not empty.`);
|
|
150
|
+
console.error("Please specify an empty directory or a new directory path.");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Prompt for information
|
|
155
|
+
const options = await promptUser();
|
|
156
|
+
try {
|
|
157
|
+
// Create directory structure
|
|
158
|
+
console.log(`Creating plugin in: ${targetDir}`);
|
|
159
|
+
createDirectoryStructure(targetDir);
|
|
160
|
+
// Generate files
|
|
161
|
+
console.log("Generating plugin files...");
|
|
162
|
+
generateFiles(targetDir, options);
|
|
163
|
+
console.log(`\n✓ Plugin "${options.packageName}" created successfully!`);
|
|
164
|
+
console.log(`\nNext steps:`);
|
|
165
|
+
if (targetArg !== ".") {
|
|
166
|
+
console.log(` 1. cd ${targetArg}`);
|
|
167
|
+
console.log(` 2. pnpm install`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.log(` 1. pnpm install`);
|
|
171
|
+
}
|
|
172
|
+
console.log(` ${targetArg !== "." ? "3" : "2"}. Implement your plugin logic in src/index.ts`);
|
|
173
|
+
console.log(` ${targetArg !== "." ? "4" : "3"}. pnpm build`);
|
|
174
|
+
console.log(` ${targetArg !== "." ? "5" : "4"}. Add the plugin to your config.yaml`);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.error("Error creating plugin:", error);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Run main function
|
|
182
|
+
main().catch((error) => {
|
|
183
|
+
console.error("Unhandled error:", error);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate src/index.ts template
|
|
3
|
+
*/
|
|
4
|
+
export function generateIndexTs(options) {
|
|
5
|
+
return `/**
|
|
6
|
+
* ${options.description}
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
activityDefinitionQueries,
|
|
11
|
+
activityQueries,
|
|
12
|
+
contributorQueries,
|
|
13
|
+
contributorAggregateDefinitionQueries,
|
|
14
|
+
contributorAggregateQueries,
|
|
15
|
+
badgeDefinitionQueries,
|
|
16
|
+
contributorBadgeQueries,
|
|
17
|
+
type Plugin,
|
|
18
|
+
type PluginContext,
|
|
19
|
+
} from "@ohcnetwork/leaderboard-api";
|
|
20
|
+
|
|
21
|
+
const plugin: Plugin = {
|
|
22
|
+
name: "${options.packageName}",
|
|
23
|
+
version: "0.1.0",
|
|
24
|
+
|
|
25
|
+
async setup(ctx: PluginContext) {
|
|
26
|
+
ctx.logger.info("Setting up ${options.pluginName} plugin...");
|
|
27
|
+
|
|
28
|
+
// TODO: Define activity types here
|
|
29
|
+
// Example:
|
|
30
|
+
// await activityDefinitionQueries.insertOrIgnore(ctx.db, {
|
|
31
|
+
// slug: "activity_slug",
|
|
32
|
+
// name: "Activity Name",
|
|
33
|
+
// description: "Activity description",
|
|
34
|
+
// points: 10,
|
|
35
|
+
// icon: "icon-name",
|
|
36
|
+
// });
|
|
37
|
+
|
|
38
|
+
// TODO: Define contributor aggregate definitions (optional)
|
|
39
|
+
// Example:
|
|
40
|
+
// await contributorAggregateDefinitionQueries.upsert(ctx.db, {
|
|
41
|
+
// slug: "custom_metric",
|
|
42
|
+
// name: "Custom Metric",
|
|
43
|
+
// description: "Example custom metric",
|
|
44
|
+
// });
|
|
45
|
+
|
|
46
|
+
// TODO: Define badge definitions (optional)
|
|
47
|
+
// Example:
|
|
48
|
+
// await badgeDefinitionQueries.upsert(ctx.db, {
|
|
49
|
+
// slug: "example_badge",
|
|
50
|
+
// name: "Example Badge",
|
|
51
|
+
// description: "Achievement badge for custom criteria",
|
|
52
|
+
// variants: {
|
|
53
|
+
// bronze: {
|
|
54
|
+
// description: "Level 1",
|
|
55
|
+
// svg_url: "https://example.com/bronze.svg",
|
|
56
|
+
// },
|
|
57
|
+
// silver: {
|
|
58
|
+
// description: "Level 2",
|
|
59
|
+
// svg_url: "https://example.com/silver.svg",
|
|
60
|
+
// },
|
|
61
|
+
// gold: {
|
|
62
|
+
// description: "Level 3",
|
|
63
|
+
// svg_url: "https://example.com/gold.svg",
|
|
64
|
+
// },
|
|
65
|
+
// },
|
|
66
|
+
// });
|
|
67
|
+
|
|
68
|
+
ctx.logger.info("Setup complete");
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
async scrape(ctx: PluginContext) {
|
|
72
|
+
ctx.logger.info("Starting ${options.pluginName} data scraping...");
|
|
73
|
+
|
|
74
|
+
// TODO: Implement your scraping logic here
|
|
75
|
+
// Example:
|
|
76
|
+
// const data = await fetchDataFromSource(ctx.config);
|
|
77
|
+
//
|
|
78
|
+
// for (const item of data) {
|
|
79
|
+
// // Ensure contributor exists
|
|
80
|
+
// await contributorQueries.upsert(ctx.db, {
|
|
81
|
+
// username: item.user.username,
|
|
82
|
+
// name: item.user.name,
|
|
83
|
+
// role: null,
|
|
84
|
+
// title: null,
|
|
85
|
+
// avatar_url: item.user.avatar_url,
|
|
86
|
+
// bio: null,
|
|
87
|
+
// social_profiles: null,
|
|
88
|
+
// joining_date: null,
|
|
89
|
+
// meta: null,
|
|
90
|
+
// });
|
|
91
|
+
//
|
|
92
|
+
// // Insert activity
|
|
93
|
+
// await activityQueries.upsert(ctx.db, {
|
|
94
|
+
// slug: \`activity-\${item.id}\`,
|
|
95
|
+
// contributor: item.user.username,
|
|
96
|
+
// activity_definition: "activity_slug",
|
|
97
|
+
// title: item.title,
|
|
98
|
+
// occured_at: new Date(item.timestamp).toISOString(),
|
|
99
|
+
// link: item.url,
|
|
100
|
+
// text: item.description,
|
|
101
|
+
// points: null, // Uses default from activity_definition
|
|
102
|
+
// meta: null,
|
|
103
|
+
// });
|
|
104
|
+
// }
|
|
105
|
+
|
|
106
|
+
// TODO: Set custom aggregates (optional)
|
|
107
|
+
// Example:
|
|
108
|
+
// await contributorAggregateQueries.upsert(ctx.db, {
|
|
109
|
+
// aggregate: "custom_metric",
|
|
110
|
+
// contributor: "username",
|
|
111
|
+
// value: {
|
|
112
|
+
// type: "number",
|
|
113
|
+
// value: 42,
|
|
114
|
+
// unit: "items",
|
|
115
|
+
// format: "integer",
|
|
116
|
+
// },
|
|
117
|
+
// meta: { source: "external_api" },
|
|
118
|
+
// });
|
|
119
|
+
|
|
120
|
+
// TODO: Award custom badges (optional)
|
|
121
|
+
// Example:
|
|
122
|
+
// await contributorBadgeQueries.award(ctx.db, {
|
|
123
|
+
// slug: \`example_badge__username__bronze\`,
|
|
124
|
+
// badge: "example_badge",
|
|
125
|
+
// contributor: "username",
|
|
126
|
+
// variant: "bronze",
|
|
127
|
+
// achieved_on: new Date().toISOString().split("T")[0],
|
|
128
|
+
// meta: { reason: "Custom criteria met" },
|
|
129
|
+
// });
|
|
130
|
+
|
|
131
|
+
ctx.logger.info("Scraping complete");
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export default plugin;
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate package.json template
|
|
3
|
+
*/
|
|
4
|
+
export function generatePackageJson(options) {
|
|
5
|
+
// Use JSON.stringify to safely escape strings
|
|
6
|
+
const pkg = {
|
|
7
|
+
name: options.packageName,
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
description: options.description,
|
|
10
|
+
type: "module",
|
|
11
|
+
main: "dist/index.js",
|
|
12
|
+
types: "dist/index.d.ts",
|
|
13
|
+
scripts: {
|
|
14
|
+
build: "tsc",
|
|
15
|
+
test: "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
},
|
|
18
|
+
keywords: ["leaderboard", "plugin"],
|
|
19
|
+
dependencies: {
|
|
20
|
+
"@ohcnetwork/leaderboard-api": "^0.1.0",
|
|
21
|
+
},
|
|
22
|
+
devDependencies: {
|
|
23
|
+
"@types/node": "^20.19.27",
|
|
24
|
+
typescript: "^5.7.3",
|
|
25
|
+
vitest: "^4.0.16",
|
|
26
|
+
},
|
|
27
|
+
author: options.author,
|
|
28
|
+
license: "MIT",
|
|
29
|
+
};
|
|
30
|
+
return JSON.stringify(pkg, null, 2) + "\n";
|
|
31
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate README.md template
|
|
3
|
+
*/
|
|
4
|
+
export function generateReadme(options) {
|
|
5
|
+
const displayName = options.pluginName
|
|
6
|
+
.split("-")
|
|
7
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
8
|
+
.join(" ");
|
|
9
|
+
return `# ${options.packageName}
|
|
10
|
+
|
|
11
|
+
${options.description}
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
Add the plugin to your \`config.yaml\`:
|
|
16
|
+
|
|
17
|
+
\`\`\`yaml
|
|
18
|
+
leaderboard:
|
|
19
|
+
plugins:
|
|
20
|
+
${options.pluginName}:
|
|
21
|
+
source: "${options.packageName}"
|
|
22
|
+
config:
|
|
23
|
+
# TODO: Add your plugin configuration options here
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
1. Build the plugin:
|
|
29
|
+
|
|
30
|
+
\`\`\`bash
|
|
31
|
+
pnpm build
|
|
32
|
+
\`\`\`
|
|
33
|
+
|
|
34
|
+
2. Add the plugin to your \`config.yaml\` (see Configuration above)
|
|
35
|
+
|
|
36
|
+
3. Run the plugin runner:
|
|
37
|
+
|
|
38
|
+
\`\`\`bash
|
|
39
|
+
pnpm data:scrape
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
## Development
|
|
43
|
+
|
|
44
|
+
\`\`\`bash
|
|
45
|
+
# Build the plugin
|
|
46
|
+
pnpm build
|
|
47
|
+
|
|
48
|
+
# Run tests
|
|
49
|
+
pnpm test
|
|
50
|
+
|
|
51
|
+
# Watch mode
|
|
52
|
+
pnpm test:watch
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate src/__tests__/plugin.test.ts template
|
|
3
|
+
*/
|
|
4
|
+
export function generateTestTs(options) {
|
|
5
|
+
return `/**
|
|
6
|
+
* Tests for ${options.pluginName} plugin
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
10
|
+
import { createDatabase, initializeSchema } from "@ohcnetwork/leaderboard-api";
|
|
11
|
+
import type { Database } from "@ohcnetwork/leaderboard-api";
|
|
12
|
+
import plugin from "../index";
|
|
13
|
+
|
|
14
|
+
describe("${options.pluginName.charAt(0).toUpperCase() + options.pluginName.slice(1)} Plugin", () => {
|
|
15
|
+
let db: Database;
|
|
16
|
+
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
db = createDatabase(":memory:");
|
|
19
|
+
await initializeSchema(db);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
await db.close();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should have correct plugin metadata", () => {
|
|
27
|
+
expect(plugin.name).toBe("${options.packageName}");
|
|
28
|
+
expect(plugin.version).toBeTruthy();
|
|
29
|
+
expect(plugin.scrape).toBeDefined();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should setup activity definitions", async () => {
|
|
33
|
+
const logger = {
|
|
34
|
+
info: () => {},
|
|
35
|
+
warn: () => {},
|
|
36
|
+
error: () => {},
|
|
37
|
+
debug: () => {},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (plugin.setup) {
|
|
41
|
+
await plugin.setup({
|
|
42
|
+
db,
|
|
43
|
+
config: {},
|
|
44
|
+
orgConfig: {
|
|
45
|
+
name: "Test Org",
|
|
46
|
+
description: "Test",
|
|
47
|
+
url: "https://test.com",
|
|
48
|
+
logo_url: "https://test.com/logo.png",
|
|
49
|
+
},
|
|
50
|
+
logger,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// TODO: Add assertions for your activity definitions
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should scrape data", async () => {
|
|
58
|
+
const logger = {
|
|
59
|
+
info: () => {},
|
|
60
|
+
warn: () => {},
|
|
61
|
+
error: () => {},
|
|
62
|
+
debug: () => {},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Setup first if needed
|
|
66
|
+
if (plugin.setup) {
|
|
67
|
+
await plugin.setup({
|
|
68
|
+
db,
|
|
69
|
+
config: {},
|
|
70
|
+
orgConfig: {
|
|
71
|
+
name: "Test Org",
|
|
72
|
+
description: "Test",
|
|
73
|
+
url: "https://test.com",
|
|
74
|
+
logo_url: "https://test.com/logo.png",
|
|
75
|
+
},
|
|
76
|
+
logger,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Then scrape
|
|
81
|
+
await plugin.scrape({
|
|
82
|
+
db,
|
|
83
|
+
config: {},
|
|
84
|
+
orgConfig: {
|
|
85
|
+
name: "Test Org",
|
|
86
|
+
description: "Test",
|
|
87
|
+
url: "https://test.com",
|
|
88
|
+
logo_url: "https://test.com/logo.png",
|
|
89
|
+
},
|
|
90
|
+
logger,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// TODO: Add assertions for scraped data
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate tsconfig.json template
|
|
3
|
+
*/
|
|
4
|
+
export function generateTsConfig() {
|
|
5
|
+
return `{
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"target": "ES2017",
|
|
8
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"module": "esnext",
|
|
14
|
+
"moduleResolution": "bundler",
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"outDir": "./dist",
|
|
18
|
+
"rootDir": ".",
|
|
19
|
+
"incremental": true,
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["./*"]
|
|
22
|
+
},
|
|
23
|
+
"noUncheckedIndexedAccess": true,
|
|
24
|
+
"strictNullChecks": true
|
|
25
|
+
},
|
|
26
|
+
"include": ["**/*.ts", "**/*.mts"],
|
|
27
|
+
"exclude": ["node_modules"]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate vitest.config.ts template
|
|
3
|
+
*/
|
|
4
|
+
export function generateVitestConfig() {
|
|
5
|
+
return `import { defineConfig } from "vitest/config";
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
test: {
|
|
9
|
+
globals: true,
|
|
10
|
+
environment: "node",
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
`;
|
|
14
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-leaderboard-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tool to generate leaderboard plugin projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"private": false,
|
|
8
|
+
"bin": {
|
|
9
|
+
"create-leaderboard-plugin": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"clean": "rm -rf dist",
|
|
17
|
+
"typecheck": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"leaderboard",
|
|
21
|
+
"plugin",
|
|
22
|
+
"generator",
|
|
23
|
+
"cli"
|
|
24
|
+
],
|
|
25
|
+
"author": "Open Healthcare Network",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"prompts": "^2.4.2"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.19.27",
|
|
32
|
+
"@types/prompts": "^2.4.9",
|
|
33
|
+
"typescript": "^5.7.3"
|
|
34
|
+
}
|
|
35
|
+
}
|