freelang-v4 4.3.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.
Files changed (261) hide show
  1. package/README.md +548 -0
  2. package/dist/ast.d.ts +367 -0
  3. package/dist/ast.js +4 -0
  4. package/dist/ast.js.map +1 -0
  5. package/dist/async-basic.test.d.ts +1 -0
  6. package/dist/async-basic.test.js +88 -0
  7. package/dist/async-basic.test.js.map +1 -0
  8. package/dist/async-jest.test.d.ts +1 -0
  9. package/dist/async-jest.test.js +99 -0
  10. package/dist/async-jest.test.js.map +1 -0
  11. package/dist/channel-jest.test.d.ts +1 -0
  12. package/dist/channel-jest.test.js +148 -0
  13. package/dist/channel-jest.test.js.map +1 -0
  14. package/dist/checker-jest.test.d.ts +1 -0
  15. package/dist/checker-jest.test.js +160 -0
  16. package/dist/checker-jest.test.js.map +1 -0
  17. package/dist/checker.d.ts +149 -0
  18. package/dist/checker.js +1565 -0
  19. package/dist/checker.js.map +1 -0
  20. package/dist/checker.test.d.ts +1 -0
  21. package/dist/checker.test.js +217 -0
  22. package/dist/checker.test.js.map +1 -0
  23. package/dist/compiler-jest.test.d.ts +1 -0
  24. package/dist/compiler-jest.test.js +233 -0
  25. package/dist/compiler-jest.test.js.map +1 -0
  26. package/dist/compiler.d.ts +127 -0
  27. package/dist/compiler.js +1588 -0
  28. package/dist/compiler.js.map +1 -0
  29. package/dist/compiler.test.d.ts +1 -0
  30. package/dist/compiler.test.js +313 -0
  31. package/dist/compiler.test.js.map +1 -0
  32. package/dist/db-100m-full.d.ts +5 -0
  33. package/dist/db-100m-full.js +78 -0
  34. package/dist/db-100m-full.js.map +1 -0
  35. package/dist/db-100m-no-index.d.ts +12 -0
  36. package/dist/db-100m-no-index.js +119 -0
  37. package/dist/db-100m-no-index.js.map +1 -0
  38. package/dist/db-100m-real.d.ts +5 -0
  39. package/dist/db-100m-real.js +131 -0
  40. package/dist/db-100m-real.js.map +1 -0
  41. package/dist/db-100m-streaming.d.ts +15 -0
  42. package/dist/db-100m-streaming.js +164 -0
  43. package/dist/db-100m-streaming.js.map +1 -0
  44. package/dist/db-100m-test.d.ts +5 -0
  45. package/dist/db-100m-test.js +111 -0
  46. package/dist/db-100m-test.js.map +1 -0
  47. package/dist/db-jest.test.d.ts +1 -0
  48. package/dist/db-jest.test.js +182 -0
  49. package/dist/db-jest.test.js.map +1 -0
  50. package/dist/db-runtime.d.ts +24 -0
  51. package/dist/db-runtime.js +204 -0
  52. package/dist/db-runtime.js.map +1 -0
  53. package/dist/db.d.ts +249 -0
  54. package/dist/db.js +593 -0
  55. package/dist/db.js.map +1 -0
  56. package/dist/file-io-jest.test.d.ts +1 -0
  57. package/dist/file-io-jest.test.js +225 -0
  58. package/dist/file-io-jest.test.js.map +1 -0
  59. package/dist/for-of-jest.test.d.ts +1 -0
  60. package/dist/for-of-jest.test.js +230 -0
  61. package/dist/for-of-jest.test.js.map +1 -0
  62. package/dist/for-of.test.d.ts +1 -0
  63. package/dist/for-of.test.js +305 -0
  64. package/dist/for-of.test.js.map +1 -0
  65. package/dist/function-literal-jest.test.d.ts +1 -0
  66. package/dist/function-literal-jest.test.js +180 -0
  67. package/dist/function-literal-jest.test.js.map +1 -0
  68. package/dist/function-literal.test.d.ts +1 -0
  69. package/dist/function-literal.test.js +245 -0
  70. package/dist/function-literal.test.js.map +1 -0
  71. package/dist/generics-jest.test.d.ts +1 -0
  72. package/dist/generics-jest.test.js +93 -0
  73. package/dist/generics-jest.test.js.map +1 -0
  74. package/dist/ir-gen.d.ts +15 -0
  75. package/dist/ir-gen.js +400 -0
  76. package/dist/ir-gen.js.map +1 -0
  77. package/dist/ir.d.ts +114 -0
  78. package/dist/ir.js +5 -0
  79. package/dist/ir.js.map +1 -0
  80. package/dist/lexer.d.ts +110 -0
  81. package/dist/lexer.js +467 -0
  82. package/dist/lexer.js.map +1 -0
  83. package/dist/lexer.test.d.ts +1 -0
  84. package/dist/lexer.test.js +426 -0
  85. package/dist/lexer.test.js.map +1 -0
  86. package/dist/main.d.ts +2 -0
  87. package/dist/main.js +241 -0
  88. package/dist/main.js.map +1 -0
  89. package/dist/module-jest.test.d.ts +1 -0
  90. package/dist/module-jest.test.js +123 -0
  91. package/dist/module-jest.test.js.map +1 -0
  92. package/dist/parser.d.ts +56 -0
  93. package/dist/parser.js +1060 -0
  94. package/dist/parser.js.map +1 -0
  95. package/dist/parser.test.d.ts +1 -0
  96. package/dist/parser.test.js +461 -0
  97. package/dist/parser.test.js.map +1 -0
  98. package/dist/pattern-matching-jest.test.d.ts +1 -0
  99. package/dist/pattern-matching-jest.test.js +158 -0
  100. package/dist/pattern-matching-jest.test.js.map +1 -0
  101. package/dist/pkg/init.d.ts +1 -0
  102. package/dist/pkg/init.js +118 -0
  103. package/dist/pkg/init.js.map +1 -0
  104. package/dist/pkg/install.d.ts +1 -0
  105. package/dist/pkg/install.js +77 -0
  106. package/dist/pkg/install.js.map +1 -0
  107. package/dist/pkg/registry.d.ts +23 -0
  108. package/dist/pkg/registry.js +106 -0
  109. package/dist/pkg/registry.js.map +1 -0
  110. package/dist/pkg/run.d.ts +1 -0
  111. package/dist/pkg/run.js +76 -0
  112. package/dist/pkg/run.js.map +1 -0
  113. package/dist/pkg/toml.d.ts +5 -0
  114. package/dist/pkg/toml.js +117 -0
  115. package/dist/pkg/toml.js.map +1 -0
  116. package/dist/repl.d.ts +15 -0
  117. package/dist/repl.js +197 -0
  118. package/dist/repl.js.map +1 -0
  119. package/dist/runtime/bytecode.d.ts +92 -0
  120. package/dist/runtime/bytecode.js +253 -0
  121. package/dist/runtime/bytecode.js.map +1 -0
  122. package/dist/runtime/value.d.ts +102 -0
  123. package/dist/runtime/value.js +302 -0
  124. package/dist/runtime/value.js.map +1 -0
  125. package/dist/runtime/vm.d.ts +65 -0
  126. package/dist/runtime/vm.js +293 -0
  127. package/dist/runtime/vm.js.map +1 -0
  128. package/dist/struct-instance-jest.test.d.ts +1 -0
  129. package/dist/struct-instance-jest.test.js +209 -0
  130. package/dist/struct-instance-jest.test.js.map +1 -0
  131. package/dist/struct-instance.test.d.ts +1 -0
  132. package/dist/struct-instance.test.js +291 -0
  133. package/dist/struct-instance.test.js.map +1 -0
  134. package/dist/struct-jest.test.d.ts +1 -0
  135. package/dist/struct-jest.test.js +176 -0
  136. package/dist/struct-jest.test.js.map +1 -0
  137. package/dist/struct.test.d.ts +1 -0
  138. package/dist/struct.test.js +231 -0
  139. package/dist/struct.test.js.map +1 -0
  140. package/dist/trait-jest.test.d.ts +1 -0
  141. package/dist/trait-jest.test.js +120 -0
  142. package/dist/trait-jest.test.js.map +1 -0
  143. package/dist/vm-jest.test.d.ts +1 -0
  144. package/dist/vm-jest.test.js +569 -0
  145. package/dist/vm-jest.test.js.map +1 -0
  146. package/dist/vm.d.ts +81 -0
  147. package/dist/vm.js +1956 -0
  148. package/dist/vm.js.map +1 -0
  149. package/dist/vm.test.d.ts +1 -0
  150. package/dist/vm.test.js +337 -0
  151. package/dist/vm.test.js.map +1 -0
  152. package/dist/web-repl/sandbox.d.ts +11 -0
  153. package/dist/web-repl/sandbox.js +76 -0
  154. package/dist/web-repl/sandbox.js.map +1 -0
  155. package/dist/web-repl/server.d.ts +1 -0
  156. package/dist/web-repl/server.js +111 -0
  157. package/dist/web-repl/server.js.map +1 -0
  158. package/dist/while-loop-jest.test.d.ts +1 -0
  159. package/dist/while-loop-jest.test.js +201 -0
  160. package/dist/while-loop-jest.test.js.map +1 -0
  161. package/dist/while-loop.test.d.ts +1 -0
  162. package/dist/while-loop.test.js +262 -0
  163. package/dist/while-loop.test.js.map +1 -0
  164. package/docs/EXPERIENCE.md +787 -0
  165. package/docs/README.md +175 -0
  166. package/docs/V1_V2_V3_ANALYSIS.md +107 -0
  167. package/docs/_config.yml +36 -0
  168. package/docs/api-reference.md +459 -0
  169. package/docs/architecture.md +470 -0
  170. package/docs/benchmarks.md +295 -0
  171. package/docs/comparison.md +454 -0
  172. package/docs/index.md +335 -0
  173. package/docs/language-completeness.md +228 -0
  174. package/docs/learning-guide.md +651 -0
  175. package/package.json +65 -0
  176. package/src/api/deploy_key.fl +294 -0
  177. package/src/api/issue.fl +302 -0
  178. package/src/api/org.fl +356 -0
  179. package/src/api/repo.fl +394 -0
  180. package/src/api/team.fl +299 -0
  181. package/src/api/user.fl +385 -0
  182. package/src/api/webhook.fl +273 -0
  183. package/src/ast.ts +158 -0
  184. package/src/async-basic.test.ts +94 -0
  185. package/src/async-jest.test.ts +107 -0
  186. package/src/channel-jest.test.ts +158 -0
  187. package/src/checker-jest.test.ts +189 -0
  188. package/src/checker.test.ts +279 -0
  189. package/src/checker.ts +1861 -0
  190. package/src/commands/analyze.fl +227 -0
  191. package/src/commands/auth.fl +315 -0
  192. package/src/commands/batch.fl +349 -0
  193. package/src/commands/config.fl +199 -0
  194. package/src/commands/deploy_key.fl +352 -0
  195. package/src/commands/issue.fl +275 -0
  196. package/src/commands/main.fl +492 -0
  197. package/src/commands/org.fl +425 -0
  198. package/src/commands/repo.fl +581 -0
  199. package/src/commands/team.fl +244 -0
  200. package/src/commands/user.fl +423 -0
  201. package/src/commands/webhook.fl +400 -0
  202. package/src/compiler-jest.test.ts +275 -0
  203. package/src/compiler.test.ts +375 -0
  204. package/src/compiler.ts +1770 -0
  205. package/src/config.fl +175 -0
  206. package/src/core/batch.fl +355 -0
  207. package/src/core/cache.fl +284 -0
  208. package/src/core/ensure.fl +324 -0
  209. package/src/db-100m-full.ts +96 -0
  210. package/src/db-100m-no-index.ts +133 -0
  211. package/src/db-100m-real.ts +152 -0
  212. package/src/db-100m-streaming.ts +154 -0
  213. package/src/db-100m-test.ts +136 -0
  214. package/src/db-jest.test.ts +161 -0
  215. package/src/db-runtime.ts +242 -0
  216. package/src/db.ts +676 -0
  217. package/src/errors.fl +134 -0
  218. package/src/for-of-jest.test.ts +246 -0
  219. package/src/for-of.test.ts +308 -0
  220. package/src/function-literal-jest.test.ts +193 -0
  221. package/src/function-literal.test.ts +248 -0
  222. package/src/generics-jest.test.ts +104 -0
  223. package/src/http/client.fl +327 -0
  224. package/src/ir-gen.ts +459 -0
  225. package/src/ir.ts +80 -0
  226. package/src/lexer.test.ts +499 -0
  227. package/src/lexer.ts +522 -0
  228. package/src/main.ts +223 -0
  229. package/src/models.fl +162 -0
  230. package/src/module-jest.test.ts +145 -0
  231. package/src/parser.test.ts +542 -0
  232. package/src/parser.ts +1211 -0
  233. package/src/pattern-matching-jest.test.ts +170 -0
  234. package/src/pkg/init.ts +91 -0
  235. package/src/pkg/install.ts +56 -0
  236. package/src/pkg/registry.ts +103 -0
  237. package/src/pkg/run.ts +49 -0
  238. package/src/pkg/toml.ts +129 -0
  239. package/src/repl.ts +190 -0
  240. package/src/runtime/bytecode.ts +291 -0
  241. package/src/runtime/value.ts +322 -0
  242. package/src/runtime/vm.ts +354 -0
  243. package/src/self-host/bootstrap.fl +68 -0
  244. package/src/self-host/interpreter.fl +361 -0
  245. package/src/self-host/lexer-simple.fl +22 -0
  246. package/src/self-host/lexer.fl +305 -0
  247. package/src/self-host/parser.fl +580 -0
  248. package/src/struct-instance-jest.test.ts +221 -0
  249. package/src/struct-instance.test.ts +293 -0
  250. package/src/struct-jest.test.ts +187 -0
  251. package/src/struct.test.ts +234 -0
  252. package/src/trait-jest.test.ts +136 -0
  253. package/src/vm-jest.test.ts +754 -0
  254. package/src/vm.ts +1976 -0
  255. package/src/web-repl/public/index.html +50 -0
  256. package/src/web-repl/public/main.js +105 -0
  257. package/src/web-repl/public/style.css +225 -0
  258. package/src/web-repl/sandbox.ts +88 -0
  259. package/src/web-repl/server.ts +97 -0
  260. package/src/while-loop-jest.test.ts +218 -0
  261. package/src/while-loop.test.ts +267 -0
