Jean-Yves Didier

functional ES modules

......@@ -4,6 +4,14 @@ module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
dist: {
files:[
{src: 'src/arcs_browser.js', dest: 'build/arcs_browser.js'}
]
}
},
jsdoc: {
dist: {
src: ['src/*.js', 'docs/Readme.md'], //, 'components/*.js'],
......@@ -43,29 +51,13 @@ module.exports = function (grunt) {
}
}
},
file_minify: {
build: {
files: {
'build/arcs.min.js': [
'build/arcs.js'
],
'build/arcs_browser.js': [
'src/arcs_browser.js'
],
'build/arcseditor.min.js': [
'build/arcseditor.js'
]
}
}
},
terser: {
build: {
files: {
'build/arcs.min.js': [
'build/arcs.js'
],
'build/arcs_browser.js': [
'build/arcs_browser.min.js': [
'src/arcs_browser.js'
],
'build/arcseditor.min.js': [
......@@ -101,7 +93,6 @@ module.exports = function (grunt) {
'src/transitionnetwork.js',
'src/statemachine.js',
'src/application.js',
'src/arcs_module.js',
'src/exports.js'
],
dest: 'build/arcs.js'
......@@ -124,16 +115,15 @@ module.exports = function (grunt) {
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-obfuscator');
grunt.loadNpmTasks('grunt-file-minify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-jsdoc');
grunt.loadNpmTasks('grunt-jslint');
grunt.loadNpmTasks('grunt-terser');
grunt.loadNpmTasks('grunt-bower-task');
// Default task(s).
grunt.registerTask('default', ['concat','terser'/*'file_minify','obfuscator'*/]);
grunt.registerTask('default', ['concat','copy','terser']);
grunt.registerTask('lint', ['jslint']);
grunt.registerTask('doc', ['jsdoc']);
};
......
......@@ -247,6 +247,7 @@ ARCS.Context = function( ctx ) {
if (ctx !== undefined) {
libraries = ctx.libraries;
var p;
for (p in ctx.components) {
if (ctx.components.hasOwnProperty(p)) {
components[p] = ctx.components[p];
......@@ -263,8 +264,7 @@ ARCS.Context = function( ctx ) {
}
//! TODO use fetch API?
loadDataFile =async function(fileName) {
var loadDataFile =async function(fileName) {
var dataPromise ;
if (ARCS.isInNode()) {
......@@ -281,19 +281,8 @@ ARCS.Context = function( ctx ) {
return client.json();
}
};
//! TODO not needed anymore?
/*this.addLibraryPromise = function(p) {
depLibPromises.push(p);
};*/
/*promiseLibrary = function(libName) {
return import(libName);
};*/
//! TODO modify loadLibraries and loadLibrary to directly register
// factories so that arcs_module is not needed anymore ?
loadLibraries = function () {
var loadLibraries = function () {
var i;
// we will use different instances of require either the one of node
// or the one from require.js
......@@ -301,16 +290,13 @@ ARCS.Context = function( ctx ) {
var res=[];
for(i=0; i < libraries.length; i++) {
//! TODO
res.push(loadLibrary(libraries[i]));
//import(libraries[i]));
res.push(self.loadLibrary(libraries[i]));
}
return Promise.all(res);
};
instanciateComponents = function() {
var instanciateComponents = function() {
var p, promises=[];
console.log(components);
for (p in components) {
if (components.hasOwnProperty(p)) {
......@@ -319,7 +305,7 @@ ARCS.Context = function( ctx ) {
console.error("[ARCS] Context dump follows: ", libraries, components, constants);
return ;
}
factory = factories[components[p].type];
var factory = factories[components[p].type];
//console.log("instanciating ", p);
try {
if (components[p].value !== undefined || components[p].url !== undefined || components[p].ref !== undefined) {
......@@ -368,21 +354,23 @@ ARCS.Context = function( ctx ) {
libActualName = libName.name;
libUrl = libName.url;
}
libraries.push(libActualName);
if (libraries.indexOf(libActualName) < 0) {
libraries.push(libActualName);
}
// TODO promisify call to cbFunction
return import(libUrl).then( function(module) {
// TODO insert here component factories
for (p in module) {
if (module.hasOwnProperty(p)) {
ARCS.Context.currentContext.setFactory(p,module[p]);
for (p in module.default) {
if (module.default.hasOwnProperty(p)) {
ARCS.Context.currentContext.setFactory(p,module.default[p]);
}
}
if (cbFunction !== undefined) {
cbFunction();
}
});
}).catch( function(msg) { console.error("[ARCS] Trouble loading '",libUrl,"' with reason -", msg) });
};
/**
......@@ -501,7 +489,7 @@ ARCS.Context = function( ctx ) {
this.instanciate = function () {
//! TODO
return loadLibraries().then(instanciateComponents)
.catch(function(msg) { console.log("[ARCS] Trouble instanciating context", msg); });
.catch(function(msg) { console.error("[ARCS] Trouble instanciating context", msg); });
};
......@@ -2049,7 +2037,7 @@ ARCS.Application = function () {
* Starts the application
*/
this.start = function () {
console.log("[ARCS] Starting application");
console.log("[ARCS] Starting application...");
context.instanciate().then(preProcess);
};
};
......@@ -2065,103 +2053,6 @@ ARCS.Application.slot("setSheet");
ARCS.Application.slot("finish");
/**
* definition of the main module function:
* it takes an anonymous function as a parameter
* the anonymous function has one parameter: the object encompassing
* ARCS definitions (in order to able to use ARCS.Component.create, ...)
* @param moduleDefinition {function} main function of the module.
* It should return a list of components
* @param deps {mixed[]} dependencies
*/
// TODO arcs_module seems to be not needed anymore!!!!
// more cunning, this time, we export an arcs_module function
// that we call later!
// still we need to do something about it in order to register
// components.
// in fact factories should be registered in load library.
// reimplementation using native promises
arcs_module = function(moduleDefinition, deps) {
var storeComponents, i;
if (typeof module !== 'undefined') {
if (module.parent.exports) {
ARCS = module.exports;
}
}
if (deps === undefined) { deps = []; }
storeComponents = function (deps) {
var mdef, p;
// we should insert ARCS at the beginning of deps !
deps.unshift(ARCS);
mdef = (typeof moduleDefinition === 'function') ?
moduleDefinition.apply(this, deps) : moduleDefinition;
if (mdef === undefined) {
throw new Error("[ARCS] Your module is undefined. Did you forget to export components?\nCode of module follows:\n" +moduleDefinition);
}
for (p in mdef) {
if (mdef.hasOwnProperty(p) && ARCS.Context.currentContext != null) {
ARCS.Context.currentContext.setFactory(p,mdef[p]); //.setFactory(ARCS.Application.currentApplication, p, mdef[p]);
}
}
return Promise.resolve();
};
// until now, it is the very same code.
// here we create a promise to solve dependency
// reject has the dependency name, while resolve has the object
var depResolve = function(dep) {
return new Promise(function(resolve, reject) {
var d,shimConfig;
if (ARCS.isInNode()) {
d = require(dep);
if (d === undefined) {
reject(dep);
} else {
resolve(d);
}
} else {
// this one a little bit trickier since we have to shim.
if (dep.name !== undefined) {
shimConfig = { shim: {} };
shimConfig.shim[dep.name] = { exports: dep.exports };
if (dep.deps !== undefined) {
shimConfig.shim[dep.name].deps = dep.deps;
}
require.config(shimConfig);
dep = dep.name;
}
// shim performed
require([dep],
function(d) { resolve(d); },
function(err) { console.log("[ARCS] Trouble with module ", dep); reject(dep, err); }
);
}
});
};
var depResolves = [];
for (i=0; i<deps.length; i++) {
depResolves[i] = depResolve(deps[i]);
}
ARCS.Context.currentContext.addLibraryPromise(
Promise.all(depResolves).then(storeComponents,
function(reason) { console.error("[ARCS] Failed to load dependency ", reason ); })
);
}
// no longer needed with the use of imports
export default ARCS;
\ No newline at end of file
export { ARCS as default};
\ No newline at end of file
......
This diff is collapsed. Click to expand it.
/* ugly hack in order to display data in web page instead of console */
import ARCS from '../build/arcs.js';
var Console;
/**
* @class Console
* @classdesc Redirects console messages to a given HTML element in the page.
* @param id {string} id of the HTML element in which console messages will be added.
*/
Console = ARCS.Component.create(
function (id) {
if (id === undefined) {
return ;
}
var output = document.getElementById(id);
if (output) {
window.console = {
timeRef: new Date().getTime(),
output : output,
display: function(color,args) {
var s = document.createElement("span");
s.style.color=color;
var elapsed = (new Date().getTime() - this.timeRef);
arcs_module(
function(ARCS) {
var Console;
/**
* @class Console
* @classdesc Redirects console messages to a given HTML element in the page.
* @param id {string} id of the HTML element in which console messages will be added.
*/
Console = ARCS.Component.create(
function (id) {
if (id === undefined) {
return ;
s.innerHTML = '<span class="marker">' + (elapsed/1000).toFixed(3) + '</span>' + Array.prototype.join.call(args, ' ');
output.appendChild(s);
output.appendChild(document.createElement("br"));
},
log: function () {
this.display('green',arguments);
},
error: function () {
this.display('red',arguments);
},
warn: function () {
this.display('orange',arguments);
}
var output = document.getElementById(id);
if (output) {
window.console = {
timeRef: new Date().getTime(),
output : output,
display: function(color,args) {
var s = document.createElement("span");
s.style.color=color;
var elapsed = (new Date().getTime() - this.timeRef);
s.innerHTML = '<span class="marker">' + (elapsed/1000).toFixed(3) + '</span>' + Array.prototype.join.call(args, ' ');
output.appendChild(s);
output.appendChild(document.createElement("br"));
},
log: function () {
this.display('green',arguments);
},
error: function () {
this.display('red',arguments);
},
warn: function () {
this.display('orange',arguments);
}
};
}
}
);
return { Console: Console};
};
}
}
);
);
\ No newline at end of file
export default { Console: Console};
......
......@@ -5,111 +5,99 @@
* @file
*/
// TODO first strategy: import ARCS and export components
// TODO second strategy: make an anonymous function to export
// in any case, arcs_module disappears
import ARCS from '../build/arcs.js';
//! TODO to comment or uncomment (maybe)
// imports ARCS from '../build/arcs.js';
function (ARCS) {
var Loop, DisplayInt, Sum;
/** @exports loop */
//console.log("loop: ", ARCS);
/**
* @class Loop
* @classdesc loop component creation using a compact style.
* This component iterates for a given number of times
*/
var Loop = ARCS.Component.create(
function () {
/**
* @class Loop
* @classdesc loop component creation using a compact style.
* This component iterates for a given number of times
*/
Loop = ARCS.Component.create(
function () {
/**
* Sets the number of times the component should iterate.
* It starts the iterations. At each iteration, a signal newIteration is
* emitted, then, at the end of the iterations, a signal sendToken is
* eventually triggered.
* @param n {numeric} number of iterations
* @function Loop#setIterations
* @slot
* @emits newIteration
* @emits sendToken
*/
this.setIterations = function (n) {
var i;
for (i = 0; i < n; i++) {
console.log("Loop : emitting ", i);
this.emit("newIteration", i);
}
this.emit("endLoop");
};
/** @function Loop#newIteration
* @signal
* @param n {number} current iteration number.
*/
/** @function Loop#sendToken
* @signal
* @param s {string} token to emit.
*/
},
"setIterations", //slotList
["endLoop", "newIteration"] // signalList
);
* Sets the number of times the component should iterate.
* It starts the iterations. At each iteration, a signal newIteration is
* emitted, then, at the end of the iterations, a signal sendToken is
* eventually triggered.
* @param n {numeric} number of iterations
* @function Loop#setIterations
* @slot
* @emits newIteration
* @emits sendToken
*/
this.setIterations = function (n) {
var i;
for (i = 0; i < n; i++) {
console.log("Loop : emitting ", i);
this.emit("newIteration", i);
}
this.emit("endLoop");
};
/** @function Loop#newIteration
* @signal
* @param n {number} current iteration number.
*/
/** @function Loop#sendToken
* @signal
* @param s {string} token to emit.
*/
},
"setIterations", //slotList
["endLoop", "newIteration"] // signalList
);
/**
* @class DisplayInt
* @classdesc displayInt component creation using a variation with defined slots
* in the constructor (a slot is a function). DisplayInt will display an integer
* received on its display slot.
*/
DisplayInt = function () {
/**
* @param n {numeric} number to display
* @function DisplayInt#display
* @slot
*/
this.display = function (n) {
console.log(" DisplayInt : " + n);
};
/**
* @class DisplayInt
* @classdesc displayInt component creation using a variation with defined slots
* in the constructor (a slot is a function). DisplayInt will display an integer
* received on its display slot.
*/
var DisplayInt = function () {
/**
* @param n {numeric} number to display
* @function DisplayInt#display
* @slot
*/
this.display = function (n) {
console.log(" DisplayInt : " + n);
};
};
ARCS.Component.create(DisplayInt);
DisplayInt.slot("display");
ARCS.Component.create(DisplayInt);
DisplayInt.slot("display");
/**
* @class Sum
* @classdec Sum is a component summing integers passed to its slot "add"
* and the result is sent back by signal "sum".
* This component is declared in two different phases: declaration of the
* constructor and declaration of the slot "add".
*/
Sum = function () {
this.total = 0;
};
/**
* @class Sum
* @classdec Sum is a component summing integers passed to its slot "add"
* and the result is sent back by signal "sum".
* This component is declared in two different phases: declaration of the
* constructor and declaration of the slot "add".
*/
var Sum = function () {
this.total = 0;
};
ARCS.Component.create(Sum);
/**
* This slot adds its parameter to its internal sum and send it back by using
* the signal "sum".
* @param n {integer} add n to the internal sum of the component.
* @function Sum#add
* @slot
*/
Sum.slot("add", function (n) {
this.total = this.total + n;
this.emit("sum", this.total); //console.log(" Total : " + this.total);
});
Sum.signal("sum");
ARCS.Component.create(Sum);
/**
* This slot adds its parameter to its internal sum and send it back by using
* the signal "sum".
* @param n {integer} add n to the internal sum of the component.
* @function Sum#add
* @slot
*/
Sum.slot("add", function (n) {
this.total = this.total + n;
this.emit("sum", this.total); //console.log(" Total : " + this.total);
});
Sum.signal("sum");
// the anonymous function must return the components in one object:
// keys are factory names, value are actual constructors modified by
// ARCS.Component.create
// the anonymous function must return the components in one object:
// keys are factory names, value are actual constructors modified by
// ARCS.Component.create
return {Loop: Loop, DisplayInt: DisplayInt, Sum: Sum};
//! TODO comment or uncomment (maybe)
}
export default {Loop: Loop, DisplayInt: DisplayInt, Sum: Sum};
......
......@@ -16,11 +16,10 @@
"bower": ">=1.3.9",
"grunt": ">=0.4.5",
"grunt-jslint": ">=1.1.12",
"grunt-contrib-obfuscator": "*",
"grunt-terser": "*",
"grunt-file-minify": ">=1.0.0",
"grunt-jsdoc": ">=0.5.6",
"grunt-bower-task": ">=0.4.0",
"grunt-contrib-concat": ">=0.5.0"
"grunt-contrib-concat": ">=0.5.0",
"grunt-contrib-copy": ">=1.0.0"
}
}
......
......@@ -199,7 +199,7 @@ ARCS.Application = function () {
* Starts the application
*/
this.start = function () {
console.log("[ARCS] Starting application");
console.log("[ARCS] Starting application...");
context.instanciate().then(preProcess);
};
};
......
......@@ -3,31 +3,31 @@
* It relies on require.js to get the job done.
* @file
*/
"use strict";
// basically, here we start by importing the module ARCS
import ARCS from './arcs.js';
console.log("Bootstrapping ARCS...");
console.log("[ARCS] Bootstrapping...");
var baseUrl, appDescription, requireMarkup, xhr;
requireMarkup = document.querySelector('[data-main]');
requireMarkup = document.querySelector('[data-arcsapp]');
if (requireMarkup !== undefined) {
baseUrl = requireMarkup.dataset.baseUrl ;
appDescription = requireMarkup.dataset.arcsapp || "arcsapp.json";
}
(async function toto() {
var description = await(fetch(appDescription));
var applicationObject = await(description.json());
console.log("ARCS application description loaded");
console.log("[ARCS] Application description loaded");
if (baseUrl) {
require.config( { baseUrl: baseUrl });
}
var aap = new ARCS.Application();
aap.import(applicationObject);
console.log("Starting application...");
aap.start();
})();
\ No newline at end of file
......
/**
* definition of the main module function:
* it takes an anonymous function as a parameter
* the anonymous function has one parameter: the object encompassing
* ARCS definitions (in order to able to use ARCS.Component.create, ...)
* @param moduleDefinition {function} main function of the module.
* It should return a list of components
* @param deps {mixed[]} dependencies
*/
// TODO arcs_module seems to be not needed anymore!!!!
// more cunning, this time, we export an arcs_module function
// that we call later!
// still we need to do something about it in order to register
// components.
// in fact factories should be registered in load library.
// reimplementation using native promises
arcs_module = function(moduleDefinition, deps) {
var storeComponents, i;
if (typeof module !== 'undefined') {
if (module.parent.exports) {
ARCS = module.exports;
}
}
if (deps === undefined) { deps = []; }
storeComponents = function (deps) {
var mdef, p;
// we should insert ARCS at the beginning of deps !
deps.unshift(ARCS);
mdef = (typeof moduleDefinition === 'function') ?
moduleDefinition.apply(this, deps) : moduleDefinition;
if (mdef === undefined) {
throw new Error("[ARCS] Your module is undefined. Did you forget to export components?\nCode of module follows:\n" +moduleDefinition);
}
for (p in mdef) {
if (mdef.hasOwnProperty(p) && ARCS.Context.currentContext != null) {
ARCS.Context.currentContext.setFactory(p,mdef[p]); //.setFactory(ARCS.Application.currentApplication, p, mdef[p]);
}
}
return Promise.resolve();
};
// until now, it is the very same code.
// here we create a promise to solve dependency
// reject has the dependency name, while resolve has the object
var depResolve = function(dep) {
return new Promise(function(resolve, reject) {
var d,shimConfig;
if (ARCS.isInNode()) {
d = require(dep);
if (d === undefined) {
reject(dep);
} else {
resolve(d);
}
} else {
// this one a little bit trickier since we have to shim.
if (dep.name !== undefined) {
shimConfig = { shim: {} };
shimConfig.shim[dep.name] = { exports: dep.exports };
if (dep.deps !== undefined) {
shimConfig.shim[dep.name].deps = dep.deps;
}
require.config(shimConfig);
dep = dep.name;
}
// shim performed
require([dep],
function(d) { resolve(d); },
function(err) { console.log("[ARCS] Trouble with module ", dep); reject(dep, err); }
);
}
});
};
var depResolves = [];
for (i=0; i<deps.length; i++) {
depResolves[i] = depResolve(deps[i]);
}
ARCS.Context.currentContext.addLibraryPromise(
Promise.all(depResolves).then(storeComponents,
function(reason) { console.error("[ARCS] Failed to load dependency ", reason ); })
);
}
\ No newline at end of file
......@@ -23,6 +23,7 @@ ARCS.Context = function( ctx ) {
if (ctx !== undefined) {
libraries = ctx.libraries;
var p;
for (p in ctx.components) {
if (ctx.components.hasOwnProperty(p)) {
components[p] = ctx.components[p];
......@@ -39,8 +40,7 @@ ARCS.Context = function( ctx ) {
}
//! TODO use fetch API?
loadDataFile =async function(fileName) {
var loadDataFile =async function(fileName) {
var dataPromise ;
if (ARCS.isInNode()) {
......@@ -57,19 +57,8 @@ ARCS.Context = function( ctx ) {
return client.json();
}
};
//! TODO not needed anymore?
/*this.addLibraryPromise = function(p) {
depLibPromises.push(p);
};*/
/*promiseLibrary = function(libName) {
return import(libName);
};*/
//! TODO modify loadLibraries and loadLibrary to directly register
// factories so that arcs_module is not needed anymore ?
loadLibraries = function () {
var loadLibraries = function () {
var i;
// we will use different instances of require either the one of node
// or the one from require.js
......@@ -77,16 +66,13 @@ ARCS.Context = function( ctx ) {
var res=[];
for(i=0; i < libraries.length; i++) {
//! TODO
res.push(loadLibrary(libraries[i]));
//import(libraries[i]));
res.push(self.loadLibrary(libraries[i]));
}
return Promise.all(res);
};
instanciateComponents = function() {
var instanciateComponents = function() {
var p, promises=[];
console.log(components);
for (p in components) {
if (components.hasOwnProperty(p)) {
......@@ -95,7 +81,7 @@ ARCS.Context = function( ctx ) {
console.error("[ARCS] Context dump follows: ", libraries, components, constants);
return ;
}
factory = factories[components[p].type];
var factory = factories[components[p].type];
//console.log("instanciating ", p);
try {
if (components[p].value !== undefined || components[p].url !== undefined || components[p].ref !== undefined) {
......@@ -144,21 +130,23 @@ ARCS.Context = function( ctx ) {
libActualName = libName.name;
libUrl = libName.url;
}
libraries.push(libActualName);
if (libraries.indexOf(libActualName) < 0) {
libraries.push(libActualName);
}
// TODO promisify call to cbFunction
return import(libUrl).then( function(module) {
// TODO insert here component factories
for (p in module) {
if (module.hasOwnProperty(p)) {
ARCS.Context.currentContext.setFactory(p,module[p]);
for (p in module.default) {
if (module.default.hasOwnProperty(p)) {
ARCS.Context.currentContext.setFactory(p,module.default[p]);
}
}
if (cbFunction !== undefined) {
cbFunction();
}
});
}).catch( function(msg) { console.error("[ARCS] Trouble loading '",libUrl,"' with reason -", msg) });
};
/**
......@@ -277,7 +265,7 @@ ARCS.Context = function( ctx ) {
this.instanciate = function () {
//! TODO
return loadLibraries().then(instanciateComponents)
.catch(function(msg) { console.log("[ARCS] Trouble instanciating context", msg); });
.catch(function(msg) { console.error("[ARCS] Trouble instanciating context", msg); });
};
......
// no longer needed with the use of imports
export default ARCS;
\ No newline at end of file
export { ARCS as default};
\ No newline at end of file
......
{
"context" : {
"libraries" : [ "components/loop","components/console"],
"libraries" : [ "../components/loop.js","../components/console.js"],
"components" : {
"loop": { "type": "Loop" },
"dint": { "type": "DisplayInt" },
......
......@@ -4,7 +4,7 @@
<script data-base-url="../.."
data-arcsapp="arcsapp.json"
type="module"
src="../../build/arcs_browser">
src="../../build/arcs_browser.js">
</script>
</head>
<body>
......