Initial commit

Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com>
Co-Authored-By: Johan  <4934465+joolsus@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
Michael Cartner
2024-01-26 11:52:55 +01:00
commit b9c60b07dc
2789 changed files with 868795 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
export class EventDispatcher {
listeners: any[];
constructor() {
this.listeners = [];
}
on(event: string | string[], listener, group: unknown) {
this.listeners.push({ event: event, listener: listener, group: group });
}
notifyListeners(event: string, args?) {
const testForComps = event.split('.');
function notify(event, listener, eventName) {
const comps = event.split('.');
if (comps[0] === testForComps[0] && (comps[1] === '*' || comps[1] === testForComps[1])) listener(args, eventName);
}
for (const i in this.listeners) {
if (this.listeners[i].event instanceof Array) {
for (const j in this.listeners[i].event) notify(this.listeners[i].event[j], this.listeners[i].listener, event);
} else {
notify(this.listeners[i].event, this.listeners[i].listener, event);
}
}
}
emit(event: string, args?) {
this.notifyListeners(event, args);
}
off(group: unknown) {
if (group === undefined) return;
for (let i = 0; i < this.listeners.length; i++) {
if (this.listeners[i].group === group) {
this.listeners.splice(i, 1);
i--;
}
}
}
static instance = new EventDispatcher();
}

View File

@@ -0,0 +1,68 @@
const path = require('path');
const mkdir = require('mkdirp-sync');
const fs = require('fs');
const rimraf = require('rimraf');
const electron = require('electron');
const app = electron.app || require('@electron/remote').app;
function fileNameForKey(key) {
const keyFileName = path.basename(key, '.json') + '.json';
// Prevent ENOENT and other similar errors when using
// reserved characters in Windows filenames.
// See: https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords
const escapedFileName = encodeURIComponent(keyFileName);
const userDataPath = app.getPath('userData');
return path.join(userDataPath, escapedFileName);
}
/**
* @depracted This implementation is not cross-platform use this instead:
* ```ts
* import { JSONStorage } from '@noodl/platform';
* ```
*
* Can't remove this file because it's called from main thread,
* where the platform code is not setup.
*/
module.exports = {
get: function (key, callback) {
var filename = fileNameForKey(key);
fs.readFile(filename, { encoding: 'utf8' }, function (error, object) {
if (!error) {
var objectJSON = {};
try {
objectJSON = JSON.parse(object);
} catch (error) {
return callback(); //new Error('Invalid data'));
}
return callback(objectJSON);
}
if (error.code === 'ENOENT') {
return callback(JSON.stringify({}));
}
return callback();
});
/*storage.get(path, function(error, data) {
if (error) { callback(); return }
callback(data);
});*/
},
set: function (key, data) {
var filename = fileNameForKey(key);
const json = JSON.stringify(data);
mkdir(path.dirname(filename));
fs.writeFileSync(filename, json);
},
remove: function (key, callback) {
var filename = fileNameForKey(key);
rimraf(filename, callback);
// storage.remove(path,callback);
}
};

View File

@@ -0,0 +1,161 @@
const fs = require('fs');
class ProjectModules {
constructor() {}
scanProjectModules(projectDirectory, callback) {
if (projectDirectory === undefined) {
callback(); // No project directory, no modules
return;
}
var modulesPath = projectDirectory + '/noodl_modules';
fs.readdir(modulesPath, function (err, files) {
if (err) {
callback();
return;
}
//we only care about directories
const directories = files.filter((f) => {
var stats = fs.lstatSync(modulesPath + '/' + f);
return stats.isDirectory() || stats.isSymbolicLink();
});
if (directories.length === 0) {
callback();
} else {
// For each subfolder in noodl_modules
var modules = [];
var modulesLeft = 0;
function completeModule(path, manifest) {
if (path && manifest) {
// Module manifest is fetched, resolve local paths
var m = {
dependencies: [],
browser: manifest.browser,
runtimes: manifest.runtimes || ['browser'] //default to browser
};
if (manifest.main) {
m.index = path + '/' + manifest.main;
}
if (manifest.dependencies) {
for (var j = 0; j < manifest.dependencies.length; j++) {
var d = manifest.dependencies[j];
if (!d.startsWith['http']) d = path + '/' + d;
m.dependencies.push(d);
}
}
modules.push(m);
}
modulesLeft--;
if (modulesLeft === 0) {
//sort modules so the order is deterministics
//helps the editor understand when node libraries change, or are the same
const modulesWithIndexFile = modules.filter((m) => m.index);
const modulesWithoutIndexFile = modules.filter((m) => !m.index);
modulesWithIndexFile.sort((a, b) => a.index.localeCompare(b.index));
callback(modulesWithIndexFile.concat(modulesWithoutIndexFile));
}
}
for (var i = 0; i < directories.length; i++) {
const dir = directories[i];
modulesLeft++;
// Read manifest
fs.readFile(
modulesPath + '/' + dir + '/manifest.json',
'utf8',
(function () {
const _dir = dir;
return function (err, data) {
if (err) {
completeModule(); // Module load failed
return;
}
try {
completeModule('noodl_modules/' + _dir, JSON.parse(data));
} catch (e) {
// JSON not valid
completeModule(); // Module load failed
}
};
})()
);
}
}
});
}
injectIntoHtml(projectDirectory, template, pathPrefix, callback) {
this.scanProjectModules(projectDirectory, function (modules) {
var dependencies = '';
var modulesMain = '';
if (modules) {
const browserModules = modules.filter((m) => m.runtimes.indexOf('browser') !== -1);
for (var i = 0; i < browserModules.length; i++) {
var m = browserModules[i];
if (m.index) {
modulesMain += '<script type="text/javascript" src="' + pathPrefix + m.index + '"></script>\n';
}
// Module javascript dependencies
if (m.dependencies) {
for (var j = 0; j < m.dependencies.length; j++) {
var d = m.dependencies[j];
var dTag = '<script type="text/javascript" src="' + pathPrefix + d + '"></script>\n';
if (dependencies.indexOf(dTag) === -1) dependencies += dTag;
}
}
// Browser modules
if (m.browser) {
if (m.browser.head) {
var head = m.browser.head;
for (var j = 0; j < head.length; j++) {
dependencies += head[j] + '\n';
}
}
if (m.browser.styles) {
var styles = m.browser.styles;
for (var j = 0; j < styles.length; j++) {
dependencies += '<style>' + styles[j] + '</style>' + '\n';
}
}
if (m.browser.stylesheets) {
var sheets = m.browser.stylesheets;
for (var j = 0; j < sheets.length; j++) {
if (typeof sheets[j] === 'string') {
let path = sheets[j];
if (!path.startsWith('http')) {
path = pathPrefix + path;
}
dependencies += '<link href="' + path + '" rel="stylesheet">';
}
}
}
}
}
}
var injected = template.replace('<%modules_dependencies%>', dependencies);
injected = injected.replace('<%modules_main%>', modulesMain);
callback(injected);
});
}
}
ProjectModules.instance = new ProjectModules();
module.exports = ProjectModules;