create-yukigo-parser 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.
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ #! /usr/bin/env node
2
+ import { program } from "commander";
3
+ import { input } from "@inquirer/prompts";
4
+ import { createProject } from "./utils.js";
5
+ program
6
+ .version("1.0.0")
7
+ .description("An initializer for new yukigo parser projects.");
8
+ const name = await input({ message: `Project Name:` });
9
+ const projectName = `yukigo-${name}-parser`;
10
+ createProject(projectName);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,gDAAgD,CAAC,CAAC;AAEjE,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,UAAU,IAAI,SAAS,CAAC;AAE5C,aAAa,CAAC,WAAW,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ export declare const runCommand: (command: string, cwd: string, loadingMessage: string) => void;
2
+ export declare function isEmpty(path: string): boolean;
3
+ export declare const createProject: (projectName: string) => Promise<void>;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,UAAU,GACrB,SAAS,MAAM,EACf,KAAK,MAAM,EACX,gBAAgB,MAAM,SAUvB,CAAC;AAEF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,WAEnC;AAED,eAAO,MAAM,aAAa,GAAU,aAAa,MAAM,kBAmEtD,CAAC"}
package/dist/utils.js ADDED
@@ -0,0 +1,105 @@
1
+ import { confirm } from "@inquirer/prompts";
2
+ import chalk from "chalk";
3
+ import { execSync } from "child_process";
4
+ import { readdirSync } from "fs";
5
+ import fse from "fs-extra";
6
+ import path from "path";
7
+ const __dirname = import.meta.dirname;
8
+ const TEMPLATE_DIR = path.join(__dirname, "..", "template");
9
+ const INDEX_TEMPLATE_PATH = path.join("src", "index.ts");
10
+ const TEST_TEMPLATE_PATH = path.join("tests", "parser.spec.ts");
11
+ const CLASS_PLACEHOLDER = "YukigoParserPlaceholder";
12
+ export const runCommand = (command, cwd, loadingMessage) => {
13
+ console.log(loadingMessage);
14
+ try {
15
+ execSync(command, { stdio: "inherit", cwd });
16
+ }
17
+ catch (error) {
18
+ console.error(`\nFailed to execute command: ${command}`);
19
+ // Exit process immediately on critical failure
20
+ process.exit(1);
21
+ }
22
+ };
23
+ export function isEmpty(path) {
24
+ return readdirSync(path).length === 0;
25
+ }
26
+ const toPascalCase = (str) => {
27
+ // First, replace non-alphanumeric separators (like hyphens, underscores) with a capitalized letter.
28
+ let pascal = str
29
+ .toLowerCase()
30
+ .replace(/[^a-zA-Z0-9]+(.)/g, (match, chr) => chr.toUpperCase());
31
+ // Then, ensure the very first letter is also capitalized.
32
+ return pascal.charAt(0).toUpperCase() + pascal.slice(1);
33
+ };
34
+ export async function replaceInFile(path, search, replace) {
35
+ let content = await fse.readFile(path, "utf-8");
36
+ const regex = new RegExp(`${search}`, "g");
37
+ content = content.replace(regex, replace);
38
+ await fse.writeFile(path, content);
39
+ }
40
+ export const createProject = async (projectName) => {
41
+ const targetDir = path.resolve(projectName);
42
+ console.log(`\n✨ Starting project setup for: ${chalk.bold.blue(projectName)}`);
43
+ // Directory Validation
44
+ if (fse.existsSync(targetDir)) {
45
+ console.error(`\n❌ Error: Directory '${projectName}' already exists.`);
46
+ process.exit(1);
47
+ }
48
+ // Copy Template Files
49
+ console.log(`\n📁 Setting up project in ${targetDir}...`);
50
+ try {
51
+ await fse.copy(TEMPLATE_DIR, targetDir);
52
+ }
53
+ catch (error) {
54
+ console.error("\n❌ Failed to copy template files:", error);
55
+ process.exit(1);
56
+ }
57
+ // Update package.json
58
+ const packageJsonPath = path.join(targetDir, "package.json");
59
+ try {
60
+ const packageJson = await fse.readJson(packageJsonPath);
61
+ packageJson.name = projectName;
62
+ await fse.writeJson(packageJsonPath, packageJson, { spaces: 2 });
63
+ }
64
+ catch (error) {
65
+ console.error("\n❌ Failed to update package.json:", error);
66
+ process.exit(1);
67
+ }
68
+ const projectNamePascal = toPascalCase(projectName);
69
+ const templateIndexPath = path.join(targetDir, INDEX_TEMPLATE_PATH);
70
+ const templateTestPath = path.join(targetDir, TEST_TEMPLATE_PATH);
71
+ try {
72
+ await replaceInFile(templateIndexPath, CLASS_PLACEHOLDER, projectNamePascal);
73
+ await replaceInFile(templateTestPath, CLASS_PLACEHOLDER, projectNamePascal);
74
+ }
75
+ catch (error) {
76
+ console.error("\n❌ Failed to update class name:", error);
77
+ process.exit(1);
78
+ }
79
+ console.log("✅ Initial project setted up correctly.");
80
+ // Initialize git if confirmed
81
+ const initGitRepo = await confirm({
82
+ message: `Do you want to initialize a git repository with the name '${projectName}'?`,
83
+ });
84
+ if (initGitRepo) {
85
+ runCommand("git init", targetDir, "\n🌱 Initializing Git repository...");
86
+ console.log("✅ Git repository initialized.");
87
+ }
88
+ const runInstall = await confirm({
89
+ message: `Do you want to install dependencies automatically?`,
90
+ });
91
+ // install deps if confirmed
92
+ if (runInstall) {
93
+ runCommand("npm install", targetDir, "\n📦 Installing dependencies (this may take a minute)...");
94
+ console.log("✅ Dependencies installed.");
95
+ }
96
+ // 6. Success Message
97
+ const successMsg = `${chalk.bold.green("Success!")} Project ${chalk.bold.blue(projectName)} is ready.`;
98
+ console.log("\n" + "-".repeat(successMsg.length));
99
+ console.log(successMsg);
100
+ console.log("-".repeat(successMsg.length));
101
+ console.log("\nNext steps:");
102
+ console.log(`1. ${chalk.bold(`cd ${projectName}`)}`);
103
+ console.log(`2. Start coding: ${chalk.bold("npm start")} (or ${chalk.bold("npm run build")})`);
104
+ console.log("\nHappy parsing! :)");
105
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "create-yukigo-parser",
3
+ "description": "A CLI to quickly set up a new Yukigo parser project.",
4
+ "version": "0.1.0",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-yukigo-parser": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
13
+ "keywords": [
14
+ "cli",
15
+ "typescript",
16
+ "parser"
17
+ ],
18
+ "author": "noiseArch",
19
+ "license": "ISC",
20
+ "devDependencies": {
21
+ "@types/node": "^24.10.0",
22
+ "ts-node": "^10.9.2",
23
+ "typescript": "^5.9.3"
24
+ },
25
+ "dependencies": {
26
+ "@inquirer/prompts": "^7.9.0",
27
+ "@types/fs-extra": "^11.0.4",
28
+ "chalk": "^5.6.2",
29
+ "commander": "^14.0.2",
30
+ "fs-extra": "^11.3.2"
31
+ }
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env node
2
+ import { program } from "commander";
3
+ import { input } from "@inquirer/prompts";
4
+ import { createProject } from "./utils.js";
5
+
6
+ program
7
+ .version("1.0.0")
8
+ .description("An initializer for new yukigo parser projects.");
9
+
10
+ const name = await input({ message: `Project Name:` });
11
+ const projectName = `yukigo-${name}-parser`;
12
+
13
+ createProject(projectName);
package/src/utils.ts ADDED
@@ -0,0 +1,143 @@
1
+ import { confirm } from "@inquirer/prompts";
2
+ import chalk from "chalk";
3
+ import { execSync } from "child_process";
4
+ import { readdirSync } from "fs";
5
+ import fse from "fs-extra";
6
+ import path from "path";
7
+
8
+ const __dirname = import.meta.dirname;
9
+ const TEMPLATE_DIR = path.join(__dirname, "..", "template");
10
+ const INDEX_TEMPLATE_PATH = path.join("src", "index.ts");
11
+ const TEST_TEMPLATE_PATH = path.join("tests", "parser.spec.ts");
12
+ const CLASS_PLACEHOLDER = "YukigoParserPlaceholder";
13
+
14
+ export const runCommand = (
15
+ command: string,
16
+ cwd: string,
17
+ loadingMessage: string
18
+ ) => {
19
+ console.log(loadingMessage);
20
+ try {
21
+ execSync(command, { stdio: "inherit", cwd });
22
+ } catch (error) {
23
+ console.error(`\nFailed to execute command: ${command}`);
24
+ // Exit process immediately on critical failure
25
+ process.exit(1);
26
+ }
27
+ };
28
+
29
+ export function isEmpty(path: string) {
30
+ return readdirSync(path).length === 0;
31
+ }
32
+
33
+ const toPascalCase = (str: string): string => {
34
+ // First, replace non-alphanumeric separators (like hyphens, underscores) with a capitalized letter.
35
+ let pascal = str
36
+ .toLowerCase()
37
+ .replace(/[^a-zA-Z0-9]+(.)/g, (match, chr) => chr.toUpperCase());
38
+
39
+ // Then, ensure the very first letter is also capitalized.
40
+ return pascal.charAt(0).toUpperCase() + pascal.slice(1);
41
+ };
42
+
43
+ export async function replaceInFile(
44
+ path: string,
45
+ search: string,
46
+ replace: string
47
+ ) {
48
+ let content = await fse.readFile(path, "utf-8");
49
+ const regex = new RegExp(`${search}`, "g");
50
+ content = content.replace(regex, replace);
51
+ await fse.writeFile(path, content);
52
+ }
53
+
54
+ export const createProject = async (projectName: string) => {
55
+ const targetDir = path.resolve(projectName);
56
+
57
+ console.log(
58
+ `\n✨ Starting project setup for: ${chalk.bold.blue(projectName)}`
59
+ );
60
+
61
+ // Directory Validation
62
+ if (fse.existsSync(targetDir)) {
63
+ console.error(`\n❌ Error: Directory '${projectName}' already exists.`);
64
+ process.exit(1);
65
+ }
66
+
67
+ // Copy Template Files
68
+ console.log(`\n📁 Setting up project in ${targetDir}...`);
69
+ try {
70
+ await fse.copy(TEMPLATE_DIR, targetDir);
71
+ } catch (error) {
72
+ console.error("\n❌ Failed to copy template files:", error);
73
+ process.exit(1);
74
+ }
75
+
76
+ // Update package.json
77
+ const packageJsonPath = path.join(targetDir, "package.json");
78
+ try {
79
+ const packageJson = await fse.readJson(packageJsonPath);
80
+ packageJson.name = projectName;
81
+ await fse.writeJson(packageJsonPath, packageJson, { spaces: 2 });
82
+ } catch (error) {
83
+ console.error("\n❌ Failed to update package.json:", error);
84
+ process.exit(1);
85
+ }
86
+
87
+ const projectNamePascal = toPascalCase(projectName);
88
+ const templateIndexPath = path.join(targetDir, INDEX_TEMPLATE_PATH);
89
+ const templateTestPath = path.join(targetDir, TEST_TEMPLATE_PATH);
90
+
91
+ try {
92
+ await replaceInFile(
93
+ templateIndexPath,
94
+ CLASS_PLACEHOLDER,
95
+ projectNamePascal
96
+ );
97
+ await replaceInFile(templateTestPath, CLASS_PLACEHOLDER, projectNamePascal);
98
+ } catch (error) {
99
+ console.error("\n❌ Failed to update class name:", error);
100
+ process.exit(1);
101
+ }
102
+
103
+ console.log("✅ Initial project setted up correctly.");
104
+
105
+ // Initialize git if confirmed
106
+ const initGitRepo = await confirm({
107
+ message: `Do you want to initialize a git repository with the name '${projectName}'?`,
108
+ });
109
+ if (initGitRepo) {
110
+ runCommand("git init", targetDir, "\n🌱 Initializing Git repository...");
111
+ console.log("✅ Git repository initialized.");
112
+ }
113
+
114
+ const runInstall = await confirm({
115
+ message: `Do you want to install dependencies automatically?`,
116
+ });
117
+ // install deps if confirmed
118
+ if (runInstall) {
119
+ runCommand(
120
+ "npm install",
121
+ targetDir,
122
+ "\n📦 Installing dependencies (this may take a minute)..."
123
+ );
124
+ console.log("✅ Dependencies installed.");
125
+ }
126
+
127
+ // 6. Success Message
128
+ const successMsg = `${chalk.bold.green("Success!")} Project ${chalk.bold.blue(
129
+ projectName
130
+ )} is ready.`;
131
+
132
+ console.log("\n" + "-".repeat(successMsg.length));
133
+ console.log(successMsg);
134
+ console.log("-".repeat(successMsg.length));
135
+ console.log("\nNext steps:");
136
+ console.log(`1. ${chalk.bold(`cd ${projectName}`)}`);
137
+ console.log(
138
+ `2. Start coding: ${chalk.bold("npm start")} (or ${chalk.bold(
139
+ "npm run build"
140
+ )})`
141
+ );
142
+ console.log("\nHappy parsing! :)");
143
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "extension": ["ts"],
3
+ "spec": "tests/**/*.spec.ts"
4
+ }
File without changes
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "yukigo-parser",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "scripts": {
13
+ "grammar": "nearleyc ./src/grammar.ne -o ./src/grammar.ts",
14
+ "build": "npm run grammar && tsc",
15
+ "test": "npm run build && mocha --import=tsx"
16
+ },
17
+ "keywords": [],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "devDependencies": {
21
+ "@types/chai": "^5.2.2",
22
+ "@types/mocha": "^10.0.10",
23
+ "@types/moo": "^0.5.10",
24
+ "@types/node": "^24.2.0",
25
+ "chai": "^5.2.1",
26
+ "mocha": "^11.7.1",
27
+ "tsx": "^4.20.6",
28
+ "typescript": "^5.9.2"
29
+ },
30
+ "dependencies": {
31
+ "moo": "^0.5.2",
32
+ "nearley": "^2.20.1",
33
+ "yukigo-core": "latest"
34
+ }
35
+ }
@@ -0,0 +1,43 @@
1
+ @{%
2
+ import { Lexer } from "./lexer.js"
3
+ import {
4
+ SourceLocation,
5
+ ArithmeticBinaryOperation,
6
+ Return,
7
+ NumberPrimitive,
8
+ StringPrimitive,
9
+ SymbolPrimitive,
10
+ CharPrimitive,
11
+ BooleanPrimitive
12
+ } from "yukigo-core"
13
+
14
+ const loc = (token) => new SourceLocation(token.line, token.col);
15
+
16
+ %}
17
+ @preprocessor typescript
18
+ @lexer Lexer
19
+
20
+ program -> addition {% (d) => [new Return(d[0])] %}
21
+
22
+ addition ->
23
+ addition _ "+" _ multiplication {% (d) => new ArithmeticBinaryOperation("Plus", d[0], d[4]) %}
24
+ | addition _ "-" _ multiplication {% (d) => new ArithmeticBinaryOperation("Minus", d[0], d[4]) %}
25
+ | multiplication {% id %}
26
+
27
+ # priority 7
28
+ multiplication ->
29
+ multiplication _ "*" _ primitive {% (d) => new ArithmeticBinaryOperation("Multiply", d[0], d[4]) %}
30
+ | multiplication _ "/" _ primitive {% (d) => new ArithmeticBinaryOperation("Divide", d[0], d[4]) %}
31
+ | primitive {% id %}
32
+
33
+ primitive ->
34
+ %number {% ([n]) => new NumberPrimitive(Number(n.value), loc(n)) %}
35
+ | %char {% ([c]) => new CharPrimitive(c.value, loc(c)) %}
36
+ | %variable {% ([c]) => new SymbolPrimitive(c.value, loc(c)) %}
37
+ | %string {% ([s]) => new StringPrimitive(s.value.slice(1, -1), loc(s)) %}
38
+ | %bool {% ([b]) => new BooleanPrimitive(b.value === 'True' ? true : false, loc(b)) %}
39
+
40
+
41
+ _ -> %WS:*
42
+
43
+ __ -> %WS:+
@@ -0,0 +1,38 @@
1
+ import grammar from "./grammar.js";
2
+ import nearley from "nearley";
3
+ import { AST, YukigoParser } from "yukigo-core";
4
+
5
+ export class YukigoParserPlaceholder implements YukigoParser {
6
+ public errors: string[] = [];
7
+ constructor() {
8
+ this.errors = [];
9
+ }
10
+
11
+ public parse(code: string): AST {
12
+ const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
13
+ try {
14
+ parser.feed(code);
15
+ parser.finish();
16
+ } catch (error) {
17
+ console.log(error);
18
+ if ("token" in error) {
19
+ const token = error.token;
20
+ const message = `Parser: Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`;
21
+ this.errors.push(message);
22
+ throw Error(message);
23
+ }
24
+ throw error;
25
+ }
26
+ if (parser.results.length > 1) {
27
+ const msg = `Parser: Too much ambiguity. ${parser.results.length} ASTs parsed. Output not generated.`;
28
+ this.errors.push(msg);
29
+ throw Error(msg);
30
+ }
31
+ if (parser.results.length == 0) {
32
+ this.errors.push("Parser did not generate an AST.");
33
+ throw Error("Parser did not generate an AST.");
34
+ }
35
+ const ast = parser.results[0];
36
+ return ast;
37
+ }
38
+ }
@@ -0,0 +1,19 @@
1
+ import moo from "moo";
2
+
3
+ export const LexerConfig = {
4
+ NL: { match: /\r?\n/, lineBreaks: true },
5
+ WS: / |\t/,
6
+ number:
7
+ /0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d*\.\d+|\d+)(?:[eE][+-]?\d+)?/,
8
+ char: /'(?:\\['\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^'\\\n\r])?'/,
9
+ string: /"(?:\\["\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^"\\\n\r])*"/,
10
+ bool: {
11
+ match: ["True", "False"],
12
+ },
13
+ op: /\+|-|\*|\//,
14
+ variable: {
15
+ match: /[a-z_][a-zA-Z0-9_']*/,
16
+ },
17
+ };
18
+
19
+ export const Lexer = moo.compile(LexerConfig);
@@ -0,0 +1,27 @@
1
+ import { YukigoParserPlaceholder } from "../src/index.js";
2
+ import {
3
+ ArithmeticBinaryOperation,
4
+ NumberPrimitive,
5
+ YukigoParser,
6
+ Return,
7
+ SourceLocation,
8
+ } from "yukigo-core";
9
+ import { assert } from "chai";
10
+
11
+ describe("Parser Tests", () => {
12
+ let parser: YukigoParser;
13
+ beforeEach(() => {
14
+ parser = new YukigoParserPlaceholder();
15
+ });
16
+ it("parses basic sum", () => {
17
+ assert.deepEqual(parser.parse("1 + 2"), [
18
+ new Return(
19
+ new ArithmeticBinaryOperation(
20
+ "Plus",
21
+ new NumberPrimitive(1, new SourceLocation(1, 1)),
22
+ new NumberPrimitive(2, new SourceLocation(1, 5))
23
+ )
24
+ ),
25
+ ]);
26
+ });
27
+ });
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2024",
4
+ "module": "nodenext",
5
+ "moduleResolution": "nodenext",
6
+ "lib": ["ES2024"],
7
+ "outDir": "./dist",
8
+ "declaration": true,
9
+ "esModuleInterop": true,
10
+ "allowSyntheticDefaultImports": true,
11
+ "sourceMap": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "skipLibCheck": true
14
+ },
15
+ "include": ["src"],
16
+ "exclude": ["dist/**/*"]
17
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist",
5
+ "module": "nodenext",
6
+ "target": "es2024",
7
+ "types": ["node"],
8
+ "lib": ["ES2024"],
9
+ "esModuleInterop": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "strict": true,
12
+ "skipLibCheck": true
13
+ },
14
+ "exclude": ["template", "dist"],
15
+ "include": ["src"]
16
+ }