Jean-Yves Didier

modified internal description of libraries

......@@ -33,7 +33,8 @@ let ARCS = {
Invocation: _invocation_js__WEBPACK_IMPORTED_MODULE_4__["default"],
Connection: _connection_js__WEBPACK_IMPORTED_MODULE_5__["default"],
Sheet: _sheet_js__WEBPACK_IMPORTED_MODULE_6__["default"],
Application: _application_js__WEBPACK_IMPORTED_MODULE_7__["default"]
Application: _application_js__WEBPACK_IMPORTED_MODULE_7__["default"],
__lib__: ()=>{}
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ARCS);
......@@ -1617,9 +1618,7 @@ let Context = function( ctx ) {
return import(/* webpackIgnore: true */libUrl).then( function(module) {
// TODO insert here component factories
for (p in module.default) {
if ( p === "__arcs__")
continue;
for (let p in module.default) {
if (module.default.hasOwnProperty(p)) {
Context.currentContext.setFactory(p,module.default[p]);
}
......
......@@ -47,3 +47,14 @@ Console = ARCS.Component.create(
export default { Console: Console};
//export default {};
ARCS.__lib__`
{
"components": {
"Console": {
"description": "Redirects console messages to a given HTML element in the page.",
"keywords": ["console", "log", "error", "warn"]
}
}
}
`
\ No newline at end of file
......
......@@ -99,24 +99,23 @@ Sum.signal("sum");
// keys are factory names, value are actual constructors modified by
// ARCS.Component.create
export default {
Loop,
DisplayInt,
Sum,
__arcs__ : {
components : {
Loop: {
keywords : ["loop", "iteration", "repeat"],
description : "Iterates for a given number of times"
},
DisplayInt : {
keywords : ["display", "integer", "number"],
description : "DisplayInt will display an integer received on its display slot."
},
Sum : {
keywords : ["sum", "add", "integer"],
description : "Sum is a component summing integers passed to its slot 'add' and the result is sent back by signal 'sum'."
}
}
export default { Loop, DisplayInt, Sum};
ARCS.__lib__`
{
"components" : {
"Loop": {
"keywords" : ["loop", "iteration", "repeat"],
"description" : "Iterates for a given number of times"
},
"DisplayInt" : {
"keywords" : ["display", "integer", "number"],
"description" : "DisplayInt will display an integer received on its display slot."
},
"Sum" : {
"keywords" : ["sum", "add", "integer"],
"description" : "Sum is a component summing integers passed to its slot 'add' and the result is sent back by signal 'sum'."
}
}
};
}
`;
\ No newline at end of file
......
......@@ -7,6 +7,10 @@
"type": "git",
"url": "https://forge.ibisc.univ-evry.fr/arcs/arcs.js.git"
},
"bin": {
"arcsrepos": "tools/arcsrepos.js",
"arcsm" : "tools/arcsm.js"
},
"main": "build/arcs.js",
"scripts": {
"build": "npx webpack --config-name core",
......
......@@ -17,7 +17,8 @@ let ARCS = {
Invocation: Invocation,
Connection: Connection,
Sheet: Sheet,
Application: Application
Application: Application,
__lib__: ()=>{}
};
export default ARCS;
......
......@@ -149,9 +149,7 @@ let Context = function( ctx ) {
return import(/* webpackIgnore: true */libUrl).then( function(module) {
// TODO insert here component factories
for (p in module.default) {
if ( p === "__arcs__")
continue;
for (let p in module.default) {
if (module.default.hasOwnProperty(p)) {
Context.currentContext.setFactory(p,module.default[p]);
}
......
import process from 'node:process';
import * as fs from 'node:fs';
const helpers ={
'-h' : function(){
console.log("usage: node arcsclient.js [-h] ");
process.exit(0);
}
}
/** list of helpers that are needed
* -h: help
* -q: keywords_list
* -i: install library
*
*
*/
\ No newline at end of file
import process from 'node:process';
import * as fs from 'node:fs';
let repositoryFile = "repos.json";
const usage = function(idx) {
console.log(
path.basename(process.argv[0]),
path.basename(process.argv[1]),
" [-f repository_file] [-h]"
);
console.log("\trepository_file is the repository json file (by default './repos.json')");
process.exit(0);
return 0;
};
const helpers = {
'-h' : usage,
'--help': usage,
'-f' : function(idx) {
repositoryFile = process.argv[idx+1];
return 1;
}
};
/** list of helpers that are needed
* -h: help
* -f: repository file
*/
for (let i=2; i<process.argv.length; i++) {
if (helpers.hasOwnProperty(process.argv[i])) {
let shift = helpers[process.argv[i]](i);
i+=shift;
}
}
const repository = JSON.parse(fs.readFileSync(repositoryFile, 'utf8'));
......
#!/usr/bin/env -S node
"use strict";
import process from 'node:process';
import * as fs from 'node:fs';
import {URL} from 'node:url';
import path from 'node:path';
let repositoryFile = null;
let env = process.env;
if (process.env.ARCS_REPOSITORY !== undefined) {
repositoryFile = process.env.ARCS_REPOSITORY;
}
const actions = [];
const usage = function(idx) {
console.log(
'Usage:',
path.basename(process.argv[0]),
path.basename(process.argv[1]),
"[-r repository_location] [-h] [-l] [-s keyword]"
);
console.log("\t-h or --help displays usage");
console.log("\t-r <repository location> sets the location of the repository json file or url");
console.log("\t-l lists available component libraries");
console.log("\t-s <keyword> searches for components with the given keyword");
process.exit(0);
return 0;
};
const getRepository = function() {
if (repositoryFile !== null) {
try {
let actualUrl = new URL(repositoryFile);
if (actualUrl.protocol === "http:" || actualUrl.protocol === "https:") {
return JSON.parse(fs.readFileSync(actualUrl, 'utf8'));
} else {
return JSON.parse(fs.readFileSync(actualUrl.path, 'utf8'));
}
} catch (e) {
return JSON.parse(fs.readFileSync(repositoryFile, 'utf8'));
}
}
return null;
};
const search = function(keyword) {
let result = [];
keyword = keyword.toLowerCase();
let components = repository.components;
if (components === undefined) { return ; }
for (let i in components) {
let component = components[i];
if (i.toLowerCase().indexOf(keyword) >= 0) {
result.push(`${i}\t${component.library}`);
}
if (component.description && component.description.toLowerCase().indexOf(keyword) >= 0) {
result.push(`${i}\t${component.library}`);
}
if (component.keywords !== undefined) {
for (let j=0; j<component.keywords.length; j++) {
let word = component.keywords[j];
if (word.toLowerCase().indexOf(keyword) >= 0) {
result.push(`${i}\t${component.library}`);
break;
}
}
}
}
result = result.filter((v, i, a) => a.indexOf(v) === i);
console.log(result.join("\n") );
};
const projectPath = function() {
let cwd = process.cwd();
// we must check, for all parent directories, if there is a node_modules directory
// if so, we are in a project
let current = cwd;
while (current !== path.dirname(current)) {
let nodeModules = path.join(current, "node_modules");
if (fs.existsSync(nodeModules)) {
return current;
}
current = path.dirname(current);
}
return null;
};
const processRecipe = function(recipe, projectPath) {
if (recipe.from === undefined || recipe.to === undefined) { return ; }
let fileContents = fs.readFileSync(path.join(projectPath, recipe.from), 'utf8');
let outContents = fileContents;
if (recipe.transform) {
fileContents = recipe.transform(fileContents);
}
let outPath = path.join(projectPath, recipe.to);
fs.mkdirSync(path.dirname(outPath), {recursive: true});
fs.writeFileSync(outPath, outContents, 'utf8');
};
const install = function(name) {
let components = repository.components;
let libraries = repository.libraries;
let library = libraries[name] || components[name]?.library;
if (library === undefined) { return ; }
let libraryPath;
// we need to compose library name depending on repositoryFile being a url or a file
try {
let actualUrl = new URL(repositoryFile);
if (actualUrl.protocol === "http:" || actualUrl.protocol === "https:") {
libraryPath = path.join(actualUrl, library);
} else {
libraryPath = path.join(path.dirname(actualUrl.path), library);
}
} catch (e) {
libraryPath = path.join(path.dirname(repositoryFile), library);
}
// we then download the library
let libraryContent = fs.readFileSync(libraryPath, 'utf8');
// we need to compute the relative path of the library to the repository
let relativePath = path.relative(path.dirname(repositoryFile), libraryPath);
// we need to compute the relative path of the library to the project
let project = projectPath();
if (project === null) {
console.error("No project found");
process.exit(1);
}
let componentPath = path.join(projectPath, 'components');
let outLibraryPath = path.join(componentPath, relativePath);
fs.mkdirSync(path.dirname(outLibraryPath), {recursive: true});
fs.writeFileSync(outLibraryPath, libraryContent, 'utf8');
// this was the first part of the installation, now we need to install the dependencies
if (library.dependencies !== undefined) {
library.dependencies.forEach((dep) => {
process.execSync(`npm install ${dep}`, {stdio: 'inherit'});
});
}
if (library.recipes !== undefined) {
library.recipes.forEach((recipe) => {
processRecipe(recipe, projectPath);
});
}
};
const listLibraries = function() {
let result = [];
let libraries = repository.libraries;
if (libraries === undefined) { return ; }
console.log(Object.keys(libraries).join("\n"));
return 0;
};
const helpers ={
'-h' : usage,
'--help': usage,
'-r' : function(idx) {
repositoryFile = process.argv[idx+1];
return 1;
},
'-s' : function(idx) {
actions.push([search, [process.argv[idx+1]]]);
return 1;
},
'-l' : function(idx) {
actions.push([listLibraries]);
return 0;
},
'-i' : function(idx) {
actions.push([install, [process.argv[idx+1]]]);
return 1;
}
}
/** list of helpers that are needed
* -h: help
* -s: keyword search
* -i: install library or component
* -l: list libraries
* -r: repository url
*
*/
for (let i=2; i<process.argv.length; i++) {
if (helpers.hasOwnProperty(process.argv[i])) {
let shift = helpers[process.argv[i]](i);
i+=shift;
}
}
let repository = getRepository();
if (repository === null) {
console.error("No repository specified");
usage();
process.exit(1);
}
if (actions.length > 0) {
actions.forEach(function(action) {
action[0].apply(null, action[1]);
});
} else {
usage();
}
#!/usr/bin/env -S node
/**
* This tool is intended to build a description of a repository of components
*/
......@@ -17,7 +19,11 @@ let outputFile = "repository.json";
let inputDir = ".";
const usage = function(idx) {
console.log(path.basename(process.argv[1])," [-o output_file] [-d component_dir] [-h]");
console.log(
path.basename(process.argv[0]),
path.basename(process.argv[1]),
" [-o output_file] [-d component_dir] [-h]"
);
console.log("\toutput_file is the generated repository json file (by default 'repos.json')");
console.log("\tcomponent_dir is the directory storing components (by default '.')");
process.exit(0);
......@@ -65,48 +71,39 @@ const files = getFiles(path.resolve(inputDir),'.js');
const libraries= {};
let components = {};
// this version, contrary to the previous one, does not use import
for(const element of files) {
const cmp = {};
try {
const exportDefault = await import(path.resolve(element));
const exportModule = exportDefault.default;
for (let c in exportModule) {
if (c === '__arcs__') {
let metaCmp = exportModule[c].components;
for(let d in metaCmp) {
if (cmp[d] === undefined) {
cmp[d] = metaCmp[d];
} else {
Object.assign(cmp[d], metaCmp[d]);
}
}
let metaLib = exportModule[c].dependencies;
if (metaLib !== undefined) {
libraries[path.relative(inputDir,element)] = metaLib;
}
} else {
if (exportModule[c] !== undefined) {
cmp[c] = { library: path.relative(inputDir,element) };
} else {
cmp[c]['library'] = path.relative(inputDir,element);
}
}
}
const cmp={};
const contents = fs.readFileSync(element, 'utf8');
const exportMatch = contents.toString().match(/__lib__\`(.*)\`/s);
if (exportMatch !== null) {
const exportDefault = JSON.parse(exportMatch[1]);
console.log(exportDefault);
let metaCmp = exportDefault.components;
for(let d in metaCmp) {
cmp[d] = metaCmp[d];
cmp[d].library = path.relative(inputDir,element);
}
let metaLib = exportDefault.dependencies;
if (metaLib !== undefined) {
libraries[path.relative(inputDir,element)] = metaLib;
}
if (libraries[element] === undefined) {
libraries[path.relative(inputDir,element)] = null;
}
} catch (e) {
console.log(`${element} is not a valid component library`);
}
for (let c in cmp) {
if (components[c] === undefined) {
components[c] = cmp[c];
} else {
components[c] = [ components[c], cmp[c] ];
}
}
};
}
}
const result = { components, libraries };
......
{ "type" : "module"}
\ No newline at end of file
{ "type": "module"}
......