@bonsae/create-nrg 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/README.md +65 -0
- package/dist/index.js +104 -0
- package/dist/scaffold.js +65 -0
- package/package.json +72 -0
- package/templates/node/docs.md.hbs +3 -0
- package/templates/node/labels.json.hbs +6 -0
- package/templates/node/schema.ts.hbs +40 -0
- package/templates/node/server-index.ts.hbs +5 -0
- package/templates/node/server-node.ts.hbs +51 -0
- package/templates/project/.gitignore.hbs +6 -0
- package/templates/project/.husky/commit-msg.hbs +1 -0
- package/templates/project/.husky/pre-commit.hbs +1 -0
- package/templates/project/.prettierrc.json.hbs +5 -0
- package/templates/project/.vscode/extensions.json +7 -0
- package/templates/project/README.md.hbs +8 -0
- package/templates/project/commitlint.config.js.hbs +1 -0
- package/templates/project/eslint.config.js.hbs +38 -0
- package/templates/project/package.json.hbs +61 -0
- package/templates/project/src/examples/README.md +1 -0
- package/templates/project/src/icons/README.md +1 -0
- package/templates/project/src/locales/README.md +1 -0
- package/templates/project/src/locales/docs/README.md +1 -0
- package/templates/project/src/locales/labels/README.md +1 -0
- package/templates/project/src/server/README.md +1 -0
- package/templates/project/src/server/nodes/README.md +1 -0
- package/templates/project/src/server/schemas/README.md +1 -0
- package/templates/project/src/server/tsconfig.json.hbs +7 -0
- package/templates/project/tsconfig.json.hbs +7 -0
- package/templates/project/vite.config.ts.hbs +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="nrg-icon" src="https://gist.githubusercontent.com/AllanOricil/84412df273de46b28c5d6945b391afd4/raw/0c9cdb994c40ab3d7b7ad06dcee162145d77d531/nrg-icon.svg" style="width: 200px"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@bonsae/create-nrg"><img src="https://img.shields.io/npm/v/@bonsae/create-nrg.svg" alt="npm package"></a>
|
|
7
|
+
<a href="https://github.com/bonsaedev/create-nrg/actions/workflows/ci.yaml"><img src="https://github.com/bonsaedev/create-nrg/actions/workflows/ci.yaml/badge.svg?branch=main" alt="build status"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
# create-nrg
|
|
11
|
+
|
|
12
|
+
Scaffold a new [NRG](https://github.com/bonsaedev/nrg) project for Node-RED.
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm create @bonsae/nrg my-project
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm create @bonsae/nrg my-project
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @bonsae/create-nrg my-project
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The CLI will prompt you for:
|
|
29
|
+
|
|
30
|
+
- **Project name**
|
|
31
|
+
- **First node name**
|
|
32
|
+
- **Node category**
|
|
33
|
+
- **Node color** (hex, default `#1A1A1A`)
|
|
34
|
+
- **Node inputs** (0 or 1)
|
|
35
|
+
- **Node outputs**
|
|
36
|
+
|
|
37
|
+
## Generated project structure
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
my-project/
|
|
41
|
+
├── .vscode/extensions.json
|
|
42
|
+
├── .husky/
|
|
43
|
+
├── .gitignore
|
|
44
|
+
├── .prettierrc.json
|
|
45
|
+
├── eslint.config.js
|
|
46
|
+
├── commitlint.config.js
|
|
47
|
+
├── package.json
|
|
48
|
+
├── tsconfig.json
|
|
49
|
+
├── vite.config.ts
|
|
50
|
+
└── src/
|
|
51
|
+
├── server/
|
|
52
|
+
│ ├── index.ts
|
|
53
|
+
│ ├── nodes/<node>.ts
|
|
54
|
+
│ ├── schemas/<node>.ts
|
|
55
|
+
│ └── tsconfig.json
|
|
56
|
+
├── locales/
|
|
57
|
+
│ ├── labels/<node>/en-US.json
|
|
58
|
+
│ └── docs/<node>/en-US.md
|
|
59
|
+
├── icons/
|
|
60
|
+
└── examples/
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { dashCase, scaffoldProject } from "./scaffold.js";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const TEMPLATES_DIR = path.resolve(__dirname, "../templates");
|
|
10
|
+
async function main() {
|
|
11
|
+
p.intro("Create a new NRG project");
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const positionalName = args.find((a) => !a.startsWith("-"));
|
|
14
|
+
const project = await p.group({
|
|
15
|
+
projectName: () => p.text({
|
|
16
|
+
message: "What would you like to name your project?",
|
|
17
|
+
placeholder: "nrg-project",
|
|
18
|
+
defaultValue: positionalName || "nrg-project",
|
|
19
|
+
initialValue: positionalName,
|
|
20
|
+
validate: (value) => {
|
|
21
|
+
if (!value?.trim())
|
|
22
|
+
return "Project name is required.";
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
nodeName: () => p.text({
|
|
26
|
+
message: "What would you like to name your first node?",
|
|
27
|
+
placeholder: "node-1",
|
|
28
|
+
defaultValue: "node-1",
|
|
29
|
+
validate: (value) => {
|
|
30
|
+
if (!value?.trim())
|
|
31
|
+
return "Node name is required.";
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
nodeCategory: () => p.text({
|
|
35
|
+
message: "Which category should your node belong to?",
|
|
36
|
+
placeholder: "new category",
|
|
37
|
+
defaultValue: "new category",
|
|
38
|
+
}),
|
|
39
|
+
nodeColor: () => p.text({
|
|
40
|
+
message: "What color should represent your node? (hex)",
|
|
41
|
+
placeholder: "#1A1A1A",
|
|
42
|
+
defaultValue: "#1A1A1A",
|
|
43
|
+
validate: (value) => {
|
|
44
|
+
if (!value || !/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(value)) {
|
|
45
|
+
return "Please enter a valid hex color code (e.g., #1A1A1A or #000)";
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
nodeInputs: () => p.text({
|
|
50
|
+
message: "How many inputs should your node have? (0 or 1)",
|
|
51
|
+
placeholder: "1",
|
|
52
|
+
defaultValue: "1",
|
|
53
|
+
validate: (value) => {
|
|
54
|
+
const n = parseInt(value || "", 10);
|
|
55
|
+
if (n !== 0 && n !== 1)
|
|
56
|
+
return "Inputs must be either 0 or 1.";
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
nodeOutputs: () => p.text({
|
|
60
|
+
message: "How many outputs should your node have?",
|
|
61
|
+
placeholder: "1",
|
|
62
|
+
defaultValue: "1",
|
|
63
|
+
validate: (value) => {
|
|
64
|
+
const n = parseInt(value || "", 10);
|
|
65
|
+
if (isNaN(n) || n < 0)
|
|
66
|
+
return "Outputs must be 0 or more.";
|
|
67
|
+
},
|
|
68
|
+
}),
|
|
69
|
+
}, {
|
|
70
|
+
onCancel: () => {
|
|
71
|
+
p.cancel("Operation cancelled.");
|
|
72
|
+
process.exit(0);
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
const projectName = project.projectName;
|
|
76
|
+
const nodeName = project.nodeName;
|
|
77
|
+
const nodeCategory = project.nodeCategory;
|
|
78
|
+
const nodeColor = project.nodeColor;
|
|
79
|
+
const nodeInputs = project.nodeInputs;
|
|
80
|
+
const nodeOutputs = project.nodeOutputs;
|
|
81
|
+
const projectDir = path.resolve(process.cwd(), dashCase(projectName));
|
|
82
|
+
if (fs.existsSync(projectDir)) {
|
|
83
|
+
p.cancel(`Directory "${dashCase(projectName)}" already exists.`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const s = p.spinner();
|
|
87
|
+
s.start("Scaffolding project...");
|
|
88
|
+
scaffoldProject(projectDir, TEMPLATES_DIR, {
|
|
89
|
+
projectName,
|
|
90
|
+
nodeName,
|
|
91
|
+
nodeCategory,
|
|
92
|
+
nodeColor,
|
|
93
|
+
nodeInputs,
|
|
94
|
+
nodeOutputs,
|
|
95
|
+
});
|
|
96
|
+
s.stop("Project scaffolded.");
|
|
97
|
+
p.note([`cd ${dashCase(projectName)}`, `pnpm install`, `pnpm run dev`].join("\n"), "Next steps");
|
|
98
|
+
p.outro("Happy coding!");
|
|
99
|
+
}
|
|
100
|
+
main().catch((err) => {
|
|
101
|
+
p.cancel("Something went wrong.");
|
|
102
|
+
console.error(err);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
export function dashCase(str) {
|
|
4
|
+
return str
|
|
5
|
+
.replace(/([a-z])([A-Z])/g, "$1-$2")
|
|
6
|
+
.replace(/[\s_]+/g, "-")
|
|
7
|
+
.toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
export function pascalCase(str) {
|
|
10
|
+
return dashCase(str)
|
|
11
|
+
.split("-")
|
|
12
|
+
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
13
|
+
.join("");
|
|
14
|
+
}
|
|
15
|
+
export function renderTemplate(content, vars) {
|
|
16
|
+
return content.replace(/\{\{(\w+)\}\}/g, (_, key) => vars[key] ?? _);
|
|
17
|
+
}
|
|
18
|
+
export function copyTemplateDir(srcDir, destDir, vars) {
|
|
19
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
22
|
+
const renderedName = renderTemplate(entry.name, vars);
|
|
23
|
+
const destPath = path.join(destDir, renderedName);
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
26
|
+
copyTemplateDir(srcPath, destPath, vars);
|
|
27
|
+
}
|
|
28
|
+
else if (entry.name.endsWith(".hbs")) {
|
|
29
|
+
const outPath = destPath.replace(/\.hbs$/, "");
|
|
30
|
+
const content = fs.readFileSync(srcPath, "utf-8");
|
|
31
|
+
fs.writeFileSync(outPath, renderTemplate(content, vars));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
fs.copyFileSync(srcPath, destPath);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function renderTemplateFile(templatePath, destPath, vars) {
|
|
39
|
+
const content = fs.readFileSync(templatePath, "utf-8");
|
|
40
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
41
|
+
fs.writeFileSync(destPath, renderTemplate(content, vars));
|
|
42
|
+
}
|
|
43
|
+
export function scaffoldProject(destDir, templatesDir, options) {
|
|
44
|
+
const vars = {
|
|
45
|
+
projectName: dashCase(options.projectName),
|
|
46
|
+
nodeName: options.nodeName,
|
|
47
|
+
dashCaseNodeName: dashCase(options.nodeName),
|
|
48
|
+
pascalCaseNodeName: pascalCase(options.nodeName),
|
|
49
|
+
nodeCategory: options.nodeCategory,
|
|
50
|
+
nodeColor: options.nodeColor,
|
|
51
|
+
nodeInputs: options.nodeInputs,
|
|
52
|
+
nodeOutputs: options.nodeOutputs,
|
|
53
|
+
};
|
|
54
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
55
|
+
// Copy project-level templates (includes directory structure with READMEs)
|
|
56
|
+
copyTemplateDir(path.join(templatesDir, "project"), destDir, vars);
|
|
57
|
+
// Place node-specific files into the correct locations
|
|
58
|
+
const nodeTemplatesDir = path.join(templatesDir, "node");
|
|
59
|
+
const srcDir = path.join(destDir, "src");
|
|
60
|
+
renderTemplateFile(path.join(nodeTemplatesDir, "server-node.ts.hbs"), path.join(srcDir, "server", "nodes", `${vars.dashCaseNodeName}.ts`), vars);
|
|
61
|
+
renderTemplateFile(path.join(nodeTemplatesDir, "schema.ts.hbs"), path.join(srcDir, "server", "schemas", `${vars.dashCaseNodeName}.ts`), vars);
|
|
62
|
+
renderTemplateFile(path.join(nodeTemplatesDir, "server-index.ts.hbs"), path.join(srcDir, "server", "index.ts"), vars);
|
|
63
|
+
renderTemplateFile(path.join(nodeTemplatesDir, "labels.json.hbs"), path.join(srcDir, "locales", "labels", vars.dashCaseNodeName, "en-US.json"), vars);
|
|
64
|
+
renderTemplateFile(path.join(nodeTemplatesDir, "docs.md.hbs"), path.join(srcDir, "locales", "docs", vars.dashCaseNodeName, "en-US.md"), vars);
|
|
65
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bonsae/create-nrg",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold a new NRG project for Node-RED",
|
|
5
|
+
"author": "Allan Oricil <allanoricil@duck.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"create-nrg": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"templates/"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/bonsaedev/create-nrg"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"node-red",
|
|
27
|
+
"nrg",
|
|
28
|
+
"scaffold",
|
|
29
|
+
"create",
|
|
30
|
+
"bonsae"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc",
|
|
34
|
+
"dev": "tsc --watch",
|
|
35
|
+
"lint": "eslint src/",
|
|
36
|
+
"lint:fix": "eslint src/ --fix",
|
|
37
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
38
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"test:watch": "vitest",
|
|
41
|
+
"prepare": "husky"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@clack/prompts": "^1.0.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@commitlint/cli": "^20.5.0",
|
|
48
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
49
|
+
"@eslint/js": "^9.27.0",
|
|
50
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
51
|
+
"@semantic-release/git": "^10.0.1",
|
|
52
|
+
"@semantic-release/github": "^11.0.0",
|
|
53
|
+
"@types/node": "^22.15.18",
|
|
54
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
55
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
56
|
+
"eslint": "^9.27.0",
|
|
57
|
+
"eslint-config-prettier": "^10.1.8",
|
|
58
|
+
"husky": "^9.1.7",
|
|
59
|
+
"lint-staged": "^16.4.0",
|
|
60
|
+
"prettier": "^3.5.3",
|
|
61
|
+
"semantic-release": "^24.2.4",
|
|
62
|
+
"typescript": "^5.8.3",
|
|
63
|
+
"typescript-eslint": "^8.32.1",
|
|
64
|
+
"vitest": "^4.1.5"
|
|
65
|
+
},
|
|
66
|
+
"lint-staged": {
|
|
67
|
+
"src/**/*.ts": [
|
|
68
|
+
"eslint --fix",
|
|
69
|
+
"prettier --write"
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SchemaType, defineSchema } from "@bonsae/nrg/server";
|
|
2
|
+
|
|
3
|
+
const ConfigsSchema = defineSchema(
|
|
4
|
+
{
|
|
5
|
+
name: SchemaType.String({ default: "{{dashCaseNodeName}}" }),
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
$id: "{{pascalCaseNodeName}}ConfigsSchema",
|
|
9
|
+
},
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const CredentialsSchema = defineSchema(
|
|
13
|
+
{},
|
|
14
|
+
{
|
|
15
|
+
$id: "{{pascalCaseNodeName}}CredentialsSchema",
|
|
16
|
+
},
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const InputSchema = defineSchema(
|
|
20
|
+
{},
|
|
21
|
+
{
|
|
22
|
+
$id: "{{pascalCaseNodeName}}InputSchema",
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const OutputSchema = defineSchema(
|
|
27
|
+
{},
|
|
28
|
+
{
|
|
29
|
+
$id: "{{pascalCaseNodeName}}OutputSchema",
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const SettingsSchema = defineSchema(
|
|
34
|
+
{},
|
|
35
|
+
{
|
|
36
|
+
$id: "{{pascalCaseNodeName}}SettingsSchema",
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export { ConfigsSchema, CredentialsSchema, InputSchema, OutputSchema, SettingsSchema };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Schema, Infer, RED } from "@bonsae/nrg/server";
|
|
2
|
+
import { IONode } from "@bonsae/nrg/server";
|
|
3
|
+
import {
|
|
4
|
+
ConfigsSchema,
|
|
5
|
+
CredentialsSchema,
|
|
6
|
+
InputSchema,
|
|
7
|
+
OutputSchema,
|
|
8
|
+
SettingsSchema,
|
|
9
|
+
} from "../schemas/{{dashCaseNodeName}}";
|
|
10
|
+
|
|
11
|
+
export type Config = Infer<typeof ConfigsSchema>;
|
|
12
|
+
export type Credentials = Infer<typeof CredentialsSchema>;
|
|
13
|
+
export type Input = Infer<typeof InputSchema>;
|
|
14
|
+
export type Output = Infer<typeof OutputSchema>;
|
|
15
|
+
export type Settings = Infer<typeof SettingsSchema>;
|
|
16
|
+
|
|
17
|
+
export default class {{pascalCaseNodeName}} extends IONode<
|
|
18
|
+
Config,
|
|
19
|
+
Credentials,
|
|
20
|
+
Input,
|
|
21
|
+
Output,
|
|
22
|
+
Settings
|
|
23
|
+
> {
|
|
24
|
+
public static override readonly type: string = "{{dashCaseNodeName}}";
|
|
25
|
+
public static override readonly category: string = "{{nodeCategory}}";
|
|
26
|
+
public static override readonly color: `#${string}` = "{{nodeColor}}";
|
|
27
|
+
public static override readonly inputs: number = {{nodeInputs}};
|
|
28
|
+
public static override readonly outputs: number = {{nodeOutputs}};
|
|
29
|
+
|
|
30
|
+
public static override readonly configSchema: Schema = ConfigsSchema;
|
|
31
|
+
public static override readonly credentialsSchema: Schema = CredentialsSchema;
|
|
32
|
+
public static override readonly inputSchema: Schema = InputSchema;
|
|
33
|
+
public static override readonly outputsSchema: Schema = OutputSchema;
|
|
34
|
+
public static override readonly settingsSchema: Schema = SettingsSchema;
|
|
35
|
+
|
|
36
|
+
public static override async registered(RED: RED): Promise<void> {
|
|
37
|
+
RED.log.info(`${this.type} registered`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public override created(): void {
|
|
41
|
+
this.log(`{{pascalCaseNodeName}} ${this.id} created`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public override async input(msg: Input): Promise<void> {
|
|
45
|
+
this.send(msg as unknown as Output);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public override async closed(): Promise<void> {
|
|
49
|
+
this.log(`{{pascalCaseNodeName}} ${this.id} closed`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx commitlint --edit $1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx lint-staged
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default { extends: ["@commitlint/config-conventional"] };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import eslint from "@eslint/js";
|
|
2
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
3
|
+
import eslintPluginVue from "eslint-plugin-vue";
|
|
4
|
+
import globals from "globals";
|
|
5
|
+
import typescriptEslint from "typescript-eslint";
|
|
6
|
+
|
|
7
|
+
export default typescriptEslint.config(
|
|
8
|
+
{
|
|
9
|
+
ignores: ["**/*.d.ts", "**/coverage", "**/dist", "**/build"],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
extends: [
|
|
13
|
+
eslint.configs.recommended,
|
|
14
|
+
...typescriptEslint.configs.recommended,
|
|
15
|
+
...eslintPluginVue.configs["flat/recommended"],
|
|
16
|
+
],
|
|
17
|
+
files: ["src/**/*.{ts,vue}"],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
ecmaVersion: "latest",
|
|
20
|
+
sourceType: "module",
|
|
21
|
+
globals: { ...globals["shared-node-browser"] },
|
|
22
|
+
parserOptions: {
|
|
23
|
+
parser: typescriptEslint.parser,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
rules: {
|
|
27
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
28
|
+
"vue/no-mutating-props": "off",
|
|
29
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
30
|
+
"error",
|
|
31
|
+
{
|
|
32
|
+
prefer: "type-imports",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
eslintConfigPrettier,
|
|
38
|
+
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"author": "",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=22",
|
|
10
|
+
"pnpm": ">=10.11.0"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"node-red",
|
|
14
|
+
"nrg"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"debug": "NODE_OPTIONS='--inspect-brk' NODE_ENV=development vite",
|
|
18
|
+
"dev": "NODE_ENV=development vite",
|
|
19
|
+
"build:dev": "NODE_ENV=development vite build",
|
|
20
|
+
"build": "NODE_ENV=production vite build",
|
|
21
|
+
"lint": "eslint src/",
|
|
22
|
+
"lint:fix": "eslint src/ --fix",
|
|
23
|
+
"format": "prettier --write \"src/**/*.{ts,vue,json}\"",
|
|
24
|
+
"format:check": "prettier --check \"src/**/*.{ts,vue,json}\"",
|
|
25
|
+
"tsc:client": "tsc -p src/client/tsconfig.json",
|
|
26
|
+
"tsc:server": "tsc -p src/server/tsconfig.json",
|
|
27
|
+
"prepare": "husky"
|
|
28
|
+
},
|
|
29
|
+
"lint-staged": {
|
|
30
|
+
"src/**/*.{ts,vue}": [
|
|
31
|
+
"eslint --fix",
|
|
32
|
+
"prettier --write"
|
|
33
|
+
],
|
|
34
|
+
"src/**/*.json": [
|
|
35
|
+
"prettier --write"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@bonsae/nrg": "latest",
|
|
40
|
+
"@sinclair/typebox": "^0.34.49"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@commitlint/cli": "^20.5.0",
|
|
44
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
45
|
+
"@eslint/js": "^9.27.0",
|
|
46
|
+
"@types/node": "^22.15.18",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
48
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
49
|
+
"eslint": "^9.27.0",
|
|
50
|
+
"eslint-config-prettier": "^10.1.8",
|
|
51
|
+
"eslint-plugin-vue": "^10.1.0",
|
|
52
|
+
"globals": "^16.1.0",
|
|
53
|
+
"husky": "^9.1.7",
|
|
54
|
+
"lint-staged": "^16.4.0",
|
|
55
|
+
"prettier": "^3.5.3",
|
|
56
|
+
"typescript": "^5.8.3",
|
|
57
|
+
"typescript-eslint": "^8.32.1",
|
|
58
|
+
"vite": "^6.3.4",
|
|
59
|
+
"vue": "^3.5.14"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to provide flow examples using your nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to provide custom icons for your nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use locales and docs directories to offer internationalization for your nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to add documentation for your nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to add label translations for your nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to write the server-side definition of your node.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to define your server-side Node-RED nodes.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Use this directory to write JSON Schemas using [Typebox](https://github.com/sinclairzx81/typebox).
|