fenrir-runtime 0.0.1
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/App/App.axaml +8 -0
- package/App/App.axaml.cs +23 -0
- package/App/FenrirLinux.csproj +27 -0
- package/App/LICENSE +674 -0
- package/App/MainWindow.axaml +10 -0
- package/App/MainWindow.axaml.cs +16 -0
- package/App/Program.cs +19 -0
- package/App/README.md +24 -0
- package/App/Views/InstallationView.axaml +48 -0
- package/App/Views/InstallationView.axaml.cs +204 -0
- package/App/Views/PasswordView.axaml +34 -0
- package/App/Views/PasswordView.axaml.cs +62 -0
- package/App/Views/WelcomeView.axaml +63 -0
- package/App/Views/WelcomeView.axaml.cs +22 -0
- package/App/app.manifest +18 -0
- package/App/images/screenshot1.png +0 -0
- package/App/images/screenshot2.png +0 -0
- package/App/obj/Debug/net9.0/Avalonia/Resources.Inputs.cache +1 -0
- package/App/obj/Debug/net9.0/Avalonia/original.dll +0 -0
- package/App/obj/Debug/net9.0/Avalonia/original.pdb +0 -0
- package/App/obj/Debug/net9.0/Avalonia/original.ref.dll +0 -0
- package/App/obj/Debug/net9.0/Avalonia/references +202 -0
- package/App/obj/Debug/net9.0/Avalonia/resources +0 -0
- package/App/obj/Debug/net9.0/FenrirLi.7B98506C.Up2Date +0 -0
- package/App/obj/Debug/net9.0/FenrirLinux.AssemblyInfo.cs +22 -0
- package/App/obj/Debug/net9.0/FenrirLinux.AssemblyInfoInputs.cache +1 -0
- package/App/obj/Debug/net9.0/FenrirLinux.GeneratedMSBuildEditorConfig.editorconfig +35 -0
- package/App/obj/Debug/net9.0/FenrirLinux.assets.cache +0 -0
- package/App/obj/Debug/net9.0/FenrirLinux.csproj.AssemblyReference.cache +0 -0
- package/App/obj/Debug/net9.0/FenrirLinux.csproj.CoreCompileInputs.cache +1 -0
- package/App/obj/Debug/net9.0/FenrirLinux.csproj.FileListAbsolute.txt +135 -0
- package/App/obj/Debug/net9.0/FenrirLinux.dll +0 -0
- package/App/obj/Debug/net9.0/FenrirLinux.genruntimeconfig.cache +1 -0
- package/App/obj/Debug/net9.0/FenrirLinux.pdb +0 -0
- package/App/obj/Debug/net9.0/apphost +0 -0
- package/App/obj/Debug/net9.0/ref/FenrirLinux.dll +0 -0
- package/App/obj/Debug/net9.0/refint/FenrirLinux.dll +0 -0
- package/App/obj/FenrirLinux.csproj.nuget.dgspec.json +115 -0
- package/App/obj/FenrirLinux.csproj.nuget.g.props +26 -0
- package/App/obj/FenrirLinux.csproj.nuget.g.targets +9 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/Resources.Inputs.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/original.dll +0 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/original.pdb +0 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/original.ref.dll +0 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/references +194 -0
- package/App/obj/Release/net9.0/linux-x64/Avalonia/resources +0 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLi.7B98506C.Up2Date +0 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.AssemblyInfo.cs +22 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.AssemblyInfoInputs.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.GeneratedMSBuildEditorConfig.editorconfig +39 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.assets.cache +0 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.csproj.AssemblyReference.cache +0 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.csproj.CoreCompileInputs.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.csproj.FileListAbsolute.txt +238 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.deps.json +1317 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.dll +0 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.genbundle.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.genpublishdeps.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.genruntimeconfig.cache +1 -0
- package/App/obj/Release/net9.0/linux-x64/FenrirLinux.pdb +0 -0
- package/App/obj/Release/net9.0/linux-x64/PublishOutputs.fac9e24064.txt +4 -0
- package/App/obj/Release/net9.0/linux-x64/apphost +0 -0
- package/App/obj/Release/net9.0/linux-x64/ref/FenrirLinux.dll +0 -0
- package/App/obj/Release/net9.0/linux-x64/refint/FenrirLinux.dll +0 -0
- package/App/obj/Release/net9.0/linux-x64/singlefilehost +0 -0
- package/App/obj/project.assets.json +2463 -0
- package/App/obj/project.nuget.cache +47 -0
- package/LICENSE +674 -0
- package/Makefile +16 -0
- package/README.md +89 -0
- package/dist/archiveSystem.js +219 -0
- package/dist/cli.js +188 -0
- package/dist/packageManager.js +98 -0
- package/dist/parser.js +24 -0
- package/dist/runtime.js +99 -0
- package/dist/transformer.js +120 -0
- package/example/fenrir+aperium/aperium.json +17 -0
- package/example/fenrir+aperium/aperium_modules/hello-world/index.js +4 -0
- package/example/fenrir+aperium/aperium_modules/hello-world/module.json +6 -0
- package/example/fenrir+aperium/app.fnr +19 -0
- package/example/fenrir+aperium/package-lock.json +890 -0
- package/example/fenrir+aperium/package.json +17 -0
- package/example/fenrir.json +10 -0
- package/example/main.fnr +18 -0
- package/example/package-lock.json +867 -0
- package/example/package.json +17 -0
- package/package.json +32 -0
- package/src/archiveSystem.ts +264 -0
- package/src/cli.ts +216 -0
- package/src/packageManager.ts +119 -0
- package/src/parser.ts +36 -0
- package/src/runtime.ts +111 -0
- package/src/transformer.ts +147 -0
- package/tsconfig.json +15 -0
package/Makefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.PHONY: install build all
|
|
2
|
+
|
|
3
|
+
all: install build
|
|
4
|
+
|
|
5
|
+
install:
|
|
6
|
+
@echo "Running npm install..."
|
|
7
|
+
npm install
|
|
8
|
+
|
|
9
|
+
build:
|
|
10
|
+
@echo "Running npm run build..."
|
|
11
|
+
npm run build
|
|
12
|
+
@echo "Finish."
|
|
13
|
+
|
|
14
|
+
clean:
|
|
15
|
+
@echo "Cleaning up node_modules and build files..."
|
|
16
|
+
rm -rf node_modules build dist
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Fenrir Runtime
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
**Fenrir** is a modern JavaScript runtime environment based on TypeScript.
|
|
6
|
+
It provides developers with a fast, secure, and flexible working environment. Thanks to TypeScript support, it offers powerful type safety and a modern development experience. Fenrir is distributed as open source and is open to community contributions.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
- **TypeScript Compatibility:** Compatible with all TypeScript functions, making your projects more secure and sustainable.
|
|
13
|
+
|
|
14
|
+
- **Rollback System:** Reduces the risk of errors by allowing you to undo changes.
|
|
15
|
+
|
|
16
|
+
- **Modern Framework Support:** Works seamlessly with popular libraries such as Express, Koa, and Fastify.
|
|
17
|
+
|
|
18
|
+
- **Open Source and Community-Focused:** You can review, modify, and contribute to the project.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
23
|
+
|
|
24
|
+
Installing Fenrir is very easy. You can run the project by following the steps below:
|
|
25
|
+
|
|
26
|
+
1. Clone the repository.
|
|
27
|
+
```
|
|
28
|
+
git clone https://github.com/yigitkabak/Fenrir
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. Enter the Project Directory.
|
|
32
|
+
```
|
|
33
|
+
cd Fenrir
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
3. Install and Compile Dependencies.
|
|
37
|
+
```
|
|
38
|
+
make
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or if you use Linux, you can download our application. [App](/App)
|
|
42
|
+
|
|
43
|
+
Once the installation is complete, **Fenrir** is ready to use in your projects.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### Example Usage
|
|
48
|
+
|
|
49
|
+
Creating a simple Express server with **Fenrir** is quite easy:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
declare express from 'express'
|
|
53
|
+
|
|
54
|
+
const app = express()
|
|
55
|
+
const port = 3000
|
|
56
|
+
|
|
57
|
+
fn handle_home_request(req, res) {
|
|
58
|
+
res.send('Hello from Fenrir Express!')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
app.get('/', handle_home_request)
|
|
62
|
+
|
|
63
|
+
fn start_server() {
|
|
64
|
+
app.listen(port, () => {
|
|
65
|
+
log(`Server running at http://localhost:${port}`)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
start_server()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
With this example, you can see the message **"Hello from Fenrir Express!"** by going to http://localhost:3000 in your browser.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
### Contributing
|
|
76
|
+
|
|
77
|
+
- **Fenrir** is a community-driven project. To contribute:
|
|
78
|
+
|
|
79
|
+
1. **Use the project and provide feedback:** Report bugs or suggestions.
|
|
80
|
+
|
|
81
|
+
2. **Contribute code:** Add new features or improve existing code.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
NOTE: ⚠️ **Fenrir** is currently in BETA. You may encounter unexpected errors. Your feedback will greatly contribute to the development of the project.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
## Licence
|
|
89
|
+
**Fenrir** is licensed under the [GPL](LICENSE) Licence.
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import { glob } from 'glob';
|
|
6
|
+
export class ArchiveSystem {
|
|
7
|
+
projectRoot;
|
|
8
|
+
archiveDir;
|
|
9
|
+
constructor(projectRoot = process.cwd()) {
|
|
10
|
+
this.projectRoot = projectRoot;
|
|
11
|
+
this.archiveDir = path.join(projectRoot, '.fenrir', 'archives');
|
|
12
|
+
}
|
|
13
|
+
async createArchive(message) {
|
|
14
|
+
const now = new Date();
|
|
15
|
+
const timestamp = this.formatTimestamp(now);
|
|
16
|
+
const archivePath = path.join(this.archiveDir, timestamp);
|
|
17
|
+
await fs.ensureDir(archivePath);
|
|
18
|
+
const filesToArchive = await this.getFilesToArchive();
|
|
19
|
+
for (const file of filesToArchive) {
|
|
20
|
+
const srcPath = path.join(this.projectRoot, file);
|
|
21
|
+
const destPath = path.join(archivePath, file);
|
|
22
|
+
await fs.ensureDir(path.dirname(destPath));
|
|
23
|
+
await fs.copy(srcPath, destPath);
|
|
24
|
+
}
|
|
25
|
+
const metadata = {
|
|
26
|
+
timestamp: now.toISOString(),
|
|
27
|
+
message: message || 'Automatic archiving',
|
|
28
|
+
files: filesToArchive.length,
|
|
29
|
+
hash: this.generateHash(filesToArchive),
|
|
30
|
+
gitHash: await this.getGitHash().catch(() => null)
|
|
31
|
+
};
|
|
32
|
+
await fs.writeJSON(path.join(archivePath, '.metadata.json'), metadata, { spaces: 2 });
|
|
33
|
+
console.log(`Archive created: ${timestamp}`);
|
|
34
|
+
console.log(` ${filesToArchive.length} file archived`);
|
|
35
|
+
console.log(`message: ${metadata.message}`);
|
|
36
|
+
return timestamp;
|
|
37
|
+
}
|
|
38
|
+
async listArchives() {
|
|
39
|
+
if (!fs.existsSync(this.archiveDir)) {
|
|
40
|
+
console.log('No archives have been created yet.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const archives = await fs.readdir(this.archiveDir);
|
|
44
|
+
archives.sort().reverse();
|
|
45
|
+
console.log('Archive history:');
|
|
46
|
+
for (const archive of archives.slice(0, 10)) {
|
|
47
|
+
const metadataPath = path.join(this.archiveDir, archive, '.metadata.json');
|
|
48
|
+
if (fs.existsSync(metadataPath)) {
|
|
49
|
+
const metadata = await fs.readJSON(metadataPath);
|
|
50
|
+
const date = new Date(metadata.timestamp);
|
|
51
|
+
console.log(` ${archive} - ${metadata.message}`);
|
|
52
|
+
console.log(` ${date.toLocaleString('en-US')}`);
|
|
53
|
+
console.log(` ${metadata.files} file`);
|
|
54
|
+
console.log('');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (archives.length > 10) {
|
|
58
|
+
console.log(` ... and ${archives.length - 10} archive more`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async rollback(archiveId) {
|
|
62
|
+
if (!fs.existsSync(this.archiveDir)) {
|
|
63
|
+
console.log('Archive not found.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let targetArchive = archiveId;
|
|
67
|
+
if (!targetArchive) {
|
|
68
|
+
const archives = await fs.readdir(this.archiveDir);
|
|
69
|
+
archives.sort().reverse();
|
|
70
|
+
targetArchive = archives[0];
|
|
71
|
+
}
|
|
72
|
+
const archivePath = path.join(this.archiveDir, targetArchive);
|
|
73
|
+
if (!fs.existsSync(archivePath)) {
|
|
74
|
+
console.log(`Archive not found: ${targetArchive}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log('Current status is being backed up...');
|
|
78
|
+
await this.createArchive(`Pre-rollback backup - ${new Date().toISOString()}`);
|
|
79
|
+
const metadataPath = path.join(archivePath, '.metadata.json');
|
|
80
|
+
const metadata = await fs.readJSON(metadataPath);
|
|
81
|
+
console.log(`${targetArchive} returning to archive...`);
|
|
82
|
+
console.log(` ${metadata.message}`);
|
|
83
|
+
const currentFiles = await this.getFilesToArchive();
|
|
84
|
+
for (const file of currentFiles) {
|
|
85
|
+
const filePath = path.join(this.projectRoot, file);
|
|
86
|
+
if (fs.existsSync(filePath)) {
|
|
87
|
+
await fs.remove(filePath);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const archiveFiles = await glob('**/*', {
|
|
91
|
+
cwd: archivePath,
|
|
92
|
+
nodir: true,
|
|
93
|
+
ignore: '.metadata.json'
|
|
94
|
+
});
|
|
95
|
+
for (const file of archiveFiles) {
|
|
96
|
+
const srcPath = path.join(archivePath, file);
|
|
97
|
+
const destPath = path.join(this.projectRoot, file);
|
|
98
|
+
await fs.ensureDir(path.dirname(destPath));
|
|
99
|
+
await fs.copy(srcPath, destPath);
|
|
100
|
+
}
|
|
101
|
+
console.log(`The return has been completed!`);
|
|
102
|
+
console.log(`${archiveFiles.length} file restored`);
|
|
103
|
+
}
|
|
104
|
+
async cleanArchives(keepCount = 10) {
|
|
105
|
+
if (!fs.existsSync(this.archiveDir)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const archives = await fs.readdir(this.archiveDir);
|
|
109
|
+
archives.sort().reverse();
|
|
110
|
+
if (archives.length <= keepCount) {
|
|
111
|
+
console.log(`${archives.length} There is an archive, no cleaning is necessary.`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const toDelete = archives.slice(keepCount);
|
|
115
|
+
for (const archive of toDelete) {
|
|
116
|
+
await fs.remove(path.join(this.archiveDir, archive));
|
|
117
|
+
}
|
|
118
|
+
console.log(`${toDelete.length} The old archive has been cleared.`);
|
|
119
|
+
console.log(`${keepCount} The archive has been preserved.`);
|
|
120
|
+
}
|
|
121
|
+
formatTimestamp(date) {
|
|
122
|
+
return date.toISOString()
|
|
123
|
+
.replace(/T/, '_')
|
|
124
|
+
.replace(/:/g, '-')
|
|
125
|
+
.substring(0, 19);
|
|
126
|
+
}
|
|
127
|
+
async getFilesToArchive() {
|
|
128
|
+
const patterns = [
|
|
129
|
+
'**/*.py',
|
|
130
|
+
'**/*.pyc',
|
|
131
|
+
'**/*.pyo',
|
|
132
|
+
'**/*.java',
|
|
133
|
+
'**/*.class',
|
|
134
|
+
'**/*.jar',
|
|
135
|
+
'**/*.cpp',
|
|
136
|
+
'**/*.cxx',
|
|
137
|
+
'**/*.cc',
|
|
138
|
+
'**/*.c',
|
|
139
|
+
'**/*.hpp',
|
|
140
|
+
'**/*.h',
|
|
141
|
+
'**/*.hxx',
|
|
142
|
+
'**/*.cs',
|
|
143
|
+
'**/*.csproj',
|
|
144
|
+
'**/*.sln',
|
|
145
|
+
'**/*.rb',
|
|
146
|
+
'**/*.rake',
|
|
147
|
+
'**/*.php',
|
|
148
|
+
'**/*.phtml',
|
|
149
|
+
'**/*.php3',
|
|
150
|
+
'**/*.php4',
|
|
151
|
+
'**/*.php5',
|
|
152
|
+
'**/*.swift',
|
|
153
|
+
'**/*.go',
|
|
154
|
+
'**/*.rs',
|
|
155
|
+
'**/*.js',
|
|
156
|
+
'**/*.ts',
|
|
157
|
+
'**/*.jsx',
|
|
158
|
+
'**/*.tsx',
|
|
159
|
+
'**/*.mjs',
|
|
160
|
+
'**/*.cjs',
|
|
161
|
+
'**/*.css',
|
|
162
|
+
'**/*.scss',
|
|
163
|
+
'**/*.sass',
|
|
164
|
+
'**/*.less',
|
|
165
|
+
'**/*.html',
|
|
166
|
+
'**/*.htm',
|
|
167
|
+
'**/*.xhtml',
|
|
168
|
+
'**/*.json',
|
|
169
|
+
'**/*.xml',
|
|
170
|
+
'**/*.yml',
|
|
171
|
+
'**/*.yaml',
|
|
172
|
+
'**/*.md',
|
|
173
|
+
'**/*.markdown',
|
|
174
|
+
'**/*.mdown',
|
|
175
|
+
'**/*.txt',
|
|
176
|
+
'**/*.ini',
|
|
177
|
+
'**/*.conf',
|
|
178
|
+
'**/*.cfg',
|
|
179
|
+
'**/*.sh',
|
|
180
|
+
'**/*.bash',
|
|
181
|
+
'**/*.npm',
|
|
182
|
+
'**/*.lock',
|
|
183
|
+
'**/*.fnr'
|
|
184
|
+
];
|
|
185
|
+
const ignorePatterns = [
|
|
186
|
+
'.fenrir/**',
|
|
187
|
+
'node_modules/**',
|
|
188
|
+
'.git/**',
|
|
189
|
+
'*.log',
|
|
190
|
+
'.DS_Store',
|
|
191
|
+
'Thumbs.db',
|
|
192
|
+
'.env*',
|
|
193
|
+
'dist/**',
|
|
194
|
+
'build/**',
|
|
195
|
+
'.cache/**'
|
|
196
|
+
];
|
|
197
|
+
const files = [];
|
|
198
|
+
for (const pattern of patterns) {
|
|
199
|
+
const matches = await glob(pattern, {
|
|
200
|
+
cwd: this.projectRoot,
|
|
201
|
+
ignore: ignorePatterns,
|
|
202
|
+
nodir: true
|
|
203
|
+
});
|
|
204
|
+
files.push(...matches);
|
|
205
|
+
}
|
|
206
|
+
return [...new Set(files)].sort();
|
|
207
|
+
}
|
|
208
|
+
generateHash(files) {
|
|
209
|
+
const hash = crypto.createHash('md5');
|
|
210
|
+
hash.update(files.join('|'));
|
|
211
|
+
return hash.digest('hex').substring(0, 8);
|
|
212
|
+
}
|
|
213
|
+
async getGitHash() {
|
|
214
|
+
return execSync('git rev-parse HEAD', {
|
|
215
|
+
cwd: this.projectRoot,
|
|
216
|
+
encoding: 'utf8'
|
|
217
|
+
}).trim();
|
|
218
|
+
}
|
|
219
|
+
}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { transformFenrirCode } from './transformer.js';
|
|
8
|
+
import { PackageManager } from './packageManager.js';
|
|
9
|
+
import { ArchiveSystem } from './archiveSystem.js';
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const command = process.argv[2];
|
|
13
|
+
const args = process.argv.slice(3);
|
|
14
|
+
const packageManager = new PackageManager();
|
|
15
|
+
const archiveSystem = new ArchiveSystem();
|
|
16
|
+
const executeCode = async (filePath) => {
|
|
17
|
+
try {
|
|
18
|
+
if (!await fs.pathExists(filePath)) {
|
|
19
|
+
console.error(`Error: File ${filePath} not found.`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
23
|
+
if (!fileContent.trim()) {
|
|
24
|
+
console.error('Error: The file is empty or contains only space characters.');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const aperiumConfig = fs.existsSync('fenrir.json')
|
|
28
|
+
? JSON.parse(await fs.readFile('fenrir.json', 'utf8'))
|
|
29
|
+
: {};
|
|
30
|
+
const jsCode = await transformFenrirCode(fileContent, filePath, aperiumConfig.imports || {});
|
|
31
|
+
if (process.env.FENRIR_DEBUG) {
|
|
32
|
+
console.log('\nConverted JavaScript code:');
|
|
33
|
+
console.log(jsCode);
|
|
34
|
+
}
|
|
35
|
+
const tempDir = path.join(os.tmpdir(), `fenrir_temp_${Date.now()}`);
|
|
36
|
+
await fs.ensureDir(tempDir);
|
|
37
|
+
const tempFilePath = path.join(tempDir, 'runtime_output.mjs');
|
|
38
|
+
// node_modules kopyalama işlemini iyileştir
|
|
39
|
+
const originalNodeModulesPath = path.join(process.cwd(), 'node_modules');
|
|
40
|
+
const tempNodeModulesPath = path.join(tempDir, 'node_modules');
|
|
41
|
+
if (await fs.pathExists(originalNodeModulesPath)) {
|
|
42
|
+
try {
|
|
43
|
+
await fs.copy(originalNodeModulesPath, tempNodeModulesPath, {
|
|
44
|
+
dereference: true,
|
|
45
|
+
preserveTimestamps: false
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (copyError) {
|
|
49
|
+
console.warn('Warning: Could not copy node_modules:', copyError?.message || copyError);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const originalPackageJsonPath = path.join(process.cwd(), 'package.json');
|
|
53
|
+
if (await fs.pathExists(originalPackageJsonPath)) {
|
|
54
|
+
try {
|
|
55
|
+
await fs.copy(originalPackageJsonPath, path.join(tempDir, 'package.json'));
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.warn('Warning: Could not copy package.json:', err?.message || err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const runtimePath = path.join(__dirname, 'runtime.js');
|
|
62
|
+
let finalCode = jsCode;
|
|
63
|
+
if (fs.existsSync(runtimePath)) {
|
|
64
|
+
const runtimeCode = await fs.readFile(runtimePath, 'utf8');
|
|
65
|
+
finalCode = `${runtimeCode}\n\n${jsCode}`;
|
|
66
|
+
}
|
|
67
|
+
await fs.writeFile(tempFilePath, finalCode);
|
|
68
|
+
const env = {
|
|
69
|
+
...process.env,
|
|
70
|
+
NODE_PATH: [
|
|
71
|
+
path.join(tempDir, 'node_modules'),
|
|
72
|
+
path.join(process.cwd(), 'node_modules'),
|
|
73
|
+
process.env.NODE_PATH
|
|
74
|
+
].filter(Boolean).join(path.delimiter)
|
|
75
|
+
};
|
|
76
|
+
if (process.env.FENRIR_DEBUG) {
|
|
77
|
+
console.log('Temp directory:', tempDir);
|
|
78
|
+
console.log('Original CWD:', process.cwd());
|
|
79
|
+
console.log('NODE_PATH:', env.NODE_PATH);
|
|
80
|
+
console.log('\nGenerated code:');
|
|
81
|
+
console.log('================');
|
|
82
|
+
console.log(finalCode);
|
|
83
|
+
console.log('================\n');
|
|
84
|
+
}
|
|
85
|
+
const child = spawn('node', [tempFilePath], {
|
|
86
|
+
stdio: 'inherit',
|
|
87
|
+
shell: false,
|
|
88
|
+
env: env,
|
|
89
|
+
cwd: process.cwd()
|
|
90
|
+
});
|
|
91
|
+
child.on('close', async (code) => {
|
|
92
|
+
try {
|
|
93
|
+
await fs.remove(tempDir);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
}
|
|
97
|
+
process.exit(code || 0);
|
|
98
|
+
});
|
|
99
|
+
child.on('error', async (err) => {
|
|
100
|
+
console.error('An error occurred while running Node.js:');
|
|
101
|
+
if (err.message.includes('SyntaxError')) {
|
|
102
|
+
console.error('Syntax error detected. Transformed code:');
|
|
103
|
+
finalCode.split('\n').forEach((line, index) => {
|
|
104
|
+
console.error(`${(index + 1).toString().padStart(2, ' ')}: ${line}`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
console.error(err);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await fs.remove(tempDir);
|
|
112
|
+
}
|
|
113
|
+
catch (cleanupErr) {
|
|
114
|
+
}
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (error instanceof SyntaxError) {
|
|
120
|
+
console.error('Syntax error:', error.message);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.error('An unexpected error occurred:', error);
|
|
124
|
+
}
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const showHelp = () => {
|
|
129
|
+
console.log(`
|
|
130
|
+
Fenrir Programming Language v0.0.1
|
|
131
|
+
|
|
132
|
+
Usage:
|
|
133
|
+
fenrir <file.fnr>
|
|
134
|
+
fenrir install [package]
|
|
135
|
+
fenrir remove <package>
|
|
136
|
+
fenrir archive [message]
|
|
137
|
+
fenrir archives
|
|
138
|
+
fenrir rollback [archive-id]
|
|
139
|
+
fenrir clean [number]
|
|
140
|
+
fenrir help
|
|
141
|
+
`);
|
|
142
|
+
};
|
|
143
|
+
const run = async () => {
|
|
144
|
+
if (!command || command === 'help') {
|
|
145
|
+
showHelp();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
switch (command) {
|
|
149
|
+
case 'install':
|
|
150
|
+
await packageManager.install(args[0]);
|
|
151
|
+
break;
|
|
152
|
+
case 'remove':
|
|
153
|
+
if (!args[0]) {
|
|
154
|
+
console.error('Package name not specified.');
|
|
155
|
+
console.log('Usage: fenrir remove <package-name>');
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
await packageManager.remove(args[0]);
|
|
159
|
+
break;
|
|
160
|
+
case 'archive':
|
|
161
|
+
await archiveSystem.createArchive(args[0]);
|
|
162
|
+
break;
|
|
163
|
+
case 'archives':
|
|
164
|
+
await archiveSystem.listArchives();
|
|
165
|
+
break;
|
|
166
|
+
case 'rollback':
|
|
167
|
+
await archiveSystem.rollback(args[0]);
|
|
168
|
+
break;
|
|
169
|
+
case 'clean':
|
|
170
|
+
const keepCount = args[0] ? parseInt(args[0]) : 10;
|
|
171
|
+
await archiveSystem.cleanArchives(keepCount);
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
if (command.endsWith('.fnr')) {
|
|
175
|
+
const filePath = path.resolve(process.cwd(), command);
|
|
176
|
+
await executeCode(filePath);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.error(`Unknown command: ${command}`);
|
|
180
|
+
console.log('For help: fenrir help');
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
run().catch((error) => {
|
|
186
|
+
console.error('A critical error occurred while running the program:', error);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export class PackageManager {
|
|
5
|
+
projectRoot;
|
|
6
|
+
packageJsonPath;
|
|
7
|
+
fenrirJsonPath;
|
|
8
|
+
constructor(projectRoot = process.cwd()) {
|
|
9
|
+
this.projectRoot = projectRoot;
|
|
10
|
+
this.packageJsonPath = path.join(projectRoot, 'package.json');
|
|
11
|
+
this.fenrirJsonPath = path.join(projectRoot, 'fenrir.json');
|
|
12
|
+
}
|
|
13
|
+
async install(packageName) {
|
|
14
|
+
if (!fs.existsSync(this.fenrirJsonPath)) {
|
|
15
|
+
await this.initProject();
|
|
16
|
+
}
|
|
17
|
+
if (packageName) {
|
|
18
|
+
console.log(`${packageName} loading...`);
|
|
19
|
+
try {
|
|
20
|
+
execSync(`npm install ${packageName}`, {
|
|
21
|
+
cwd: this.projectRoot,
|
|
22
|
+
stdio: 'pipe'
|
|
23
|
+
});
|
|
24
|
+
await this.updateFenrirJson(packageName);
|
|
25
|
+
console.log(`${packageName} Successfully loaded!`);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(`${packageName} An error occurred while loading:`, error);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log('All dependencies are being loaded...');
|
|
34
|
+
execSync('npm install', {
|
|
35
|
+
cwd: this.projectRoot,
|
|
36
|
+
stdio: 'inherit'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async remove(packageName) {
|
|
41
|
+
console.log(` ${packageName} being removed...`);
|
|
42
|
+
try {
|
|
43
|
+
execSync(`npm uninstall ${packageName}`, {
|
|
44
|
+
cwd: this.projectRoot,
|
|
45
|
+
stdio: 'pipe'
|
|
46
|
+
});
|
|
47
|
+
await this.removeFomFenrirJson(packageName);
|
|
48
|
+
console.log(`${packageName} removed!`);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(`${packageName} An error occurred while removing:`, error);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async initProject() {
|
|
55
|
+
const projectName = path.basename(this.projectRoot);
|
|
56
|
+
const fenrirJson = {
|
|
57
|
+
name: projectName,
|
|
58
|
+
version: "0.0.1",
|
|
59
|
+
description: "A Fenrir project",
|
|
60
|
+
dependencies: {},
|
|
61
|
+
fenrirVersion: "0.0.1"
|
|
62
|
+
};
|
|
63
|
+
await fs.writeJSON(this.fenrirJsonPath, fenrirJson, { spaces: 2 });
|
|
64
|
+
if (!fs.existsSync(this.packageJsonPath)) {
|
|
65
|
+
const packageJson = {
|
|
66
|
+
name: projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
|
|
67
|
+
version: "0.0.1",
|
|
68
|
+
type: "module",
|
|
69
|
+
dependencies: {}
|
|
70
|
+
};
|
|
71
|
+
await fs.writeJSON(this.packageJsonPath, packageJson, { spaces: 2 });
|
|
72
|
+
}
|
|
73
|
+
console.log('The Fenrir project has been launched!');
|
|
74
|
+
}
|
|
75
|
+
async readFenrirJson() {
|
|
76
|
+
if (!fs.existsSync(this.fenrirJsonPath)) {
|
|
77
|
+
return { dependencies: {} };
|
|
78
|
+
}
|
|
79
|
+
return await fs.readJSON(this.fenrirJsonPath);
|
|
80
|
+
}
|
|
81
|
+
async updateFenrirJson(packageName) {
|
|
82
|
+
const fenrirJson = await this.readFenrirJson();
|
|
83
|
+
const packageJson = await fs.readJSON(this.packageJsonPath);
|
|
84
|
+
const version = packageJson.dependencies?.[packageName] || 'latest';
|
|
85
|
+
if (!fenrirJson.dependencies) {
|
|
86
|
+
fenrirJson.dependencies = {};
|
|
87
|
+
}
|
|
88
|
+
fenrirJson.dependencies[packageName] = version;
|
|
89
|
+
await fs.writeJSON(this.fenrirJsonPath, fenrirJson, { spaces: 2 });
|
|
90
|
+
}
|
|
91
|
+
async removeFomFenrirJson(packageName) {
|
|
92
|
+
const fenrirJson = await this.readFenrirJson();
|
|
93
|
+
if (fenrirJson.dependencies && fenrirJson.dependencies[packageName]) {
|
|
94
|
+
delete fenrirJson.dependencies[packageName];
|
|
95
|
+
await fs.writeJSON(this.fenrirJsonPath, fenrirJson, { spaces: 2 });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const parse = (code) => {
|
|
2
|
+
const tokens = [];
|
|
3
|
+
const lines = code.split('\n');
|
|
4
|
+
for (const line of lines) {
|
|
5
|
+
if (line.trim().startsWith('fn')) {
|
|
6
|
+
tokens.push({ type: 'FN_DECL', value: line.trim() });
|
|
7
|
+
// DEĞİŞTİRİLDİ: Artık 'declare' kelimesini bir import beyanı olarak tanıyor
|
|
8
|
+
}
|
|
9
|
+
else if (line.trim().startsWith('declare')) {
|
|
10
|
+
tokens.push({ type: 'IMPORT_DECL', value: line.trim() });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
tokens.push({ type: 'EXPRESSION', value: line.trim() });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const ast = {
|
|
17
|
+
type: 'Program',
|
|
18
|
+
children: tokens.map(token => ({
|
|
19
|
+
type: token.type,
|
|
20
|
+
value: token.value
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
return ast;
|
|
24
|
+
};
|