fbp-language 0.0.0-stage → 1.0.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 +103 -2
- package/dist/cli.js +100 -0
- package/dist/compiler.js +186 -0
- package/dist/errors.js +24 -0
- package/package.json +44 -4
package/README.md
CHANGED
|
@@ -1,3 +1,104 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FBP — French Bot Programming
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
FBP est un langage interprété par Node.js. Les fichiers source utilisent l'extension `.fbp`. Le paquet fournit le moteur et la commande `fbp`.
|
|
4
|
+
|
|
5
|
+
## Prérequis
|
|
6
|
+
|
|
7
|
+
- Node.js 20 ou plus récent
|
|
8
|
+
- npm
|
|
9
|
+
|
|
10
|
+
## Installation depuis npm
|
|
11
|
+
|
|
12
|
+
Quand le paquet sera publié sur npm :
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install fbp-language
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Puis, dans le `package.json` de ton projet :
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"scripts": {
|
|
23
|
+
"start": "fbp run lancer"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"fbp-language": "^1.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Lance le script avec `npm start`. npm rend la commande `fbp` disponible dans les scripts du projet.
|
|
32
|
+
|
|
33
|
+
## Créer un projet FBP
|
|
34
|
+
|
|
35
|
+
Crée un fichier `commandes.fbp` à la racine de ton projet. Malgré son extension, ce fichier est actuellement du JSON :
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"lancer": "scripts/main.fbp"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Crée ensuite le fichier `scripts/main.fbp` :
|
|
44
|
+
|
|
45
|
+
```fbp
|
|
46
|
+
nom = "Mon projet"
|
|
47
|
+
|
|
48
|
+
lance() {
|
|
49
|
+
affiche("FBP fonctionne !")
|
|
50
|
+
affiche("Projet :", nom)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
lance()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Les chemins déclarés dans `commandes.fbp` sont relatifs à la racine du projet.
|
|
57
|
+
|
|
58
|
+
## Commandes CLI
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
fbp help
|
|
62
|
+
fbp version
|
|
63
|
+
fbp info
|
|
64
|
+
fbp ping
|
|
65
|
+
fbp run lancer
|
|
66
|
+
fbp run-file scripts/main.fbp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `fbp run <nom>` exécute la commande correspondante dans le fichier `commandes.fbp` du dossier courant.
|
|
70
|
+
- `fbp run-file <fichier>` exécute directement un fichier FBP.
|
|
71
|
+
- `fbp ping` vérifie que le CLI répond ; il ne se connecte pas à Discord.
|
|
72
|
+
|
|
73
|
+
## Syntaxe actuelle
|
|
74
|
+
|
|
75
|
+
```fbp
|
|
76
|
+
nom = "Gab"
|
|
77
|
+
niveau = 15
|
|
78
|
+
actif = true
|
|
79
|
+
|
|
80
|
+
lance() {
|
|
81
|
+
affiche("Bonjour", nom)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
lance()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- Types reconnus : texte, nombre et booléen.
|
|
88
|
+
- Les fonctions ne prennent pas encore de paramètres.
|
|
89
|
+
- `affiche(...)` écrit dans le terminal.
|
|
90
|
+
- `import { fonction } de "./fichier.fbp"` importe des fonctions.
|
|
91
|
+
- Les commentaires commencent par `//` ou `#`.
|
|
92
|
+
|
|
93
|
+
## Limites actuelles
|
|
94
|
+
|
|
95
|
+
FBP est encore un interpréteur de base. Les paramètres de fonction, les conditions, les boucles, les valeurs de retour et les expressions arithmétiques ne sont pas encore implémentés. La connexion à Discord n'est pas incluse dans le moteur.
|
|
96
|
+
|
|
97
|
+
## Développement du dépôt
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install
|
|
101
|
+
npm test
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Les fichiers d'essai internes se trouvent dans `tests/fixtures`. Ils ne font pas partie du paquet publié.
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const compiler_1 = require("./compiler");
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
const VERSION = "1.0.0";
|
|
12
|
+
function help() {
|
|
13
|
+
console.log(`FBP — French Bot Programming
|
|
14
|
+
|
|
15
|
+
Utilisation :
|
|
16
|
+
fbp help Affiche cette aide
|
|
17
|
+
fbp version Affiche la version de FBP
|
|
18
|
+
fbp info Affiche les informations du moteur
|
|
19
|
+
fbp ping Vérifie que le CLI répond
|
|
20
|
+
fbp run <commande> Exécute une commande de commandes.fbp
|
|
21
|
+
fbp run-file <fichier> Exécute directement un fichier .fbp`);
|
|
22
|
+
}
|
|
23
|
+
function ping() {
|
|
24
|
+
console.log("FBP : opérationnel");
|
|
25
|
+
console.log(`Version : ${VERSION}`);
|
|
26
|
+
console.log(`Node.js : ${process.version}`);
|
|
27
|
+
console.log("Bot : aucune connexion externe n'est configurée par le CLI seul.");
|
|
28
|
+
}
|
|
29
|
+
function runCommand(name) {
|
|
30
|
+
const configPath = node_path_1.default.resolve("commandes.fbp");
|
|
31
|
+
if (!node_fs_1.default.existsSync(configPath)) {
|
|
32
|
+
throw new errors_1.FbpError("Fichier commandes.fbp introuvable à la racine du projet. Crée ce fichier pour définir tes commandes.");
|
|
33
|
+
}
|
|
34
|
+
let commands;
|
|
35
|
+
try {
|
|
36
|
+
commands = JSON.parse(node_fs_1.default.readFileSync(configPath, "utf8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new errors_1.FbpError("commandes.fbp doit contenir un objet JSON valide associant chaque commande à un fichier .fbp.");
|
|
40
|
+
}
|
|
41
|
+
if (!commands || typeof commands !== "object" || Array.isArray(commands)) {
|
|
42
|
+
throw new errors_1.FbpError("commandes.fbp doit être un objet de commandes.");
|
|
43
|
+
}
|
|
44
|
+
const target = commands[name];
|
|
45
|
+
if (typeof target !== "string" || !target.trim()) {
|
|
46
|
+
const available = Object.keys(commands);
|
|
47
|
+
throw new errors_1.FbpError(`Commande « ${name} » inconnue.${available.length ? ` Commandes disponibles : ${available.join(", ")}.` : " Aucune commande n'est définie."}`);
|
|
48
|
+
}
|
|
49
|
+
new compiler_1.FbpCompiler().runFile(node_path_1.default.resolve(node_path_1.default.dirname(configPath), target));
|
|
50
|
+
}
|
|
51
|
+
function main() {
|
|
52
|
+
const [command, ...args] = process.argv.slice(2);
|
|
53
|
+
try {
|
|
54
|
+
switch (command) {
|
|
55
|
+
case "help":
|
|
56
|
+
case "--help":
|
|
57
|
+
case "-h":
|
|
58
|
+
case undefined:
|
|
59
|
+
help();
|
|
60
|
+
break;
|
|
61
|
+
case "version":
|
|
62
|
+
case "--version":
|
|
63
|
+
case "-v":
|
|
64
|
+
console.log(`FBP ${VERSION}`);
|
|
65
|
+
break;
|
|
66
|
+
case "info":
|
|
67
|
+
console.log("FBP — French Bot Programming");
|
|
68
|
+
console.log("Moteur : TypeScript / Node.js");
|
|
69
|
+
console.log("Fichiers source : .fbp");
|
|
70
|
+
break;
|
|
71
|
+
case "ping":
|
|
72
|
+
ping();
|
|
73
|
+
break;
|
|
74
|
+
case "run":
|
|
75
|
+
if (!args[0])
|
|
76
|
+
throw new errors_1.FbpError("Indique le nom de la commande. Exemple : fbp run lancer");
|
|
77
|
+
runCommand(args[0]);
|
|
78
|
+
break;
|
|
79
|
+
case "run-file":
|
|
80
|
+
if (!args[0])
|
|
81
|
+
throw new errors_1.FbpError("Indique un fichier. Exemple : fbp run-file bot/main.fbp");
|
|
82
|
+
new compiler_1.FbpCompiler().runFile(args[0]);
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
throw new errors_1.FbpError(`Commande CLI inconnue : « ${command} ». Utilise « fbp help » pour afficher l'aide.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof errors_1.FbpError) {
|
|
90
|
+
console.error(error.format());
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.error("Erreur FBP : une erreur inattendue est survenue.");
|
|
95
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
main();
|
package/dist/compiler.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FbpCompiler = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const errors_1 = require("./errors");
|
|
10
|
+
function valueType(value) {
|
|
11
|
+
const v = value.trim();
|
|
12
|
+
if (/^"(?:[^"\\]|\\.)*"$/.test(v) || /^'(?:[^'\\]|\\.)*'$/.test(v))
|
|
13
|
+
return "texte";
|
|
14
|
+
if (/^-?\d+(?:\.\d+)?$/.test(v))
|
|
15
|
+
return "nombre";
|
|
16
|
+
if (v === "true" || v === "false")
|
|
17
|
+
return "booleen";
|
|
18
|
+
return "inconnu";
|
|
19
|
+
}
|
|
20
|
+
function splitArguments(raw) {
|
|
21
|
+
const result = [];
|
|
22
|
+
let current = "";
|
|
23
|
+
let quote = "";
|
|
24
|
+
let depth = 0;
|
|
25
|
+
for (const char of raw) {
|
|
26
|
+
if (quote) {
|
|
27
|
+
current += char;
|
|
28
|
+
if (char === quote)
|
|
29
|
+
quote = "";
|
|
30
|
+
}
|
|
31
|
+
else if (char === '"' || char === "'") {
|
|
32
|
+
quote = char;
|
|
33
|
+
current += char;
|
|
34
|
+
}
|
|
35
|
+
else if (char === "(") {
|
|
36
|
+
depth++;
|
|
37
|
+
current += char;
|
|
38
|
+
}
|
|
39
|
+
else if (char === ")") {
|
|
40
|
+
depth--;
|
|
41
|
+
current += char;
|
|
42
|
+
}
|
|
43
|
+
else if (char === "," && depth === 0) {
|
|
44
|
+
if (current.trim())
|
|
45
|
+
result.push(current.trim());
|
|
46
|
+
current = "";
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
current += char;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (current.trim())
|
|
53
|
+
result.push(current.trim());
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
function parseFile(file, source) {
|
|
57
|
+
const lines = source.split(/\r?\n/);
|
|
58
|
+
const root = [];
|
|
59
|
+
const stack = [];
|
|
60
|
+
const target = () => stack.length ? stack[stack.length - 1].body : root;
|
|
61
|
+
for (let index = 0; index < lines.length; index++) {
|
|
62
|
+
const raw = lines[index];
|
|
63
|
+
const line = raw.trim();
|
|
64
|
+
const lineNo = index + 1;
|
|
65
|
+
if (!line || line.startsWith("//") || line.startsWith("#"))
|
|
66
|
+
continue;
|
|
67
|
+
const importMatch = line.match(/^import\s*\{\s*([^}]+)\s*\}\s*de\s*(["'])(.+?)\2\s*$/);
|
|
68
|
+
if (importMatch) {
|
|
69
|
+
target().push({ kind: "import", names: importMatch[1].split(",").map(x => x.trim()), source: importMatch[3], line: lineNo });
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const functionMatch = line.match(/^([\p{L}_][\p{L}\p{N}_]*)\s*\(\s*\)\s*\{$/u);
|
|
73
|
+
if (functionMatch) {
|
|
74
|
+
const entry = { name: functionMatch[1], line: lineNo, body: [] };
|
|
75
|
+
target().push({ kind: "function", ...entry });
|
|
76
|
+
stack.push(entry);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (line === "}") {
|
|
80
|
+
if (!stack.length)
|
|
81
|
+
throw new errors_1.FbpError("Accolade fermante sans fonction correspondante.", file, lineNo);
|
|
82
|
+
stack.pop();
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const assignment = line.match(/^([\p{L}_][\p{L}\p{N}_]*)\s*=\s*(.+)$/u);
|
|
86
|
+
if (assignment) {
|
|
87
|
+
target().push({ kind: "assign", name: assignment[1], value: assignment[2].trim(), line: lineNo });
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const call = line.match(/^([\p{L}_][\p{L}\p{N}_]*)\s*\((.*)\)\s*;?$/u);
|
|
91
|
+
if (call) {
|
|
92
|
+
target().push({ kind: "call", name: call[1], args: splitArguments(call[2]), line: lineNo });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
throw new errors_1.FbpError(`Syntaxe non reconnue : « ${line} ». Vérifie les parenthèses, les accolades et le signe =.`, file, lineNo);
|
|
96
|
+
}
|
|
97
|
+
if (stack.length) {
|
|
98
|
+
const open = stack[stack.length - 1];
|
|
99
|
+
throw new errors_1.FbpError(`La fonction « ${open.name} » n'est pas fermée par }.`, file, open.line);
|
|
100
|
+
}
|
|
101
|
+
return root;
|
|
102
|
+
}
|
|
103
|
+
class FbpCompiler {
|
|
104
|
+
variables = new Map();
|
|
105
|
+
functions = new Map();
|
|
106
|
+
imports = new Map();
|
|
107
|
+
output;
|
|
108
|
+
constructor(options = {}) {
|
|
109
|
+
this.output = options.onOutput ?? (value => console.log(value));
|
|
110
|
+
}
|
|
111
|
+
runFile(filePath) {
|
|
112
|
+
const absolute = node_path_1.default.resolve(filePath);
|
|
113
|
+
if (!node_fs_1.default.existsSync(absolute))
|
|
114
|
+
throw new errors_1.FbpError(`Fichier introuvable : ${absolute}`);
|
|
115
|
+
if (!node_fs_1.default.statSync(absolute).isFile())
|
|
116
|
+
throw new errors_1.FbpError(`Le chemin indiqué n'est pas un fichier : ${absolute}`);
|
|
117
|
+
this.execute(parseFile(absolute, node_fs_1.default.readFileSync(absolute, "utf8")), node_path_1.default.dirname(absolute));
|
|
118
|
+
}
|
|
119
|
+
execute(statements, baseDir) {
|
|
120
|
+
for (const statement of statements) {
|
|
121
|
+
if (statement.kind === "import") {
|
|
122
|
+
const targetFile = node_path_1.default.resolve(baseDir, statement.source);
|
|
123
|
+
if (!node_fs_1.default.existsSync(targetFile))
|
|
124
|
+
throw new errors_1.FbpError(`Fichier importé introuvable : ${statement.source}`);
|
|
125
|
+
const nested = parseFile(targetFile, node_fs_1.default.readFileSync(targetFile, "utf8"));
|
|
126
|
+
for (const item of nested) {
|
|
127
|
+
if (item.kind === "function")
|
|
128
|
+
this.functions.set(item.name, item);
|
|
129
|
+
}
|
|
130
|
+
for (const name of statement.names) {
|
|
131
|
+
if (!this.functions.has(name))
|
|
132
|
+
throw new errors_1.FbpError(`La fonction « ${name} » n'existe pas dans ${statement.source}.`);
|
|
133
|
+
this.imports.set(name, targetFile);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (statement.kind === "function") {
|
|
137
|
+
if (this.functions.has(statement.name))
|
|
138
|
+
throw new errors_1.FbpError(`La fonction « ${statement.name} » est définie plusieurs fois.`, undefined, statement.line);
|
|
139
|
+
this.functions.set(statement.name, statement);
|
|
140
|
+
}
|
|
141
|
+
else if (statement.kind === "assign") {
|
|
142
|
+
const type = valueType(statement.value);
|
|
143
|
+
const previous = this.variables.get(statement.name);
|
|
144
|
+
if (previous && type !== "inconnu" && previous.type !== "inconnu" && previous.type !== type) {
|
|
145
|
+
throw new errors_1.FbpError(`Type incompatible pour « ${statement.name} » : attendu ${previous.type}, reçu ${type}.`, undefined, statement.line);
|
|
146
|
+
}
|
|
147
|
+
const value = this.evaluate(statement.value, statement.line);
|
|
148
|
+
this.variables.set(statement.name, { type: previous?.type ?? type, value });
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this.call(statement.name, statement.args, statement.line, baseDir);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
evaluate(expression, line) {
|
|
156
|
+
const value = expression.trim();
|
|
157
|
+
if (value === "true")
|
|
158
|
+
return true;
|
|
159
|
+
if (value === "false")
|
|
160
|
+
return false;
|
|
161
|
+
if (/^-?\d+(?:\.\d+)?$/.test(value))
|
|
162
|
+
return Number(value);
|
|
163
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
164
|
+
return value.slice(1, -1).replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\(["'\\])/g, "$1");
|
|
165
|
+
}
|
|
166
|
+
if (this.variables.has(value))
|
|
167
|
+
return this.variables.get(value).value;
|
|
168
|
+
throw new errors_1.FbpError(`Valeur inconnue « ${value} ». Utilise un texte, un nombre, true, false ou une variable déclarée.`, undefined, line);
|
|
169
|
+
}
|
|
170
|
+
call(name, args, line, baseDir) {
|
|
171
|
+
const values = args.map(arg => this.evaluate(arg, line));
|
|
172
|
+
if (name === "affiche") {
|
|
173
|
+
this.output(values.map(value => value === undefined ? "" : String(value)).join(" "));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (name === "ping") {
|
|
177
|
+
this.output("FBP fonctionne. Cette commande ne vérifie pas à elle seule une connexion Discord.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const fn = this.functions.get(name);
|
|
181
|
+
if (!fn)
|
|
182
|
+
throw new errors_1.FbpError(`Fonction « ${name} » inconnue. Vérifie son nom ou son import.`, undefined, line);
|
|
183
|
+
this.execute(fn.body, this.imports.has(name) ? node_path_1.default.dirname(this.imports.get(name)) : baseDir);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.FbpCompiler = FbpCompiler;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FbpError = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
class FbpError extends Error {
|
|
9
|
+
file;
|
|
10
|
+
line;
|
|
11
|
+
constructor(message, file, line) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.file = file;
|
|
14
|
+
this.line = line;
|
|
15
|
+
this.name = "FbpError";
|
|
16
|
+
}
|
|
17
|
+
format() {
|
|
18
|
+
const location = this.file
|
|
19
|
+
? `${node_path_1.default.relative(process.cwd(), this.file)}${this.line ? `:${this.line}` : ""}: `
|
|
20
|
+
: "";
|
|
21
|
+
return `Erreur FBP : ${location}${this.message}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.FbpError = FbpError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fbp-language",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"displayName": "FBP - French Bot Programming",
|
|
4
|
+
"description": "Interpréteur et CLI du langage FBP.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"main": "dist/compiler.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"fbp": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/GabyY-1/French-Bot-Programming.git"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/GabyY-1/French-Bot-Programming#readme",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/GabyY-1/French-Bot-Programming/issues"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"fbp",
|
|
25
|
+
"language",
|
|
26
|
+
"interpreter",
|
|
27
|
+
"french",
|
|
28
|
+
"cli"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.json",
|
|
32
|
+
"prepare": "npm run build",
|
|
33
|
+
"prepublishOnly": "npm test",
|
|
34
|
+
"start": "node dist/cli.js",
|
|
35
|
+
"dev": "ts-node src/cli.ts",
|
|
36
|
+
"test": "npm run build && node --test tests/*.test.cjs"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.10.0",
|
|
43
|
+
"ts-node": "^10.9.2",
|
|
44
|
+
"typescript": "^5.7.2"
|
|
45
|
+
}
|
|
46
|
+
}
|