@slim-lang/core 1.2.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 (52) hide show
  1. package/README.md +666 -0
  2. package/package.json +55 -0
  3. package/packages/slim/.spm +7 -0
  4. package/packages/slim/converters/main.slim +106 -0
  5. package/packages/slim/helpers/array.slim +25 -0
  6. package/packages/slim/helpers/path.slim +3 -0
  7. package/packages/slim/helpers/request.slim +102 -0
  8. package/packages/slim/helpers/string.slim +27 -0
  9. package/packages/slim/main.slim +42 -0
  10. package/packages/slim/parse/main.slim +25 -0
  11. package/packages/slim/server/main.slim +423 -0
  12. package/packages/slim/time/main.slim +66 -0
  13. package/packages/slim/types/common.slim +6 -0
  14. package/packages/slim/types/formats.slim +23 -0
  15. package/packages/slim/types/hash.slim +6 -0
  16. package/packages/slim/types/mails.slim +3 -0
  17. package/packages/slim/types/numerical.slim +9 -0
  18. package/packages/slim/types/time.slim +3 -0
  19. package/run-dev-slim.js +133 -0
  20. package/run-slim.js +20 -0
  21. package/src/bin/api/github_auth.js +89 -0
  22. package/src/bin/api/github_get.js +139 -0
  23. package/src/bin/api/github_req.js +455 -0
  24. package/src/bin/api/lock.js +37 -0
  25. package/src/bin/api/spm.js +103 -0
  26. package/src/bin/api/storage.js +30 -0
  27. package/src/bin/cli.js +404 -0
  28. package/src/bin/config.default.json +5 -0
  29. package/src/bin/helpers.js +147 -0
  30. package/src/bin/parsers/spm.js +174 -0
  31. package/src/bin/spm.js +519 -0
  32. package/src/checker.js +926 -0
  33. package/src/compile.js +230 -0
  34. package/src/external/classErrors.js +202 -0
  35. package/src/external/client.js +38 -0
  36. package/src/external/core.js +861 -0
  37. package/src/external/defaults.js +25 -0
  38. package/src/external/helpers.js +541 -0
  39. package/src/external/slim-globals.d.ts +65 -0
  40. package/src/external/types.js +38 -0
  41. package/src/format.js +81 -0
  42. package/src/handlers/errorHandler.js +43 -0
  43. package/src/handlers/parser/components.js +250 -0
  44. package/src/handlers/parserHandler.js +793 -0
  45. package/src/jsdoc.js +273 -0
  46. package/src/lexer.js +174 -0
  47. package/src/modulePaths.js +74 -0
  48. package/src/parser.js +818 -0
  49. package/src/repl.js +32 -0
  50. package/src/sourcemap.js +0 -0
  51. package/src/test-runner.js +62 -0
  52. package/src/transform.js +765 -0