@@ -0,0 +1,170 @@
1
+ import { Lexer } from "./lexer";
2
+ import { Parser } from "./parser";
3
+ import { Compiler } from "./compiler";
4
+ import { VM } from "./vm";
5
+
6
+ async function exec(source: string): Promise<{ output: string[]; error: string | null }> {
7
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
8
+ if (lexErrors.length > 0) throw new Error(`Lex: ${lexErrors[0].message}`);
9
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
10
+ if (parseErrors.length > 0) throw new Error(`Parse: ${parseErrors[0].message}`);
11
+ const chunk = new Compiler().compile(program);
12
+ return await new VM().run(chunk);
13
+ }
14
+
15
+ describe("Pattern Matching Features - Guard & Destructuring", () => {
16
+ // T1: Guard 절 기본
17
+ it("T1: should support guard clause", async () => {
18
+ const code = `
19
+ fn test() -> i32 {
20
+ var x = 10
21
+ match x {
22
+ y if y > 5 => 100,
23
+ y if y < 5 => 50,
24
+ _ => 0,
25
+ }
26
+ }
27
+ println(str(test()))
28
+ `;
29
+
30
+ const { output } = await exec(code);
31
+ expect(output).toEqual(["100"]);
32
+ });
33
+
34
+ // T2: Guard 절에서 패턴 바인딩 사용
35
+ it("T2: should use bindings in guard clause", async () => {
36
+ const code = `
37
+ fn test() -> i32 {
38
+ match 42 {
39
+ x if x > 40 => x + 1,
40
+ _ => 0,
41
+ }
42
+ }
43
+ println(str(test()))
44
+ `;
45
+
46
+ const { output } = await exec(code);
47
+ expect(output).toEqual(["43"]);
48
+ });
49
+
50
+ // T3: 구조체 분해 패턴 (기본)
51
+ it("T3: should support struct destructuring", async () => {
52
+ const code = `
53
+ struct Point {
54
+ x: i32,
55
+ y: i32,
56
+ }
57
+
58
+ fn test() -> i32 {
59
+ var p = Point { x: 10, y: 20 }
60
+ match p {
61
+ Point { x, y } => x + y,
62
+ _ => 0,
63
+ }
64
+ }
65
+ println(str(test()))
66
+ `;
67
+
68
+ const { output } = await exec(code);
69
+ expect(output).toEqual(["30"]);
70
+ });
71
+
72
+ // T4: 구조체 분해 + Guard 절
73
+ it("T4: should combine struct destructuring with guard", async () => {
74
+ const code = `
75
+ struct Point {
76
+ x: i32,
77
+ y: i32,
78
+ }
79
+
80
+ fn test() -> i32 {
81
+ var p = Point { x: 10, y: 20 }
82
+ match p {
83
+ Point { x, y } if x > 5 => x + y,
84
+ Point { x, y } if x <= 5 => y - x,
85
+ _ => 0,
86
+ }
87
+ }
88
+ println(str(test()))
89
+ `;
90
+
91
+ const { output } = await exec(code);
92
+ expect(output).toEqual(["30"]);
93
+ });
94
+
95
+ // T5: 배열 분해 패턴 (기본)
96
+ it("T5: should support array destructuring", async () => {
97
+ const code = `
98
+ fn test() -> i32 {
99
+ var arr = [10, 20, 30]
100
+ match arr {
101
+ [a, b, c] => a + b + c,
102
+ _ => 0,
103
+ }
104
+ }
105
+ println(str(test()))
106
+ `;
107
+
108
+ const { output } = await exec(code);
109
+ expect(output).toEqual(["60"]);
110
+ });
111
+
112
+ // T6: 배열 분해 + 나머지 패턴
113
+ it("T6: should support rest pattern in array", async () => {
114
+ const code = `
115
+ fn test() -> i32 {
116
+ var arr = [10, 20, 30, 40]
117
+ match arr {
118
+ [a, .., b] => a + b,
119
+ _ => 0,
120
+ }
121
+ }
122
+ println(str(test()))
123
+ `;
124
+
125
+ const { output } = await exec(code);
126
+ expect(output).toEqual(["50"]);
127
+ });
128
+
129
+ // T7: 다중 조건 가드
130
+ it("T7: should support multiple guard conditions", async () => {
131
+ const code = `
132
+ fn categorize(x: i32) -> i32 {
133
+ match x {
134
+ y if y < 0 => -1,
135
+ 0 => 0,
136
+ y if y > 0 => 1,
137
+ _ => 999,
138
+ }
139
+ }
140
+ println(str(categorize(42)))
141
+ `;
142
+
143
+ const { output } = await exec(code);
144
+ expect(output).toEqual(["1"]);
145
+ });
146
+
147
+ // T8: 복잡한 중첩 패턴
148
+ it("T8: should support complex nested patterns", async () => {
149
+ const code = `
150
+ struct Point {
151
+ x: i32,
152
+ y: i32,
153
+ }
154
+
155
+ fn test() -> i32 {
156
+ var p = Some(Point { x: 5, y: 10 })
157
+ match p {
158
+ Some(Point { x, y }) if x > 0 => x + y,
159
+ Some(Point { x, y }) if x <= 0 => y - x,
160
+ None => -999,
161
+ _ => 0,
162
+ }
163
+ }
164
+ println(str(test()))
165
+ `;
166
+
167
+ const { output } = await exec(code);
168
+ expect(output).toEqual(["15"]);
169
+ });
170
+ });
@@ -0,0 +1,91 @@
1
+ // freelang init [name] - Initialize a new FreeLang project
2
+
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { stringifyTOML } from "./toml";
6
+
7
+ export async function initProject(projectName: string = "my-app"): Promise<void> {
8
+ const projectPath = path.resolve(process.cwd(), projectName);
9
+
10
+ // Check if directory already exists
11
+ if (fs.existsSync(projectPath)) {
12
+ console.error(`Error: Directory '${projectName}' already exists`);
13
+ process.exit(1);
14
+ }
15
+
16
+ // Create project structure
17
+ fs.mkdirSync(projectPath, { recursive: true });
18
+ fs.mkdirSync(path.join(projectPath, "src"), { recursive: true });
19
+ fs.mkdirSync(path.join(projectPath, "tests"), { recursive: true });
20
+
21
+ // Create freelang.toml
22
+ const tomlContent = stringifyTOML({
23
+ package: {
24
+ name: projectName,
25
+ version: "0.1.0",
26
+ entry: "src/main.fl",
27
+ },
28
+ dependencies: {},
29
+ scripts: {
30
+ test: "freelang tests/main.fl",
31
+ },
32
+ });
33
+
34
+ fs.writeFileSync(path.join(projectPath, "freelang.toml"), tomlContent);
35
+
36
+ // Create main.fl
37
+ const mainContent = `// FreeLang v4 - ${projectName}
38
+
39
+ fn main() -> () {
40
+ println("Hello from FreeLang!")
41
+ }
42
+
43
+ main()
44
+ `;
45
+ fs.writeFileSync(path.join(projectPath, "src", "main.fl"), mainContent);
46
+
47
+ // Create test file
48
+ const testContent = `// Tests for ${projectName}
49
+
50
+ fn test_basic() -> bool {
51
+ var x = 42
52
+ x == 42
53
+ }
54
+
55
+ // Run: freelang tests/main.fl
56
+ `;
57
+ fs.writeFileSync(path.join(projectPath, "tests", "main.fl"), testContent);
58
+
59
+ // Create README.md
60
+ const readmeContent = `# ${projectName}
61
+
62
+ A FreeLang v4 project.
63
+
64
+ ## Build
65
+
66
+ \`\`\`bash
67
+ freelang run build
68
+ \`\`\`
69
+
70
+ ## Test
71
+
72
+ \`\`\`bash
73
+ freelang run test
74
+ \`\`\`
75
+
76
+ ## Run
77
+
78
+ \`\`\`bash
79
+ freelang src/main.fl
80
+ \`\`\`
81
+ `;
82
+ fs.writeFileSync(path.join(projectPath, "README.md"), readmeContent);
83
+
84
+ console.log(`✓ Created project '${projectName}' at ${projectPath}`);
85
+ console.log(" - freelang.toml (project configuration)");
86
+ console.log(" - src/main.fl (entry point)");
87
+ console.log(" - tests/main.fl (test file)");
88
+ console.log(" - README.md (documentation)");
89
+ console.log("");
90
+ console.log(`Run 'cd ${projectName} && freelang src/main.fl' to get started!`);
91
+ }
@@ -0,0 +1,56 @@
1
+ // freelang install <pkg> - Install a FreeLang package
2
+
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { parseTOML, stringifyTOML } from "./toml";
6
+
7
+ export async function installPackage(
8
+ packageName: string,
9
+ projectRoot: string,
10
+ ): Promise<void> {
11
+ const tomlPath = path.join(projectRoot, "freelang.toml");
12
+
13
+ // Read freelang.toml
14
+ if (!fs.existsSync(tomlPath)) {
15
+ console.error("Error: freelang.toml not found");
16
+ process.exit(1);
17
+ }
18
+
19
+ const tomlContent = fs.readFileSync(tomlPath, "utf-8");
20
+ const tomlData = parseTOML(tomlContent);
21
+
22
+ // Initialize dependencies if not present
23
+ if (!tomlData.dependencies) {
24
+ tomlData.dependencies = {};
25
+ }
26
+
27
+ // Check if package exists in registry
28
+ const registryPath = path.join(__dirname, "../../packages/registry.json");
29
+ if (!fs.existsSync(registryPath)) {
30
+ console.error("Error: Package registry not found");
31
+ process.exit(1);
32
+ }
33
+
34
+ const registry = JSON.parse(fs.readFileSync(registryPath, "utf-8"));
35
+ const pkg = registry.packages[packageName];
36
+
37
+ if (!pkg) {
38
+ console.error(`Error: Package '${packageName}' not found in registry`);
39
+ process.exit(1);
40
+ }
41
+
42
+ // Add package to dependencies
43
+ tomlData.dependencies[packageName] = {
44
+ version: pkg.latest_version,
45
+ path: `../../packages/${packageName}/${pkg.latest_version}/src`,
46
+ };
47
+
48
+ // Write updated freelang.toml
49
+ const updatedToml = stringifyTOML(tomlData);
50
+ fs.writeFileSync(tomlPath, updatedToml);
51
+
52
+ console.log(`✓ Installed ${packageName}@${pkg.latest_version}`);
53
+ console.log(
54
+ ` Description: ${pkg.description}`,
55
+ );
56
+ }
@@ -0,0 +1,103 @@
1
+ // Package registry exploration
2
+
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+
6
+ export interface Package {
7
+ name: string;
8
+ description: string;
9
+ version: string;
10
+ author?: string;
11
+ repository?: string;
12
+ }
13
+
14
+ export interface PackageRegistry {
15
+ packages: {
16
+ [name: string]: {
17
+ name: string;
18
+ description: string;
19
+ latest_version: string;
20
+ versions: string[];
21
+ author?: string;
22
+ repository?: string;
23
+ };
24
+ };
25
+ }
26
+
27
+ export function getRegistry(): PackageRegistry {
28
+ const registryPath = path.join(__dirname, "../../packages/registry.json");
29
+
30
+ if (!fs.existsSync(registryPath)) {
31
+ return { packages: {} };
32
+ }
33
+
34
+ try {
35
+ const content = fs.readFileSync(registryPath, "utf-8");
36
+ return JSON.parse(content);
37
+ } catch {
38
+ return { packages: {} };
39
+ }
40
+ }
41
+
42
+ export function listPackages(): void {
43
+ const registry = getRegistry();
44
+
45
+ if (Object.keys(registry.packages).length === 0) {
46
+ console.log("No packages available in registry");
47
+ return;
48
+ }
49
+
50
+ console.log("Available FreeLang packages:\n");
51
+
52
+ for (const [name, pkg] of Object.entries(registry.packages)) {
53
+ console.log(`${name}@${pkg.latest_version}`);
54
+ console.log(` ${pkg.description}`);
55
+ if (pkg.author) {
56
+ console.log(` By: ${pkg.author}`);
57
+ }
58
+ console.log("");
59
+ }
60
+ }
61
+
62
+ export function searchPackages(query: string): void {
63
+ const registry = getRegistry();
64
+ const results = Object.entries(registry.packages).filter(([name, pkg]) => {
65
+ return (
66
+ name.includes(query) ||
67
+ pkg.description.toLowerCase().includes(query.toLowerCase())
68
+ );
69
+ });
70
+
71
+ if (results.length === 0) {
72
+ console.log(`No packages found matching '${query}'`);
73
+ return;
74
+ }
75
+
76
+ console.log(`Found ${results.length} package(s) matching '${query}':\n`);
77
+
78
+ for (const [name, pkg] of results) {
79
+ console.log(`${name}@${pkg.latest_version}`);
80
+ console.log(` ${pkg.description}`);
81
+ console.log("");
82
+ }
83
+ }
84
+
85
+ export function getPackageInfo(name: string): void {
86
+ const registry = getRegistry();
87
+ const pkg = registry.packages[name];
88
+
89
+ if (!pkg) {
90
+ console.error(`Package '${name}' not found`);
91
+ process.exit(1);
92
+ }
93
+
94
+ console.log(`${pkg.name}@${pkg.latest_version}`);
95
+ console.log(`${pkg.description}`);
96
+ if (pkg.author) {
97
+ console.log(`Author: ${pkg.author}`);
98
+ }
99
+ if (pkg.repository) {
100
+ console.log(`Repository: ${pkg.repository}`);
101
+ }
102
+ console.log(`Versions: ${pkg.versions.join(", ")}`);
103
+ }
package/src/pkg/run.ts ADDED
@@ -0,0 +1,49 @@
1
+ // freelang run <script> - Run script from freelang.toml
2
+
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import { execSync } from "child_process";
6
+ import { parseTOML } from "./toml";
7
+
8
+ export async function runScript(
9
+ scriptName: string,
10
+ projectRoot: string,
11
+ ): Promise<void> {
12
+ const tomlPath = path.join(projectRoot, "freelang.toml");
13
+
14
+ // Read freelang.toml
15
+ if (!fs.existsSync(tomlPath)) {
16
+ console.error("Error: freelang.toml not found");
17
+ process.exit(1);
18
+ }
19
+
20
+ const tomlContent = fs.readFileSync(tomlPath, "utf-8");
21
+ const tomlData = parseTOML(tomlContent);
22
+
23
+ // Get script
24
+ if (!tomlData.scripts || !tomlData.scripts[scriptName]) {
25
+ console.error(`Error: Script '${scriptName}' not found in freelang.toml`);
26
+ console.log("Available scripts:");
27
+ if (tomlData.scripts) {
28
+ for (const [name] of Object.entries(tomlData.scripts)) {
29
+ console.log(` - ${name}`);
30
+ }
31
+ }
32
+ process.exit(1);
33
+ }
34
+
35
+ const scriptCommand = tomlData.scripts[scriptName];
36
+
37
+ console.log(`> ${scriptCommand}`);
38
+ console.log("");
39
+
40
+ try {
41
+ execSync(scriptCommand, {
42
+ cwd: projectRoot,
43
+ stdio: "inherit",
44
+ });
45
+ } catch (error) {
46
+ console.error("Script failed");
47
+ process.exit(1);
48
+ }
49
+ }
@@ -0,0 +1,129 @@
1
+ // Lightweight TOML Parser (no external dependencies)
2
+
3
+ export interface TomlValue {
4
+ [key: string]: any;
5
+ }
6
+
7
+ export function parseTOML(content: string): TomlValue {
8
+ const result: TomlValue = {};
9
+ const lines = content.split("\n");
10
+ let currentSection: string | null = null;
11
+ let currentObj: TomlValue = result;
12
+
13
+ for (let i = 0; i < lines.length; i++) {
14
+ const line = lines[i].trim();
15
+
16
+ // Skip empty lines and comments
17
+ if (!line || line.startsWith("#")) continue;
18
+
19
+ // Section header: [section]
20
+ if (line.startsWith("[") && line.endsWith("]")) {
21
+ currentSection = line.slice(1, -1).trim();
22
+ if (!result[currentSection]) {
23
+ result[currentSection] = {};
24
+ }
25
+ currentObj = result[currentSection];
26
+ continue;
27
+ }
28
+
29
+ // Key-value pairs: key = value
30
+ const eqIndex = line.indexOf("=");
31
+ if (eqIndex > 0) {
32
+ const key = line.substring(0, eqIndex).trim();
33
+ const valueStr = line.substring(eqIndex + 1).trim();
34
+ const value = parseValue(valueStr);
35
+ currentObj[key] = value;
36
+ }
37
+ }
38
+
39
+ return result;
40
+ }
41
+
42
+ function parseValue(valueStr: string): any {
43
+ // String values (double quotes)
44
+ if (valueStr.startsWith('"') && valueStr.endsWith('"')) {
45
+ return valueStr.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
46
+ }
47
+
48
+ // String values (single quotes)
49
+ if (valueStr.startsWith("'") && valueStr.endsWith("'")) {
50
+ return valueStr.slice(1, -1);
51
+ }
52
+
53
+ // Boolean values
54
+ if (valueStr === "true") return true;
55
+ if (valueStr === "false") return false;
56
+
57
+ // Numeric values
58
+ if (!isNaN(Number(valueStr))) {
59
+ return Number(valueStr);
60
+ }
61
+
62
+ // Array values [item1, item2, ...]
63
+ if (valueStr.startsWith("[") && valueStr.endsWith("]")) {
64
+ const itemsStr = valueStr.slice(1, -1);
65
+ const items = itemsStr.split(",").map((item) => parseValue(item.trim()));
66
+ return items;
67
+ }
68
+
69
+ // Table values {key = value, ...}
70
+ if (valueStr.startsWith("{") && valueStr.endsWith("}")) {
71
+ const content = valueStr.slice(1, -1);
72
+ const obj: TomlValue = {};
73
+ const pairs = content.split(",");
74
+ for (const pair of pairs) {
75
+ const eqIdx = pair.indexOf("=");
76
+ if (eqIdx > 0) {
77
+ const k = pair.substring(0, eqIdx).trim();
78
+ const v = pair.substring(eqIdx + 1).trim();
79
+ obj[k] = parseValue(v);
80
+ }
81
+ }
82
+ return obj;
83
+ }
84
+
85
+ // Return as string if no match
86
+ return valueStr;
87
+ }
88
+
89
+ export function stringifyTOML(obj: TomlValue, indent: number = 0): string {
90
+ const lines: string[] = [];
91
+ const indentStr = " ".repeat(indent);
92
+
93
+ for (const [key, value] of Object.entries(obj)) {
94
+ if (value === null || value === undefined) {
95
+ continue;
96
+ }
97
+
98
+ if (typeof value === "object" && !Array.isArray(value)) {
99
+ // Nested section
100
+ if (indent === 0) {
101
+ lines.push(`[${key}]`);
102
+ }
103
+ lines.push(stringifyTOML(value, indent + 2));
104
+ } else if (Array.isArray(value)) {
105
+ // Array
106
+ const items = value.map((v) => stringifyValue(v)).join(", ");
107
+ lines.push(`${indentStr}${key} = [${items}]`);
108
+ } else {
109
+ // Scalar value
110
+ lines.push(`${indentStr}${key} = ${stringifyValue(value)}`);
111
+ }
112
+ }
113
+
114
+ return lines.filter((l) => l).join("\n");
115
+ }
116
+
117
+ function stringifyValue(value: any): string {
118
+ if (typeof value === "string") {
119
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
120
+ }
121
+ if (typeof value === "boolean") {
122
+ return value ? "true" : "false";
123
+ }
124
+ if (Array.isArray(value)) {
125
+ const items = value.map((v) => stringifyValue(v)).join(", ");
126
+ return `[${items}]`;
127
+ }
128
+ return String(value);
129
+ }