diff --git a/bin/heta-build.js b/bin/heta-build.js index dbf44554..f5fdc9ea 100644 --- a/bin/heta-build.js +++ b/bin/heta-build.js @@ -1,7 +1,7 @@ #!/usr/bin/env node const { Command } = require('commander'); const program = new Command(); -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const { Builder } = require('../src'); const YAML = require('js-yaml'); // https://www.npmjs.com/package/js-yaml @@ -115,8 +115,12 @@ async function main() { process.exit(2); // BRAKE } - let builder = new Builder(declaration, targetDir); - builder.run(); + let builder = new Builder( + declaration, + targetDir, + fs.readFileSync, + fs.outputFileSync + ).run(); return builder; } diff --git a/src/builder/index-online.js b/src/builder/index-online.js new file mode 100644 index 00000000..73a5487e --- /dev/null +++ b/src/builder/index-online.js @@ -0,0 +1,149 @@ +function build(inputDict, settings) { // modules, exports + let coreDirname = '/'; + /* + constructor() + */ + + // create container and logger + let c = new Container(); + + /* + c.logger.addTransport((level, msg, opt, levelNum) => { // temporal solution, all logs to console + console.log(`{heta-compiler} [${level}]\t${msg}`); + }); + */ + let minLogLevel = settings.options?.logLevel || 'info'; + let minLevelNum = levels.indexOf(minLogLevel); + c.logger.addTransport((level, msg, opt, levelNum) => { + let value = `\n[${level}]\t${msg}`; + if (levelNum >= minLevelNum) { + postMessage({action: 'console', value: value}); + } + }); + + // file paths + let _coreDirname = path.resolve(coreDirname); + let _distDirname = path.resolve(coreDirname, settings.options.distDir); + let _metaDirname = path.resolve(coreDirname, settings.options.metaDir); + let _logPath = path.resolve(coreDirname, settings.options.logPath); + + c.logger.info(`Heta builder of version ${hetaCompilerPackage.version} initialized in directory "${_coreDirname}"`); + if (settings.id) c.logger.info(`Platform id: "${settings.id}"`); + + /* + run() + */ + let outputDict = {}; // {: } + c.logger.info(`Compilation of module "${settings.importModule.source}" of type "${settings.importModule.type}"...`); + + // 1. Parsing + let ms = new ModuleSystem(c.logger, (filename) => { + let arrayBuffer = inputDict[filename]; // Uint8Array + if (!arrayBuffer) { + throw new HetaLevelError(`Module ${filename} is not found.`); + } + let buffer = Buffer.from(arrayBuffer); // Buffer + + return buffer; + }); + let sourceFilepath = path.resolve(_coreDirname, settings.importModule.source); + let sourceType = settings.importModule.type; + ms.addModuleDeep(sourceFilepath, sourceType, settings.importModule); + + // 2. Modules integration + if (settings.options.debug) { + Object.getOwnPropertyNames(ms.moduleCollection).forEach((name) => { + let relPath = path.relative(_coreDirname, name + '.json'); + let absPath = path.join(_metaDirname, relPath); + let str = JSON.stringify(ms.moduleCollection[name], null, 2); + outputDict[absPath] = Buffer.from(str, 'utf-8'); + c.logger.info(`Meta file was saved to ${absPath}`); + }); + } + let qArr = ms.integrate(); + + // 3. Translation + c.loadMany(qArr, false); + + // 4. Binding + c.logger.info('Setting references in elements, total length ' + c.length); + c.knitMany(); + + // 5. Circular start_ and ode_ + c.logger.info('Checking for circular references in Records.'); + c.checkCircRecord(); + + // 6. check circ UnitDef + c.checkCircUnitDef(); + + + // === STOP if errors === + if (!c.logger.hasErrors) { + + // 7. Units checking + if (settings.options.unitsCheck) { + c.logger.info('Checking unit\'s consistency.'); + c.checkUnits(); + } else { + c.logger.warn('Units checking skipped. To turn it on set "unitsCheck: true" in declaration.'); + } + + // 8. Terms checking + c.logger.info('Checking unit\'s terms.'); + c.checkTerms(); + + // 9. Exports + // save + if (settings.options.skipExport) { + c.logger.warn('Exporting skipped as stated in declaration.'); + } else if (settings.options.juliaOnly) { + c.logger.warn('"Julia only" mode'); + //this.exportJuliaOnly(); + // create export without putting it to exportStorage + let Julia = this.container.classes['Julia']; + let exportItem = new Julia({ + format: 'Julia', + filepath: '_julia' + }); + + _makeAndSave(exportItem, _distDirname, outputDict); + } else { + //this.exportMany(); + let exportElements = [...c.exportStorage].map((x) => x[1]); + c.logger.info(`Start exporting to files, total: ${exportElements.length}.`); + + exportElements.forEach((exportItem) => _makeAndSave(exportItem, _distDirname, outputDict)); + } + } else { + c.logger.warn('Units checking and export were skipped because of errors in compilation.'); + } + + // 10. save logs if required + let hetaErrors = c.hetaErrors(); + let createLog = settings.options.logMode === 'always' + || (settings.options.logMode === 'error' && hetaErrors.length > 0); + if (createLog) { + switch (settings.options.logFormat) { + case 'json': + var logs = JSON.stringify(c.defaultLogs, null, 2); + break; + default: + logs = c.defaultLogs + .filter(x => x.levelNum >= minLevelNum) + .map(x => `[${x.level}]\t${x.msg}`) + .join('\n'); + } + + //fs.outputFileSync(_logPath, logs); + outputDict[_logPath] = Buffer.from(logs, 'utf-8'); // Buffer + c.logger.info(`All logs was saved to file: "${_logPath}"`); + } + + if (!c.logger.hasErrors) { + postMessage({action: 'finished', dict: outputDict}); + } else { + postMessage({action: 'stop', dict: outputDict}); + } + + return c; +} \ No newline at end of file diff --git a/src/builder/index.js b/src/builder/index.js index fc954cb9..a50ef403 100644 --- a/src/builder/index.js +++ b/src/builder/index.js @@ -41,8 +41,8 @@ class Builder { constructor( declaration = {}, coreDirname = '.', - fileReadHandler = (fn) => fs.readFileSync(fn), // return text - fileWriteHandler = (fn, text) => fs.outputFileSync(fn, text) // return undefined + fileReadHandler = (fn) => { throw new Error('File read is not set for Builder'); }, // return text + fileWriteHandler = (fn, text) => { throw new Error('File write is not set for Builder'); } // return undefined ) { // create container this.container = new Container(); @@ -197,7 +197,8 @@ class Builder { this.fileWriteHandler(this._logPath, logs); this.logger.info(`All logs was saved to file: "${this._logPath}"`); } - return; + + return this; } /** diff --git a/test/builder/index.js b/test/builder/index.js index b2e8a674..6539b247 100644 --- a/test/builder/index.js +++ b/test/builder/index.js @@ -2,11 +2,12 @@ const { Builder } = require('../../src/builder'); const declaration = require('./test-platform'); const { expect } = require('chai'); +const fs = require('fs-extra'); describe('Test Builder.', () => { let b; it('Create Builder object and run.', () => { - b = new Builder(declaration, __dirname); + b = new Builder(declaration, __dirname, fs.readFileSync, () => {}); b.run(); }); }); diff --git a/test/cases/0.js b/test/cases/0.js index 30c9302a..0ea02506 100644 --- a/test/cases/0.js +++ b/test/cases/0.js @@ -15,7 +15,7 @@ use(chaiXml); const { load } = require('js-yaml'); const fs = require('fs-extra'); const { slvParse } = require('slv-utils'); -const XLSX = require('xlsx'); +const XLSX = require('xlsx'); const sbml_l2v4_correct = fs.readFileSync('cases/0-hello-world/master/mm_sbml_l2v4/mm.xml','utf8'); const sbml_l3v1_correct = fs.readFileSync('cases/0-hello-world/master/mm_sbml_l3v1/mm.xml','utf8'); @@ -52,7 +52,7 @@ describe('Testing "cases/0-hello-world"', () => { {format: 'Mrgsolve', spaceFilter: '^mm$'}, {format: 'Julia', spaceFilter: '^mm$'}] }; - b = new Builder(declaration, 'cases/0-hello-world'); + b = new Builder(declaration, 'cases/0-hello-world', fs.readFileSync, () => {}); }); it('Run include', () => { diff --git a/test/cases/12.js b/test/cases/12.js index b1eb6042..f844999e 100644 --- a/test/cases/12.js +++ b/test/cases/12.js @@ -3,9 +3,7 @@ const { Builder } = require('../../src/builder'); const { expect, use } = require('chai'); const chaiXml = require('chai-xml'); use(chaiXml); -//const { load } = require('js-yaml'); const fs = require('fs-extra'); -//const { slvParse } = require('slv-utils'); const sbml_correct = fs.readFileSync('cases/12-to-sbml/master/sbml/first.xml','utf8'); const json_correct = require('../../cases/12-to-sbml/master/output.json'); @@ -25,7 +23,7 @@ describe('Testing "cases/12-to-sbml"', () => { source: 'src/index.heta' } }; - b = new Builder(declaration, 'cases/12-to-sbml'); + b = new Builder(declaration, 'cases/12-to-sbml', fs.readFileSync, () => {}); //console.log(b); }); diff --git a/test/cases/14.js b/test/cases/14.js index 217049ee..2f418073 100644 --- a/test/cases/14.js +++ b/test/cases/14.js @@ -2,6 +2,7 @@ const { Builder } = require('../../src'); const { expect, use } = require('chai'); +const fs = require('fs-extra'); const json_correct = require('../../cases/14-sbml-module/master/output.json'); @@ -22,7 +23,7 @@ describe('Case #14: testing SBML module with units', () => { export: [ {format: 'JSON'} ] - }, 'cases/14-sbml-module'); + }, 'cases/14-sbml-module', fs.readFileSync, () => {}); b.run(); expect(b.container.logger).to.have.property('hasErrors').false; }); diff --git a/test/cases/6.js b/test/cases/6.js index b2b11824..91eedff2 100644 --- a/test/cases/6.js +++ b/test/cases/6.js @@ -28,7 +28,7 @@ describe('Testing "cases/6-import"', () => { {format: 'SBML', spaceFilter: 'model'}, ] }; - b = new Builder(declaration, 'cases/6-import'); + b = new Builder(declaration, 'cases/6-import', fs.readFileSync, () => {}); //console.log(b); }); diff --git a/test/cases/7.tmp.js b/test/cases/7.tmp.js index 47987bb4..ffef6a8d 100644 --- a/test/cases/7.tmp.js +++ b/test/cases/7.tmp.js @@ -24,7 +24,7 @@ describe('Testing "cases/7-importNS"', () => { source: 'src/index.heta' } }; - b = new Builder(declaration, 'cases/7-importNS'); + b = new Builder(declaration, 'cases/7-importNS', fs.readFileSync, () => {}); //console.log(b); }); diff --git a/test/module-system/index.js b/test/module-system/index.js index d0b13802..f09fd860 100644 --- a/test/module-system/index.js +++ b/test/module-system/index.js @@ -3,7 +3,6 @@ const { expect } = require('chai'); const ModuleSystem = require('../../src/module-system'); const { Logger } = require('../../src/logger'); const path = require('path'); -//const { writeFileSync } = require('fs'); const expected = require('./expected'); const noImportOutput = require('./no-include'); const fs = require('fs'); @@ -26,7 +25,6 @@ describe('Run normal ModuleSystem.', () => { let ms = new ModuleSystem(logger, (filename) => fs.readFileSync(filename)); let filepath = path.join(__dirname, './normal-a.heta'); let mdl = ms.addModuleDeep(filepath, 'heta', {}); - //writeFileSync('res0-new.json', JSON.stringify(ms, null, 2)); expect(mdl).to.be.with.a('Array').lengthOf(3); @@ -34,7 +32,6 @@ describe('Run normal ModuleSystem.', () => { expect(Object.keys(ms.graph.map)).to.have.property('length', 5); let arr = ms.integrate(); - //writeFileSync('res-new.json', JSON.stringify(arr, null, 2)); expect(arr).to.be.deep.equal(expected); }); }); diff --git a/test/module-xlsx/index.js b/test/module-xlsx/index.js index 06018b07..047ca644 100644 --- a/test/module-xlsx/index.js +++ b/test/module-xlsx/index.js @@ -3,6 +3,7 @@ const { expect } = require('chai'); const { Builder } = require('../../src/builder'); const outputNameless = require('./output-nameless'); const outputOne = require('./output-one'); +const fs = require('fs-extra'); describe('Integral test of correct xlsx module', () => { it('Create platform for single XLSX sheet.', () => { @@ -18,7 +19,7 @@ describe('Integral test of correct xlsx module', () => { omitRows: 2 } }; - let b = new Builder(declaration, __dirname); + let b = new Builder(declaration, __dirname, fs.readFileSync, () => {}); b.run(); let resultNameless = b.container.namespaceStorage.get('nameless').toQArr(true); expect(resultNameless).to.be.deep.equal(outputNameless); @@ -38,7 +39,7 @@ describe('Integral test of correct xlsx module', () => { sheet: 1 } }; - let b = new Builder(declaration, __dirname); + let b = new Builder(declaration, __dirname, fs.readFileSync, () => {}); b.run(); let resultNameless = b.container.namespaceStorage.get('nameless').toQArr(true); expect(resultNameless).to.be.deep.equal(outputNameless); @@ -56,7 +57,7 @@ describe('Integral test of correct xlsx module', () => { sheet: 9 } }; - let b = new Builder(declaration, __dirname); + let b = new Builder(declaration, __dirname, fs.readFileSync, () => {}); b.run(); expect(b.container.hetaErrors()).to.be.lengthOf(1);