@@ -0,0 +1,89 @@
1
+ import { formatBold, formatItalic } from "../helpers.js";
2
+
3
+ const CLIENT_ID = "Iv23lijjcVMtJwfS18dj";
4
+
5
+ const DEVICE_URL = "https://github.com/login/device/code";
6
+ const TOKEN_URL = "https://github.com/login/oauth/access_token";
7
+
8
+ export async function loginGitHub() {
9
+ if (!CLIENT_ID) {
10
+ throw new Error("GITHUB_CLIENT_ID is not configured");
11
+ }
12
+
13
+ const response = await fetch(DEVICE_URL, {
14
+ method: "POST",
15
+ headers: {
16
+ "Accept": "application/json",
17
+ "Content-Type": "application/x-www-form-urlencoded"
18
+ },
19
+ body: new URLSearchParams({
20
+ client_id: CLIENT_ID
21
+ })
22
+ });
23
+
24
+ if (!response.ok) {
25
+ throw new Error("Failed to start GitHub authorization");
26
+ }
27
+
28
+ const data = await response.json();
29
+
30
+ console.log("\n");
31
+ console.log("Open:", formatItalic.underline(data.verification_uri));
32
+ console.log(`Code: ${formatBold(data.user_code)}`);
33
+ console.log("");
34
+ console.log("Open the link and paste the code into the fields you see. Then, follow the steps");
35
+
36
+ let interval = data.interval || 5;
37
+
38
+ while (true) {
39
+ await sleep(interval * 1000);
40
+
41
+ const tokenResponse = await fetch(TOKEN_URL, {
42
+ method: "POST",
43
+ headers: {
44
+ "Accept": "application/json",
45
+ "Content-Type": "application/x-www-form-urlencoded"
46
+ },
47
+ body: new URLSearchParams({
48
+ client_id: CLIENT_ID,
49
+ device_code: data.device_code,
50
+ grant_type:
51
+ "urn:ietf:params:oauth:grant-type:device_code"
52
+ })
53
+ });
54
+
55
+ const tokenData = await tokenResponse.json();
56
+
57
+ if (tokenData.access_token) {
58
+ return tokenData.access_token;
59
+ }
60
+
61
+ if (tokenData.error === "authorization_pending") {
62
+ continue;
63
+ }
64
+
65
+ if (tokenData.error === "slow_down") {
66
+ interval += 5;
67
+ continue;
68
+ }
69
+
70
+ if (tokenData.error === "access_denied") {
71
+ throw new Error("GitHub authorization denied");
72
+ }
73
+
74
+ if (
75
+ tokenData.error === "expired_token"
76
+ ) {
77
+ throw new Error("GitHub authorization expired");
78
+ }
79
+
80
+ throw new Error(
81
+ tokenData.error_description ||
82
+ "GitHub authorization failed"
83
+ );
84
+ }
85
+ }
86
+
87
+ function sleep(ms) {
88
+ return new Promise(resolve => setTimeout(resolve, ms));
89
+ }
@@ -0,0 +1,139 @@
1
+ import { GITHUB_API, githubHeaders } from "./github_req.js";
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import os from "node:os";
6
+ import { pipeline } from "node:stream/promises";
7
+ import { createWriteStream } from "node:fs";
8
+ import * as tar from 'tar'
9
+
10
+ export async function getGitHubUser(token) {
11
+ const response = await fetch(
12
+ `${GITHUB_API}/user`,
13
+ {
14
+ headers: githubHeaders(token)
15
+ }
16
+ );
17
+
18
+ if (!response.ok) {
19
+ throw new Error("GitHub token is invalid");
20
+ }
21
+
22
+ return response.json();
23
+ }
24
+
25
+ export async function getGitHubRepo(token, repo) {
26
+ const response = await fetch(
27
+ `${GITHUB_API}/repos/${repo}`,
28
+ {
29
+ headers: githubHeaders(token)
30
+ }
31
+ );
32
+
33
+ if (!response.ok) {
34
+ throw new Error(
35
+ `GitHub repository "${repo}" not found`
36
+ );
37
+ }
38
+
39
+ return response.json();
40
+ }
41
+
42
+ export async function getPermission(token, repo, username) {
43
+ const response = await fetch(
44
+ `${GITHUB_API}/repos/${repo}/collaborators/${username}/permission`,
45
+ {
46
+ headers: githubHeaders(token)
47
+ }
48
+ );
49
+
50
+ if (!response.ok) {
51
+ throw new Error(
52
+ "Unable to verify repository permissions"
53
+ );
54
+ }
55
+
56
+ return response.json();
57
+ }
58
+
59
+ async function extractTarGz(file, destination) {
60
+ await tar.x({
61
+ file,
62
+ cwd: destination,
63
+ strip: 1
64
+ });
65
+ }
66
+
67
+ export async function downloadGitHubRepo(
68
+ token,
69
+ repository,
70
+ destination,
71
+ version = null
72
+ ) {
73
+ const match = repository.match(
74
+ /^([a-zA-Z0-9-]+)\/([a-zA-Z0-9._-]+)$/
75
+ );
76
+
77
+ if (!match) {
78
+ return {
79
+ success: false,
80
+ msg: "Repository must have format user/repo"
81
+ };
82
+ }
83
+
84
+ const [, owner, repo] = match;
85
+
86
+ try {
87
+ const ref = version
88
+ ? `tarball/v${version}`
89
+ : "tarball/main";
90
+
91
+ const response = await fetch(
92
+ `${GITHUB_API}/repos/${owner}/${repo}/${ref}`,
93
+ {
94
+ headers: githubHeaders(token)
95
+ }
96
+ );
97
+
98
+ if (!response.ok) {
99
+ const data = await response.json().catch(() => null);
100
+
101
+ return {
102
+ success: false,
103
+ msg: data?.message || `GitHub API error: ${response.status}`
104
+ };
105
+ }
106
+
107
+ const tempFile = path.join(
108
+ os.tmpdir(),
109
+ `spm-${owner}-${repo}-${Date.now()}.tar.gz`
110
+ );
111
+
112
+ await pipeline(
113
+ response.body,
114
+ createWriteStream(tempFile)
115
+ );
116
+
117
+ await fs.promises.mkdir(destination, {
118
+ recursive: true
119
+ });
120
+
121
+ await extractTarGz(tempFile, destination);
122
+
123
+ await fs.promises.unlink(tempFile);
124
+
125
+ return {
126
+ success: true,
127
+ msg: `Repository ${repository} downloaded`,
128
+ path: destination
129
+ };
130
+ }
131
+ catch (error) {
132
+ return {
133
+ success: false,
134
+ msg: error instanceof Error
135
+ ? error.message
136
+ : String(error)
137
+ };
138
+ }
139
+ }
@@ -0,0 +1,455 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ export const GITHUB_API = "https://api.github.com";
5
+ export const API_VERSION = "2026-03-10";
6
+
7
+ export function githubHeaders(token, extra = {}) {
8
+ return {
9
+ Accept: "application/vnd.github+json",
10
+ Authorization: `Bearer ${token}`,
11
+ "X-GitHub-Api-Version": API_VERSION,
12
+ ...extra
13
+ };
14
+ }
15
+
16
+ export async function githubRequest(token, url, options = {}) {
17
+ const response = await fetch(`${GITHUB_API}${url}`, {
18
+ ...options,
19
+ headers: githubHeaders(token, {
20
+ "Content-Type": "application/json",
21
+ ...options.headers
22
+ })
23
+ });
24
+
25
+ const data = await response.json();
26
+
27
+ if (!response.ok) {
28
+ throw new Error(
29
+ data.message || `GitHub API error: ${response.status}`
30
+ );
31
+ }
32
+
33
+ return data;
34
+ }
35
+
36
+ async function getFiles(dir, base = dir) {
37
+ const entries = await fs.readdir(dir, {
38
+ withFileTypes: true
39
+ });
40
+
41
+ const files = [];
42
+
43
+ for (const entry of entries) {
44
+ const fullPath = path.join(dir, entry.name);
45
+
46
+ if (entry.isDirectory()) {
47
+ files.push(
48
+ ...(await getFiles(fullPath, base))
49
+ );
50
+ continue;
51
+ }
52
+
53
+ if (!entry.isFile()) {
54
+ continue;
55
+ }
56
+
57
+ files.push({
58
+ path: path.relative(base, fullPath).replaceAll("\\", "/"),
59
+ fullPath
60
+ });
61
+ }
62
+
63
+ return files;
64
+ }
65
+
66
+ export async function publishToGitHub({
67
+ token,
68
+ repo,
69
+ contentPath,
70
+ branch = "main"
71
+ }) {
72
+ try {
73
+ const [owner, repoName] = repo.split("/");
74
+
75
+ if (!owner || !repoName || repo.split("/").length !== 2) {
76
+ return {
77
+ success: false,
78
+ msg: `Invalid GitHub repository: ${repo}`
79
+ };
80
+ }
81
+
82
+ const repository = await githubRequest(
83
+ token,
84
+ `/repos/${owner}/${repoName}`
85
+ );
86
+
87
+ const files = await getFiles(contentPath);
88
+
89
+ if (!files.length) {
90
+ return {
91
+ success: false,
92
+ msg: "Package directory is empty"
93
+ };
94
+ }
95
+
96
+ const reference = await githubRequest(
97
+ token,
98
+ `/repos/${owner}/${repoName}/git/ref/heads/${branch}`
99
+ );
100
+
101
+ const parentSha = reference.object.sha;
102
+
103
+ const parentCommit = await githubRequest(
104
+ token,
105
+ `/repos/${owner}/${repoName}/git/commits/${parentSha}`
106
+ );
107
+
108
+ const tree = [];
109
+
110
+ for (const file of files) {
111
+ const content = await fs.readFile(
112
+ file.fullPath,
113
+ "base64"
114
+ );
115
+
116
+ const blob = await githubRequest(
117
+ token,
118
+ `/repos/${owner}/${repoName}/git/blobs`,
119
+ {
120
+ method: "POST",
121
+ body: JSON.stringify({
122
+ content,
123
+ encoding: "base64"
124
+ })
125
+ }
126
+ );
127
+
128
+ tree.push({
129
+ path: file.path,
130
+ mode: "100644",
131
+ type: "blob",
132
+ sha: blob.sha
133
+ });
134
+ }
135
+
136
+ const newTree = await githubRequest(
137
+ token,
138
+ `/repos/${owner}/${repoName}/git/trees`,
139
+ {
140
+ method: "POST",
141
+ body: JSON.stringify({
142
+ base_tree: parentCommit.tree.sha,
143
+ tree
144
+ })
145
+ }
146
+ );
147
+
148
+ const commit = await githubRequest(
149
+ token,
150
+ `/repos/${owner}/${repoName}/git/commits`,
151
+ {
152
+ method: "POST",
153
+ body: JSON.stringify({
154
+ message: "Publish package",
155
+ tree: newTree.sha,
156
+ parents: [parentSha]
157
+ })
158
+ }
159
+ );
160
+
161
+ await githubRequest(
162
+ token,
163
+ `/repos/${owner}/${repoName}/git/refs/heads/${branch}`,
164
+ {
165
+ method: "PATCH",
166
+ body: JSON.stringify({
167
+ sha: commit.sha
168
+ })
169
+ }
170
+ );
171
+
172
+ return {
173
+ success: true,
174
+ msg: `Published ${repo}`,
175
+ repo: repository.full_name,
176
+ commit: commit.sha
177
+ };
178
+ }
179
+ catch (error) {
180
+ return {
181
+ success: false,
182
+ msg: error instanceof Error
183
+ ? error.message
184
+ : String(error)
185
+ };
186
+ }
187
+ }
188
+
189
+ export async function updateGitHubRepo({
190
+ token,
191
+ repo,
192
+ packagePath,
193
+ version,
194
+ message = `Release ${version}`
195
+ }) {
196
+ const branch = await githubRequest(
197
+ token,
198
+ `/repos/${repo}/git/ref/heads/main`
199
+ );
200
+
201
+ const parentSha = branch.object.sha;
202
+
203
+ const parentCommit = await githubRequest(
204
+ token,
205
+ `/repos/${repo}/git/commits/${parentSha}`
206
+ );
207
+
208
+ const baseTreeSha = parentCommit.tree.sha;
209
+
210
+ const files = await getFiles(packagePath);
211
+
212
+ if (files.length === 0) {
213
+ throw new Error("Package directory is empty");
214
+ }
215
+
216
+ const tree = [];
217
+
218
+ for (const file of files) {
219
+ const content = await fs.readFile(file.fullPath);
220
+
221
+ const blob = await githubRequest(
222
+ token,
223
+ `/repos/${repo}/git/blobs`,
224
+ {
225
+ method: "POST",
226
+ body: JSON.stringify({
227
+ content: content.toString("base64"),
228
+ encoding: "base64"
229
+ })
230
+ }
231
+ );
232
+
233
+ tree.push({
234
+ path: file.path,
235
+ mode: "100644",
236
+ type: "blob",
237
+ sha: blob.sha
238
+ });
239
+ }
240
+
241
+ const newTree = await githubRequest(
242
+ token,
243
+ `/repos/${repo}/git/trees`,
244
+ {
245
+ method: "POST",
246
+ body: JSON.stringify({
247
+ base_tree: baseTreeSha,
248
+ tree
249
+ })
250
+ }
251
+ );
252
+
253
+ const commit = await githubRequest(
254
+ token,
255
+ `/repos/${repo}/git/commits`,
256
+ {
257
+ method: "POST",
258
+ body: JSON.stringify({
259
+ message,
260
+ tree: newTree.sha,
261
+ parents: [parentSha]
262
+ })
263
+ }
264
+ );
265
+
266
+ await githubRequest(
267
+ token,
268
+ `/repos/${repo}/git/refs/heads/main`,
269
+ {
270
+ method: "PATCH",
271
+ body: JSON.stringify({
272
+ sha: commit.sha
273
+ })
274
+ }
275
+ );
276
+
277
+ const tagRef = `refs/tags/v${version}`;
278
+
279
+ await githubRequest(
280
+ token,
281
+ `/repos/${repo}/git/refs`,
282
+ {
283
+ method: "POST",
284
+ body: JSON.stringify({
285
+ ref: tagRef,
286
+ sha: commit.sha
287
+ })
288
+ }
289
+ );
290
+
291
+ return {
292
+ success: true,
293
+ commit: commit.sha,
294
+ tree: newTree.sha,
295
+ version,
296
+ tag: `v${version}`
297
+ };
298
+ }
299
+
300
+ export async function createGitHubRepo(token, repository, organization = false) {
301
+ const match = repository.match(
302
+ /^([a-zA-Z0-9-]+)\/([a-zA-Z0-9._-]+)$/
303
+ );
304
+
305
+ if (!match) {
306
+ return {
307
+ success: false,
308
+ msg: "Repository must have format user/repo"
309
+ };
310
+ }
311
+
312
+ const [, owner, repo] = match;
313
+
314
+ try {
315
+ const check = await fetch(
316
+ `${GITHUB_API}/repos/${owner}/${repo}`,
317
+ {
318
+ headers: githubHeaders(token)
319
+ }
320
+ );
321
+
322
+ if (check.ok) {
323
+ return {
324
+ success: false,
325
+ msg: `Repository ${repository} already exists`
326
+ };
327
+ }
328
+
329
+ if (check.status !== 404) {
330
+ const data = await check.json();
331
+
332
+ return {
333
+ success: false,
334
+ msg: data.message || `GitHub API error: ${check.status}`
335
+ };
336
+ }
337
+
338
+ // Organization repositories use the org endpoint; user repositories require ownership.
339
+ if (!organization) {
340
+ const userResponse = await fetch(
341
+ `${GITHUB_API}/user`,
342
+ {
343
+ headers: githubHeaders(token)
344
+ }
345
+ );
346
+
347
+ if (!userResponse.ok) {
348
+ const data = await userResponse.json();
349
+
350
+ return {
351
+ success: false,
352
+ msg: data.message || "Failed to get GitHub user"
353
+ };
354
+ }
355
+
356
+ const user = await userResponse.json();
357
+
358
+ if (user.login.toLowerCase() !== owner.toLowerCase()) {
359
+ return {
360
+ success: false,
361
+ msg: `You cannot create ${repository}. Your GitHub account is ${user.login}`
362
+ };
363
+ }
364
+ }
365
+
366
+ const createUrl = organization
367
+ ? `${GITHUB_API}/orgs/${owner}/repos`
368
+ : `${GITHUB_API}/user/repos`;
369
+
370
+ const response = await fetch(
371
+ createUrl,
372
+ {
373
+ method: "POST",
374
+ headers: githubHeaders(token, {
375
+ "Content-Type": "application/json"
376
+ }),
377
+ body: JSON.stringify({
378
+ name: repo,
379
+ private: false,
380
+ auto_init: true
381
+ })
382
+ }
383
+ );
384
+
385
+ const data = await response.json();
386
+
387
+ if (!response.ok) {
388
+ return {
389
+ success: false,
390
+ msg: data.message || `GitHub API error: ${response.status}`
391
+ };
392
+ }
393
+
394
+ return {
395
+ success: true,
396
+ msg: `Repository ${repository} created`,
397
+ repo: data
398
+ };
399
+ }
400
+ catch (error) {
401
+ return {
402
+ success: false,
403
+ msg: error instanceof Error
404
+ ? error.message
405
+ : String(error)
406
+ };
407
+ }
408
+ }
409
+
410
+ export async function deleteGitHubRepo(token, repository) {
411
+ const match = repository.match(
412
+ /^([a-zA-Z0-9-]+)\/([a-zA-Z0-9._-]+)$/
413
+ );
414
+
415
+ if (!match) {
416
+ return {
417
+ success: false,
418
+ msg: "Repository must have format user/repo"
419
+ };
420
+ }
421
+
422
+ const [, owner, repo] = match;
423
+
424
+ try {
425
+ const response = await fetch(
426
+ `${GITHUB_API}/repos/${owner}/${repo}`,
427
+ {
428
+ method: "DELETE",
429
+ headers: githubHeaders(token)
430
+ }
431
+ );
432
+
433
+ if (response.status === 204) {
434
+ return {
435
+ success: true,
436
+ msg: `Repository ${repository} deleted`
437
+ };
438
+ }
439
+
440
+ const data = await response.json().catch(() => null);
441
+
442
+ return {
443
+ success: false,
444
+ msg: data?.message || `GitHub API error: ${response.status}`
445
+ };
446
+ }
447
+ catch (error) {
448
+ return {
449
+ success: false,
450
+ msg: error instanceof Error
451
+ ? error.message
452
+ : String(error)
453
+ };
454
+ }
455
+ }
@@ -0,0 +1,37 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import { rootPath } from "../helpers.js"
4
+
5
+ export function lockFile(dir = rootPath) {
6
+ return path.join(dir, "spm.lock.json")
7
+ }
8
+
9
+ export function readLock(dir = rootPath) {
10
+ try {
11
+ const data = JSON.parse(fs.readFileSync(lockFile(dir), "utf8"))
12
+ if (!data.packages || typeof data.packages !== "object") data.packages = {}
13
+ return data
14
+ } catch {
15
+ return { packages: {} }
16
+ }
17
+ }
18
+
19
+ export function writeLock(data, dir = rootPath) {
20
+ fs.writeFileSync(lockFile(dir), JSON.stringify(data, null, 4) + "\n", "utf8")
21
+ return data
22
+ }
23
+
24
+ export function setLockEntry(name, entry, dir = rootPath) {
25
+ const lock = readLock(dir)
26
+ lock.packages[name] = entry
27
+ return writeLock(lock, dir)
28
+ }
29
+
30
+ export function removeLockEntry(name, dir = rootPath) {
31
+ const lock = readLock(dir)
32
+ if (name in lock.packages) {
33
+ delete lock.packages[name]
34
+ writeLock(lock, dir)
35
+ }
36
+ return lock
37
+ }