From cb1cf9c5c61684d394e083e955602004ac610b07 Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Tue, 12 Dec 2017 00:02:22 +0100 Subject: [PATCH 1/6] feat(core): report the name of the Content Document where an unexpected error occurred --- packages/ace-core/src/checker/checker-chromium.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ace-core/src/checker/checker-chromium.js b/packages/ace-core/src/checker/checker-chromium.js index 56c2751b..06a3ef49 100644 --- a/packages/ace-core/src/checker/checker-chromium.js +++ b/packages/ace-core/src/checker/checker-chromium.js @@ -74,7 +74,7 @@ async function checkSingle(spineItem, epub, browser) { return results; } catch (err) { winston.debug(`Error when running HTML checks: ${err}`); - throw new Error('Failed to check HTML content'); + throw new Error(`Failed to check Content Document '${spineItem.relpath}'`); } } From 2f2f204993fccab8575965889a17c68f7ae8522d Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Tue, 12 Dec 2017 03:41:57 +0100 Subject: [PATCH 2/6] chore: allow package-specific extra build scripts If a package has a custom build scripts (`scripts/build.js`), this script will be run during the main build task. --- scripts/build-utils.js | 8 ++++++++ scripts/build.js | 14 +++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/build-utils.js b/scripts/build-utils.js index 1b5384e4..83b8cbef 100644 --- a/scripts/build-utils.js +++ b/scripts/build-utils.js @@ -5,6 +5,13 @@ const path = require('path'); const PACKAGES_DIR = path.resolve(__dirname, '../packages'); +const config = { + srcDir: 'src', + buildDir: 'lib', + jsPattern: '**/*.js', + ignorePattern: '**/*.test.js', +}; + function listPackages() { return fs .readdirSync(PACKAGES_DIR) @@ -13,6 +20,7 @@ function listPackages() { } module.exports = { + config, listPackages, PACKAGES_DIR, }; diff --git a/scripts/build.js b/scripts/build.js index a99fb7ce..f99a09e2 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -16,15 +16,10 @@ const glob = require('glob'); const micromatch = require('micromatch'); const mkdirp = require('mkdirp'); const path = require('path'); +const spawn = require('cross-spawn'); -const { listPackages, PACKAGES_DIR } = require('./build-utils'); -const config = { - srcDir: 'src', - buildDir: 'lib', - jsPattern: '**/*.js', - ignorePattern: '**/*.test.js', -}; +const { config, listPackages, PACKAGES_DIR } = require('./build-utils'); const babelConfig = JSON.parse( fs.readFileSync(path.resolve(__dirname, '..', '.babelrc'), 'utf8')); @@ -80,6 +75,11 @@ function buildPackage(pkg) { process.stdout.write(` ${path.basename(pkg)} ${chalk.dim('...')}`); files.forEach(file => buildFile(file, true)); + + const buildScript = path.resolve(pkg, 'scripts/build.js'); + if (fs.existsSync(buildScript)) { + spawn.sync('node', [buildScript], { stdio: 'inherit' }); + } process.stdout.write(`${chalk.reset.bold.green(' ✓ Done')}\n`); } From aef4349950e591c64dc22185f708903b6fdc2135 Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Tue, 12 Dec 2017 03:46:39 +0100 Subject: [PATCH 3/6] fix: Error when running HTML checks (HTML5Outline is not defined) EPUB scripts based on RequireJS were conflicting with the injected HTML5 outliner library (h5o), and caused an unexpected error. ("HTML5Outline is not defined"). This fix wraps h5o in a function that undefines any global `define` function, to prevent this conflict. Fixes #108 --- packages/ace-core/scripts/build.js | 29 +++++++++++++++++++ .../ace-core/src/checker/checker-chromium.js | 2 +- tests/__tests__/regression.test.js | 5 ++++ tests/data/issue-108/EPUB/content_001.xhtml | 10 +++++++ tests/data/issue-108/EPUB/nav.xhtml | 12 ++++++++ tests/data/issue-108/EPUB/package.opf | 24 +++++++++++++++ tests/data/issue-108/EPUB/require.js | 5 ++++ tests/data/issue-108/META-INF/container.xml | 6 ++++ tests/data/issue-108/mimetype | 1 + 9 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/ace-core/scripts/build.js create mode 100644 tests/data/issue-108/EPUB/content_001.xhtml create mode 100644 tests/data/issue-108/EPUB/nav.xhtml create mode 100644 tests/data/issue-108/EPUB/package.opf create mode 100644 tests/data/issue-108/EPUB/require.js create mode 100644 tests/data/issue-108/META-INF/container.xml create mode 100644 tests/data/issue-108/mimetype diff --git a/packages/ace-core/scripts/build.js b/packages/ace-core/scripts/build.js new file mode 100644 index 00000000..562e2195 --- /dev/null +++ b/packages/ace-core/scripts/build.js @@ -0,0 +1,29 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const mkdirp = require('mkdirp'); +const { config } = require('../../../scripts/build-utils'); + +function buildH5O() { + /** + * Wrap the browserified h5o in a function to temporarily undefine 'define' + * since Browserify and RequireJS otherwise don’t go along + * see: https://github.com/browserify/browserify/issues/790 + */ + const vendorDir = path.resolve(__dirname, '..', config.buildDir, 'scripts/vendor'); + const srcPath = path.resolve(require.resolve('h5o'), '../dist/outliner.min.js'); + const destPath = path.resolve(vendorDir, 'outliner.min.js'); + + mkdirp.sync(path.dirname(destPath)); + const ws = fs.createWriteStream(destPath); + const rs = fs.createReadStream(srcPath); + ws.write('(function () { var define = undefined;'); + rs.pipe(ws, { end: false }); + rs.on('end', () => { + ws.end('})();'); + }); +} + +buildH5O(); + diff --git a/packages/ace-core/src/checker/checker-chromium.js b/packages/ace-core/src/checker/checker-chromium.js index 06a3ef49..2cedcde7 100644 --- a/packages/ace-core/src/checker/checker-chromium.js +++ b/packages/ace-core/src/checker/checker-chromium.js @@ -11,7 +11,7 @@ const utils = require('@daisy/puppeteer-utils'); const scripts = [ path.resolve(require.resolve('axe-core'), '../axe.min.js'), - path.resolve(require.resolve('h5o'), '../dist/outliner.min.js'), + require.resolve('../scripts/vendor/outliner.min.js'), require.resolve('../scripts/axe-patch-getselector.js'), require.resolve('../scripts/axe-patch-arialookuptable.js'), require.resolve('../scripts/ace-axe.js'), diff --git a/tests/__tests__/regression.test.js b/tests/__tests__/regression.test.js index 1ce209f2..620b8204 100644 --- a/tests/__tests__/regression.test.js +++ b/tests/__tests__/regression.test.js @@ -56,3 +56,8 @@ test('issue #85: failed to detect page markers from `epub:type`', async () => { expect(report['earl:result']['earl:outcome']).toEqual('pass'); expect(report.properties.hasPageBreaks).toBe(true); }); + +test('issue #108: HTML5Outline is not defined (RequireJS conflict)', async () => { + const report = await ace('../data/issue-108'); + expect(report['earl:result']['earl:outcome']).toEqual('pass'); +}); diff --git a/tests/data/issue-108/EPUB/content_001.xhtml b/tests/data/issue-108/EPUB/content_001.xhtml new file mode 100644 index 00000000..b29307b7 --- /dev/null +++ b/tests/data/issue-108/EPUB/content_001.xhtml @@ -0,0 +1,10 @@ + + +Minimal EPUB + + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/tests/data/issue-108/EPUB/nav.xhtml b/tests/data/issue-108/EPUB/nav.xhtml new file mode 100644 index 00000000..1d538c19 --- /dev/null +++ b/tests/data/issue-108/EPUB/nav.xhtml @@ -0,0 +1,12 @@ + + +Minimal Nav + + + + + diff --git a/tests/data/issue-108/EPUB/package.opf b/tests/data/issue-108/EPUB/package.opf new file mode 100644 index 00000000..41b3c96a --- /dev/null +++ b/tests/data/issue-108/EPUB/package.opf @@ -0,0 +1,24 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-01-01T00:00:01Z + structuralNavigation + everything OK! + noFlashingHazard + noSoundHazard + noMotionSimulationHazard + textual + textual + + + + + + + + + + diff --git a/tests/data/issue-108/EPUB/require.js b/tests/data/issue-108/EPUB/require.js new file mode 100644 index 00000000..a3ca583b --- /dev/null +++ b/tests/data/issue-108/EPUB/require.js @@ -0,0 +1,5 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.3.5 Copyright jQuery Foundation and other contributors. + * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE + */ +var requirejs,require,define;!function(global,setTimeout){function commentReplace(e,t){return t||""}function isFunction(e){return"[object Function]"===ostring.call(e)}function isArray(e){return"[object Array]"===ostring.call(e)}function each(e,t){if(e){var i;for(i=0;i-1&&(!e[i]||!t(e[i],i,e));i-=1);}}function hasProp(e,t){return hasOwn.call(e,t)}function getOwn(e,t){return hasProp(e,t)&&e[t]}function eachProp(e,t){var i;for(i in e)if(hasProp(e,i)&&t(e[i],i))break}function mixin(e,t,i,r){return t&&eachProp(t,function(t,n){!i&&hasProp(e,n)||(!r||"object"!=typeof t||!t||isArray(t)||isFunction(t)||t instanceof RegExp?e[n]=t:(e[n]||(e[n]={}),mixin(e[n],t,i,r)))}),e}function bind(e,t){return function(){return t.apply(e,arguments)}}function scripts(){return document.getElementsByTagName("script")}function defaultOnError(e){throw e}function getGlobal(e){if(!e)return e;var t=global;return each(e.split("."),function(e){t=t[e]}),t}function makeError(e,t,i,r){var n=new Error(t+"\nhttp://requirejs.org/docs/errors.html#"+e);return n.requireType=e,n.requireModules=r,i&&(n.originalError=i),n}function newContext(e){function t(e){var t,i;for(t=0;t0&&(e.splice(t-1,2),t-=2)}}function i(e,i,r){var n,o,a,s,u,c,d,p,f,l,h=i&&i.split("/"),m=y.map,g=m&&m["*"];if(e&&(c=(e=e.split("/")).length-1,y.nodeIdCompat&&jsSuffixRegExp.test(e[c])&&(e[c]=e[c].replace(jsSuffixRegExp,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),t(e),e=e.join("/")),r&&m&&(h||g)){e:for(a=(o=e.split("/")).length;a>0;a-=1){if(u=o.slice(0,a).join("/"),h)for(s=h.length;s>0;s-=1)if((n=getOwn(m,h.slice(0,s).join("/")))&&(n=getOwn(n,u))){d=n,p=a;break e}!f&&g&&getOwn(g,u)&&(f=getOwn(g,u),l=a)}!d&&f&&(d=f,p=l),d&&(o.splice(0,p,d),e=o.join("/"))}return getOwn(y.pkgs,e)||e}function r(e){isBrowser&&each(scripts(),function(t){if(t.getAttribute("data-requiremodule")===e&&t.getAttribute("data-requirecontext")===q.contextName)return t.parentNode.removeChild(t),!0})}function n(e){var t=getOwn(y.paths,e);if(t&&isArray(t)&&t.length>1)return t.shift(),q.require.undef(e),q.makeRequire(null,{skipMap:!0})([e]),!0}function o(e){var t,i=e?e.indexOf("!"):-1;return i>-1&&(t=e.substring(0,i),e=e.substring(i+1,e.length)),[t,e]}function a(e,t,r,n){var a,s,u,c,d=null,p=t?t.name:null,f=e,l=!0,h="";return e||(l=!1,e="_@r"+(T+=1)),c=o(e),d=c[0],e=c[1],d&&(d=i(d,p,n),s=getOwn(j,d)),e&&(d?h=r?e:s&&s.normalize?s.normalize(e,function(e){return i(e,p,n)}):-1===e.indexOf("!")?i(e,p,n):e:(d=(c=o(h=i(e,p,n)))[0],h=c[1],r=!0,a=q.nameToUrl(h))),u=!d||s||r?"":"_unnormalized"+(A+=1),{prefix:d,name:h,parentMap:t,unnormalized:!!u,url:a,originalName:f,isDefine:l,id:(d?d+"!"+h:h)+u}}function s(e){var t=e.id,i=getOwn(S,t);return i||(i=S[t]=new q.Module(e)),i}function u(e,t,i){var r=e.id,n=getOwn(S,r);!hasProp(j,r)||n&&!n.defineEmitComplete?(n=s(e)).error&&"error"===t?i(n.error):n.on(t,i):"defined"===t&&i(j[r])}function c(e,t){var i=e.requireModules,r=!1;t?t(e):(each(i,function(t){var i=getOwn(S,t);i&&(i.error=e,i.events.error&&(r=!0,i.emit("error",e)))}),r||req.onError(e))}function d(){globalDefQueue.length&&(each(globalDefQueue,function(e){var t=e[0];"string"==typeof t&&(q.defQueueMap[t]=!0),O.push(e)}),globalDefQueue=[])}function p(e){delete S[e],delete k[e]}function f(e,t,i){var r=e.map.id;e.error?e.emit("error",e.error):(t[r]=!0,each(e.depMaps,function(r,n){var o=r.id,a=getOwn(S,o);!a||e.depMatched[n]||i[o]||(getOwn(t,o)?(e.defineDep(n,j[o]),e.check()):f(a,t,i))}),i[r]=!0)}function l(){var e,t,i=1e3*y.waitSeconds,o=i&&q.startTime+i<(new Date).getTime(),a=[],s=[],u=!1,d=!0;if(!x){if(x=!0,eachProp(k,function(e){var i=e.map,c=i.id;if(e.enabled&&(i.isDefine||s.push(e),!e.error))if(!e.inited&&o)n(c)?(t=!0,u=!0):(a.push(c),r(c));else if(!e.inited&&e.fetched&&i.isDefine&&(u=!0,!i.prefix))return d=!1}),o&&a.length)return e=makeError("timeout","Load timeout for modules: "+a,null,a),e.contextName=q.contextName,c(e);d&&each(s,function(e){f(e,{},{})}),o&&!t||!u||!isBrowser&&!isWebWorker||w||(w=setTimeout(function(){w=0,l()},50)),x=!1}}function h(e){hasProp(j,e[0])||s(a(e[0],null,!0)).init(e[1],e[2])}function m(e,t,i,r){e.detachEvent&&!isOpera?r&&e.detachEvent(r,t):e.removeEventListener(i,t,!1)}function g(e){var t=e.currentTarget||e.srcElement;return m(t,q.onScriptLoad,"load","onreadystatechange"),m(t,q.onScriptError,"error"),{node:t,id:t&&t.getAttribute("data-requiremodule")}}function v(){var e;for(d();O.length;){if(null===(e=O.shift())[0])return c(makeError("mismatch","Mismatched anonymous define() module: "+e[e.length-1]));h(e)}q.defQueueMap={}}var x,b,q,E,w,y={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},S={},k={},M={},O=[],j={},P={},R={},T=1,A=1;return E={require:function(e){return e.require?e.require:e.require=q.makeRequire(e.map)},exports:function(e){if(e.usingExports=!0,e.map.isDefine)return e.exports?j[e.map.id]=e.exports:e.exports=j[e.map.id]={}},module:function(e){return e.module?e.module:e.module={id:e.map.id,uri:e.map.url,config:function(){return getOwn(y.config,e.map.id)||{}},exports:e.exports||(e.exports={})}}},b=function(e){this.events=getOwn(M,e.id)||{},this.map=e,this.shim=getOwn(y.shim,e.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0},b.prototype={init:function(e,t,i,r){r=r||{},this.inited||(this.factory=t,i?this.on("error",i):this.events.error&&(i=bind(this,function(e){this.emit("error",e)})),this.depMaps=e&&e.slice(0),this.errback=i,this.inited=!0,this.ignore=r.ignore,r.enabled||this.enabled?this.enable():this.check())},defineDep:function(e,t){this.depMatched[e]||(this.depMatched[e]=!0,this.depCount-=1,this.depExports[e]=t)},fetch:function(){if(!this.fetched){this.fetched=!0,q.startTime=(new Date).getTime();var e=this.map;if(!this.shim)return e.prefix?this.callPlugin():this.load();q.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],bind(this,function(){return e.prefix?this.callPlugin():this.load()}))}},load:function(){var e=this.map.url;P[e]||(P[e]=!0,q.load(this.map.id,e))},check:function(){if(this.enabled&&!this.enabling){var e,t,i=this.map.id,r=this.depExports,n=this.exports,o=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,this.depCount<1&&!this.defined){if(isFunction(o)){if(this.events.error&&this.map.isDefine||req.onError!==defaultOnError)try{n=q.execCb(i,o,r,n)}catch(t){e=t}else n=q.execCb(i,o,r,n);if(this.map.isDefine&&void 0===n&&((t=this.module)?n=t.exports:this.usingExports&&(n=this.exports)),e)return e.requireMap=this.map,e.requireModules=this.map.isDefine?[this.map.id]:null,e.requireType=this.map.isDefine?"define":"require",c(this.error=e)}else n=o;if(this.exports=n,this.map.isDefine&&!this.ignore&&(j[i]=n,req.onResourceLoad)){var a=[];each(this.depMaps,function(e){a.push(e.normalizedMap||e)}),req.onResourceLoad(q,this.map,a)}p(i),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else hasProp(q.defQueueMap,i)||this.fetch()}},callPlugin:function(){var e=this.map,t=e.id,r=a(e.prefix);this.depMaps.push(r),u(r,"defined",bind(this,function(r){var n,o,d,f=getOwn(R,this.map.id),l=this.map.name,h=this.map.parentMap?this.map.parentMap.name:null,m=q.makeRequire(e.parentMap,{enableBuildCallback:!0});return this.map.unnormalized?(r.normalize&&(l=r.normalize(l,function(e){return i(e,h,!0)})||""),o=a(e.prefix+"!"+l,this.map.parentMap,!0),u(o,"defined",bind(this,function(e){this.map.normalizedMap=o,this.init([],function(){return e},null,{enabled:!0,ignore:!0})})),void((d=getOwn(S,o.id))&&(this.depMaps.push(o),this.events.error&&d.on("error",bind(this,function(e){this.emit("error",e)})),d.enable()))):f?(this.map.url=q.nameToUrl(f),void this.load()):((n=bind(this,function(e){this.init([],function(){return e},null,{enabled:!0})})).error=bind(this,function(e){this.inited=!0,this.error=e,e.requireModules=[t],eachProp(S,function(e){0===e.map.id.indexOf(t+"_unnormalized")&&p(e.map.id)}),c(e)}),n.fromText=bind(this,function(i,r){var o=e.name,u=a(o),d=useInteractive;r&&(i=r),d&&(useInteractive=!1),s(u),hasProp(y.config,t)&&(y.config[o]=y.config[t]);try{req.exec(i)}catch(e){return c(makeError("fromtexteval","fromText eval for "+t+" failed: "+e,e,[t]))}d&&(useInteractive=!0),this.depMaps.push(u),q.completeLoad(o),m([o],n)}),void r.load(e.name,m,n,y))})),q.enable(r,this),this.pluginMaps[r.id]=r},enable:function(){k[this.map.id]=this,this.enabled=!0,this.enabling=!0,each(this.depMaps,bind(this,function(e,t){var i,r,n;if("string"==typeof e){if(e=a(e,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[t]=e,n=getOwn(E,e.id))return void(this.depExports[t]=n(this));this.depCount+=1,u(e,"defined",bind(this,function(e){this.undefed||(this.defineDep(t,e),this.check())})),this.errback?u(e,"error",bind(this,this.errback)):this.events.error&&u(e,"error",bind(this,function(e){this.emit("error",e)}))}i=e.id,r=S[i],hasProp(E,i)||!r||r.enabled||q.enable(e,this)})),eachProp(this.pluginMaps,bind(this,function(e){var t=getOwn(S,e.id);t&&!t.enabled&&q.enable(e,this)})),this.enabling=!1,this.check()},on:function(e,t){var i=this.events[e];i||(i=this.events[e]=[]),i.push(t)},emit:function(e,t){each(this.events[e],function(e){e(t)}),"error"===e&&delete this.events[e]}},q={config:y,contextName:e,registry:S,defined:j,urlFetched:P,defQueue:O,defQueueMap:{},Module:b,makeModuleMap:a,nextTick:req.nextTick,onError:c,configure:function(e){if(e.baseUrl&&"/"!==e.baseUrl.charAt(e.baseUrl.length-1)&&(e.baseUrl+="/"),"string"==typeof e.urlArgs){var t=e.urlArgs;e.urlArgs=function(e,i){return(-1===i.indexOf("?")?"?":"&")+t}}var i=y.shim,r={paths:!0,bundles:!0,config:!0,map:!0};eachProp(e,function(e,t){r[t]?(y[t]||(y[t]={}),mixin(y[t],e,!0,!0)):y[t]=e}),e.bundles&&eachProp(e.bundles,function(e,t){each(e,function(e){e!==t&&(R[e]=t)})}),e.shim&&(eachProp(e.shim,function(e,t){isArray(e)&&(e={deps:e}),!e.exports&&!e.init||e.exportsFn||(e.exportsFn=q.makeShimExports(e)),i[t]=e}),y.shim=i),e.packages&&each(e.packages,function(e){var t;t=(e="string"==typeof e?{name:e}:e).name,e.location&&(y.paths[t]=e.location),y.pkgs[t]=e.name+"/"+(e.main||"main").replace(currDirRegExp,"").replace(jsSuffixRegExp,"")}),eachProp(S,function(e,t){e.inited||e.map.unnormalized||(e.map=a(t,null,!0))}),(e.deps||e.callback)&&q.require(e.deps||[],e.callback)},makeShimExports:function(e){return function(){var t;return e.init&&(t=e.init.apply(global,arguments)),t||e.exports&&getGlobal(e.exports)}},makeRequire:function(t,n){function o(i,r,u){var d,p,f;return n.enableBuildCallback&&r&&isFunction(r)&&(r.__requireJsBuild=!0),"string"==typeof i?isFunction(r)?c(makeError("requireargs","Invalid require call"),u):t&&hasProp(E,i)?E[i](S[t.id]):req.get?req.get(q,i,t,o):(p=a(i,t,!1,!0),d=p.id,hasProp(j,d)?j[d]:c(makeError("notloaded",'Module name "'+d+'" has not been loaded yet for context: '+e+(t?"":". Use require([])")))):(v(),q.nextTick(function(){v(),(f=s(a(null,t))).skipMap=n.skipMap,f.init(i,r,u,{enabled:!0}),l()}),o)}return n=n||{},mixin(o,{isBrowser:isBrowser,toUrl:function(e){var r,n=e.lastIndexOf("."),o=e.split("/")[0],a="."===o||".."===o;return-1!==n&&(!a||n>1)&&(r=e.substring(n,e.length),e=e.substring(0,n)),q.nameToUrl(i(e,t&&t.id,!0),r,!0)},defined:function(e){return hasProp(j,a(e,t,!1,!0).id)},specified:function(e){return e=a(e,t,!1,!0).id,hasProp(j,e)||hasProp(S,e)}}),t||(o.undef=function(e){d();var i=a(e,t,!0),n=getOwn(S,e);n.undefed=!0,r(e),delete j[e],delete P[i.url],delete M[e],eachReverse(O,function(t,i){t[0]===e&&O.splice(i,1)}),delete q.defQueueMap[e],n&&(n.events.defined&&(M[e]=n.events),p(e))}),o},enable:function(e){getOwn(S,e.id)&&s(e).enable()},completeLoad:function(e){var t,i,r,o=getOwn(y.shim,e)||{},a=o.exports;for(d();O.length;){if(null===(i=O.shift())[0]){if(i[0]=e,t)break;t=!0}else i[0]===e&&(t=!0);h(i)}if(q.defQueueMap={},r=getOwn(S,e),!t&&!hasProp(j,e)&&r&&!r.inited){if(!(!y.enforceDefine||a&&getGlobal(a)))return n(e)?void 0:c(makeError("nodefine","No define call for "+e,null,[e]));h([e,o.deps||[],o.exportsFn])}l()},nameToUrl:function(e,t,i){var r,n,o,a,s,u,c,d=getOwn(y.pkgs,e);if(d&&(e=d),c=getOwn(R,e))return q.nameToUrl(c,t,i);if(req.jsExtRegExp.test(e))s=e+(t||"");else{for(r=y.paths,o=(n=e.split("/")).length;o>0;o-=1)if(a=n.slice(0,o).join("/"),u=getOwn(r,a)){isArray(u)&&(u=u[0]),n.splice(0,o,u);break}s=n.join("/"),s=("/"===(s+=t||(/^data\:|^blob\:|\?/.test(s)||i?"":".js")).charAt(0)||s.match(/^[\w\+\.\-]+:/)?"":y.baseUrl)+s}return y.urlArgs&&!/^blob\:/.test(s)?s+y.urlArgs(e,s):s},load:function(e,t){req.load(q,e,t)},execCb:function(e,t,i,r){return t.apply(r,i)},onScriptLoad:function(e){if("load"===e.type||readyRegExp.test((e.currentTarget||e.srcElement).readyState)){interactiveScript=null;var t=g(e);q.completeLoad(t.id)}},onScriptError:function(e){var t=g(e);if(!n(t.id)){var i=[];return eachProp(S,function(e,r){0!==r.indexOf("_@r")&&each(e.depMaps,function(e){if(e.id===t.id)return i.push(r),!0})}),c(makeError("scripterror",'Script error for "'+t.id+(i.length?'", needed by: '+i.join(", "):'"'),e,[t.id]))}}},q.require=q.makeRequire(),q}function getInteractiveScript(){return interactiveScript&&"interactive"===interactiveScript.readyState?interactiveScript:(eachReverse(scripts(),function(e){if("interactive"===e.readyState)return interactiveScript=e}),interactiveScript)}var req,s,head,baseElement,dataMain,src,interactiveScript,currentlyAddingScript,mainScript,subPath,version="2.3.5",commentRegExp=/\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,cjsRequireRegExp=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,jsSuffixRegExp=/\.js$/,currDirRegExp=/^\.\//,op=Object.prototype,ostring=op.toString,hasOwn=op.hasOwnProperty,isBrowser=!("undefined"==typeof window||"undefined"==typeof navigator||!window.document),isWebWorker=!isBrowser&&"undefined"!=typeof importScripts,readyRegExp=isBrowser&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,defContextName="_",isOpera="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),contexts={},cfg={},globalDefQueue=[],useInteractive=!1;if(void 0===define){if(void 0!==requirejs){if(isFunction(requirejs))return;cfg=requirejs,requirejs=void 0}void 0===require||isFunction(require)||(cfg=require,require=void 0),req=requirejs=function(e,t,i,r){var n,o,a=defContextName;return isArray(e)||"string"==typeof e||(o=e,isArray(t)?(e=t,t=i,i=r):e=[]),o&&o.context&&(a=o.context),(n=getOwn(contexts,a))||(n=contexts[a]=req.s.newContext(a)),o&&n.configure(o),n.require(e,t,i)},req.config=function(e){return req(e)},req.nextTick=void 0!==setTimeout?function(e){setTimeout(e,4)}:function(e){e()},require||(require=req),req.version=version,req.jsExtRegExp=/^\/|:|\?|\.js$/,req.isBrowser=isBrowser,s=req.s={contexts:contexts,newContext:newContext},req({}),each(["toUrl","undef","defined","specified"],function(e){req[e]=function(){var t=contexts[defContextName];return t.require[e].apply(t,arguments)}}),isBrowser&&(head=s.head=document.getElementsByTagName("head")[0],(baseElement=document.getElementsByTagName("base")[0])&&(head=s.head=baseElement.parentNode)),req.onError=defaultOnError,req.createNode=function(e,t,i){var r=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");return r.type=e.scriptType||"text/javascript",r.charset="utf-8",r.async=!0,r},req.load=function(e,t,i){var r,n=e&&e.config||{};if(isBrowser)return(r=req.createNode(n,t,i)).setAttribute("data-requirecontext",e.contextName),r.setAttribute("data-requiremodule",t),!r.attachEvent||r.attachEvent.toString&&r.attachEvent.toString().indexOf("[native code")<0||isOpera?(r.addEventListener("load",e.onScriptLoad,!1),r.addEventListener("error",e.onScriptError,!1)):(useInteractive=!0,r.attachEvent("onreadystatechange",e.onScriptLoad)),r.src=i,n.onNodeCreated&&n.onNodeCreated(r,n,t,i),currentlyAddingScript=r,baseElement?head.insertBefore(r,baseElement):head.appendChild(r),currentlyAddingScript=null,r;if(isWebWorker)try{setTimeout(function(){},0),importScripts(i),e.completeLoad(t)}catch(r){e.onError(makeError("importscripts","importScripts failed for "+t+" at "+i,r,[t]))}},isBrowser&&!cfg.skipDataMain&&eachReverse(scripts(),function(e){if(head||(head=e.parentNode),dataMain=e.getAttribute("data-main"))return mainScript=dataMain,cfg.baseUrl||-1!==mainScript.indexOf("!")||(src=mainScript.split("/"),mainScript=src.pop(),subPath=src.length?src.join("/")+"/":"./",cfg.baseUrl=subPath),mainScript=mainScript.replace(jsSuffixRegExp,""),req.jsExtRegExp.test(mainScript)&&(mainScript=dataMain),cfg.deps=cfg.deps?cfg.deps.concat(mainScript):[mainScript],!0}),define=function(e,t,i){var r,n;"string"!=typeof e&&(i=t,t=e,e=null),isArray(t)||(i=t,t=null),!t&&isFunction(i)&&(t=[],i.length&&(i.toString().replace(commentRegExp,commentReplace).replace(cjsRequireRegExp,function(e,i){t.push(i)}),t=(1===i.length?["require"]:["require","exports","module"]).concat(t))),useInteractive&&(r=currentlyAddingScript||getInteractiveScript())&&(e||(e=r.getAttribute("data-requiremodule")),n=contexts[r.getAttribute("data-requirecontext")]),n?(n.defQueue.push([e,t,i]),n.defQueueMap[e]=!0):globalDefQueue.push([e,t,i])},define.amd={jQuery:!0},req.exec=function(text){return eval(text)},req(cfg)}}(this,"undefined"==typeof setTimeout?void 0:setTimeout); \ No newline at end of file diff --git a/tests/data/issue-108/META-INF/container.xml b/tests/data/issue-108/META-INF/container.xml new file mode 100644 index 00000000..2cf00654 --- /dev/null +++ b/tests/data/issue-108/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/data/issue-108/mimetype b/tests/data/issue-108/mimetype new file mode 100644 index 00000000..57ef03f2 --- /dev/null +++ b/tests/data/issue-108/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file From 93402d85b5b30f1106e0d9ab11e2feea6fde3d5d Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Tue, 12 Dec 2017 08:49:29 +0100 Subject: [PATCH 4/6] fix(aXe): description list item does not have a
parent aXe v2.x uses an equality check based on the uppercase `tagName` property, but this latter is case-sensitive in XHTML. This change patches aXe until a PR is submitted to fix dequelabs/axe-core#581 Fixes #114 --- .../ace-core/src/checker/checker-chromium.js | 1 + .../ace-core/src/scripts/axe-patch-dlitem.js | 8 +++++++ tests/__tests__/regression.test.js | 5 ++++ tests/data/issue-114/EPUB/content_001.xhtml | 19 +++++++++++++++ tests/data/issue-114/EPUB/nav.xhtml | 12 ++++++++++ tests/data/issue-114/EPUB/package.opf | 23 +++++++++++++++++++ tests/data/issue-114/META-INF/container.xml | 6 +++++ tests/data/issue-114/mimetype | 1 + 8 files changed, 75 insertions(+) create mode 100644 packages/ace-core/src/scripts/axe-patch-dlitem.js create mode 100644 tests/data/issue-114/EPUB/content_001.xhtml create mode 100644 tests/data/issue-114/EPUB/nav.xhtml create mode 100644 tests/data/issue-114/EPUB/package.opf create mode 100644 tests/data/issue-114/META-INF/container.xml create mode 100644 tests/data/issue-114/mimetype diff --git a/packages/ace-core/src/checker/checker-chromium.js b/packages/ace-core/src/checker/checker-chromium.js index 2cedcde7..68e219f2 100644 --- a/packages/ace-core/src/checker/checker-chromium.js +++ b/packages/ace-core/src/checker/checker-chromium.js @@ -14,6 +14,7 @@ const scripts = [ require.resolve('../scripts/vendor/outliner.min.js'), require.resolve('../scripts/axe-patch-getselector.js'), require.resolve('../scripts/axe-patch-arialookuptable.js'), + require.resolve('../scripts/axe-patch-dlitem.js'), require.resolve('../scripts/ace-axe.js'), require.resolve('../scripts/ace-extraction.js'), ]; diff --git a/packages/ace-core/src/scripts/axe-patch-dlitem.js b/packages/ace-core/src/scripts/axe-patch-dlitem.js new file mode 100644 index 00000000..5e875010 --- /dev/null +++ b/packages/ace-core/src/scripts/axe-patch-dlitem.js @@ -0,0 +1,8 @@ +'use strict'; + +(function axePatch(window) { + const axe = window.axe; + axe._audit.checks.dlitem.evaluate = function evaluate(node, options) { + return node.parentNode.nodeName.toUpperCase() === 'DL'; + } +}(window)); diff --git a/tests/__tests__/regression.test.js b/tests/__tests__/regression.test.js index 620b8204..110f9d1d 100644 --- a/tests/__tests__/regression.test.js +++ b/tests/__tests__/regression.test.js @@ -61,3 +61,8 @@ test('issue #108: HTML5Outline is not defined (RequireJS conflict)', async () => const report = await ace('../data/issue-108'); expect(report['earl:result']['earl:outcome']).toEqual('pass'); }); + +test('issue #114: Description list item does not have a
parent element', async () => { + const report = await ace('../data/issue-114'); + expect(report['earl:result']['earl:outcome']).toEqual('pass'); +}); diff --git a/tests/data/issue-114/EPUB/content_001.xhtml b/tests/data/issue-114/EPUB/content_001.xhtml new file mode 100644 index 00000000..8a93bdaf --- /dev/null +++ b/tests/data/issue-114/EPUB/content_001.xhtml @@ -0,0 +1,19 @@ + + +Minimal EPUB + + + +

Loomings

+

Call me Ishmael.

+
+
term
+
def
+
+ + + diff --git a/tests/data/issue-114/EPUB/nav.xhtml b/tests/data/issue-114/EPUB/nav.xhtml new file mode 100644 index 00000000..1d538c19 --- /dev/null +++ b/tests/data/issue-114/EPUB/nav.xhtml @@ -0,0 +1,12 @@ + + +Minimal Nav + + + + + diff --git a/tests/data/issue-114/EPUB/package.opf b/tests/data/issue-114/EPUB/package.opf new file mode 100644 index 00000000..17cf544e --- /dev/null +++ b/tests/data/issue-114/EPUB/package.opf @@ -0,0 +1,23 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-01-01T00:00:01Z + structuralNavigation + everything OK! + noFlashingHazard + noSoundHazard + noMotionSimulationHazard + textual + textual + + + + + + + + + diff --git a/tests/data/issue-114/META-INF/container.xml b/tests/data/issue-114/META-INF/container.xml new file mode 100644 index 00000000..2cf00654 --- /dev/null +++ b/tests/data/issue-114/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/data/issue-114/mimetype b/tests/data/issue-114/mimetype new file mode 100644 index 00000000..57ef03f2 --- /dev/null +++ b/tests/data/issue-114/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file From 8987dd8eeb9306620e97896a286e7c8e8b911026 Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Wed, 13 Dec 2017 02:30:46 +0100 Subject: [PATCH 5/6] feat(config): enable configurability with a config file Introduce a new `ace-config` package: - exposes a `paths` object storing the system paths (log, config, data, etc) - exposes the config stored in the config file in the `config` object - exposes constants in the `constants` object The config file will be stored in the user's OS-specific configuration directory Fixes #63, Fixes #77 --- packages/ace-config/package.json | 27 +++++++++ .../src/__tests__/config-store.test.js | 60 +++++++++++++++++++ .../ace-config/src/__tests__/index.test.js | 29 +++++++++ packages/ace-config/src/config-store.js | 20 +++++++ packages/ace-config/src/constants.json | 3 + packages/ace-config/src/index.js | 17 ++++++ yarn.lock | 24 +++++++- 7 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 packages/ace-config/package.json create mode 100644 packages/ace-config/src/__tests__/config-store.test.js create mode 100644 packages/ace-config/src/__tests__/index.test.js create mode 100644 packages/ace-config/src/config-store.js create mode 100644 packages/ace-config/src/constants.json create mode 100644 packages/ace-config/src/index.js diff --git a/packages/ace-config/package.json b/packages/ace-config/package.json new file mode 100644 index 00000000..25763d2e --- /dev/null +++ b/packages/ace-config/package.json @@ -0,0 +1,27 @@ +{ + "name": "@daisy/ace-config", + "version": "0.0.1", + "description": "Config utilities for Ace", + "author": { + "name": "DAISY developers", + "organization": "DAISY Consortium", + "url": "http://www.daisy.org/" + }, + "repository": { + "type": "git", + "url": "https://github.com/daisy/ace" + }, + "bugs": { + "url": "https://github.com/daisy/ace/issues" + }, + "license": "MIT", + "main": "lib/index.js", + "dependencies": { + "conf": "^1.3.1", + "env-paths": "^1.0.0", + "lodash.mergewith": "^4.6.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/ace-config/src/__tests__/config-store.test.js b/packages/ace-config/src/__tests__/config-store.test.js new file mode 100644 index 00000000..001281ab --- /dev/null +++ b/packages/ace-config/src/__tests__/config-store.test.js @@ -0,0 +1,60 @@ +'use strict'; + +const ConfigStore = require('../config-store'); +const tmp = require('tmp'); + +tmp.setGracefulCleanup(); + +let conf; +const fixture = { + a: 1, + b: [2, 2], + c: { x: 3, y: 3 }, +}; + +beforeEach(() => { + conf = new ConfigStore({ cwd: tmp.dirSync({ unsafeCleanup: true }).name }); +}); + +test('config store is defined', () => { + expect(ConfigStore).toBeDefined(); +}); + +test('.get 2-args to work as in parent', () => { + expect(conf.get('foo')).not.toBeDefined(); + expect(conf.get('foo', 'bar')).toBe('bar'); + conf.set('foo', fixture); + expect(conf.get('foo')).toEqual(fixture); +}); + +test('.get to ignore null or false merge mode', () => { + conf.set('foo', fixture); + expect(conf.get('foo', { d: 4 }, null)).toEqual(fixture); + expect(conf.get('foo', { d: 4 }, false)).toEqual(fixture); +}); + +test('.get merge mode to merge the defaults', () => { + conf.set('foo', fixture); + expect(conf.get('foo', { c: { z: 3 } }, true)).toEqual({ + a: 1, + b: [2, 2], + c: { x: 3, y: 3, z: 3 }, + }); +}); + +test('.get merge mode override the defaults', () => { + conf.set('foo', fixture); + expect(conf.get('foo', { a: 'foo' }, true)).toEqual(fixture); + expect(conf.get('foo', { c: { x: 'foo' } }, true)).toEqual(fixture); +}); + +test('.get merge mode ignores non-object defaults', () => { + conf.set('foo', fixture); + expect(conf.get('foo', 'foo', true)).toEqual(fixture); + expect(conf.get('foo', null, true)).toEqual(fixture); +}); + +test('.get merge mode concatenates arrays', () => { + conf.set('foo', fixture); + expect(conf.get('foo', { b: ['x'] }, true)).toMatchObject({ b: ['x', 2, 2] }); +}); diff --git a/packages/ace-config/src/__tests__/index.test.js b/packages/ace-config/src/__tests__/index.test.js new file mode 100644 index 00000000..c987a92e --- /dev/null +++ b/packages/ace-config/src/__tests__/index.test.js @@ -0,0 +1,29 @@ +'use strict'; + +const path = require('path'); +const { config, paths, constants } = require('..'); + +test('config store is defined', () => { + expect(config).toBeDefined(); +}); + +test('config file default name', () => { + expect(path.basename(config.path)).toEqual('config.json'); + expect(path.basename(path.dirname(config.path))).toEqual('DAISY Ace'); +}); + +test('paths are defined', () => { + expect(paths).toBeDefined(); + expect(paths.config).toBeDefined(); + expect(paths.data).toBeDefined(); + expect(paths.log).toBeDefined(); + expect(paths.temp).toBeDefined(); +}); + +test('constants are defined', () => { + expect(constants).toBeDefined(); +}); + +test('constants are as in constants.json', () => { + expect(constants.dirname).toBe('DAISY Ace'); +}); diff --git a/packages/ace-config/src/config-store.js b/packages/ace-config/src/config-store.js new file mode 100644 index 00000000..0b0850c5 --- /dev/null +++ b/packages/ace-config/src/config-store.js @@ -0,0 +1,20 @@ +'use strict'; + +const Conf = require('conf'); +const merge = require('lodash.mergewith'); + +class ConfigStore extends Conf { + + get(key, defaultValue, mergeMode) { + if (mergeMode && typeof defaultValue === 'object') { + return merge({}, defaultValue, super.get(key), (obj, val) => { + if (Array.isArray(obj)) { + return obj.concat(val); + } + }); + } + return super.get(key, defaultValue); + } +} + +module.exports = ConfigStore; diff --git a/packages/ace-config/src/constants.json b/packages/ace-config/src/constants.json new file mode 100644 index 00000000..e630e7b3 --- /dev/null +++ b/packages/ace-config/src/constants.json @@ -0,0 +1,3 @@ +{ + "dirname": "DAISY Ace" +} diff --git a/packages/ace-config/src/index.js b/packages/ace-config/src/index.js new file mode 100644 index 00000000..ffc3f85d --- /dev/null +++ b/packages/ace-config/src/index.js @@ -0,0 +1,17 @@ +'use strict'; + +const envPaths = require('env-paths'); +const constants = require('./constants'); +const ConfigStore = require('./config-store'); + +const paths = envPaths(constants.dirname, { suffix: null }); + +const config = new ConfigStore({ + cwd: paths.config, +}); + +module.exports = { + config, + constants: Object.freeze(constants), + paths, +}; diff --git a/yarn.lock b/yarn.lock index 9d1ae3e0..ab5ea3ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1215,6 +1215,16 @@ concat-stream@1.6.0, concat-stream@^1.4.10, concat-stream@^1.5.0, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" +conf@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/conf/-/conf-1.3.1.tgz#829a82b081bb355129992333be1598f797a56f58" + dependencies: + dot-prop "^4.1.0" + env-paths "^1.0.0" + make-dir "^1.0.0" + pkg-up "^2.0.0" + write-file-atomic "^2.3.0" + configstore@^1.0.0, configstore@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" @@ -1649,6 +1659,12 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + duplexer2@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" @@ -3685,7 +3701,7 @@ lodash.defaultsdeep@^4.3.1: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" -lodash.mergewith@^4.3.1: +lodash.mergewith@^4.3.1, lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" @@ -4382,6 +4398,12 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + dependencies: + find-up "^2.1.0" + pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" From 79b93aef7a6d25a610b7d36c32c11f4097ae49e0 Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Wed, 13 Dec 2017 02:31:21 +0100 Subject: [PATCH 6/6] feat(config): make the logging configurable --- packages/ace-logger/package.json | 2 +- packages/ace-logger/src/defaults.json | 6 ++++++ packages/ace-logger/src/index.js | 13 +++++++------ 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 packages/ace-logger/src/defaults.json diff --git a/packages/ace-logger/package.json b/packages/ace-logger/package.json index 0e9c3ee0..c6dd7701 100644 --- a/packages/ace-logger/package.json +++ b/packages/ace-logger/package.json @@ -17,7 +17,7 @@ "license": "MIT", "main": "lib/index.js", "dependencies": { - "env-paths": "^1.0.0", + "@daisy/ace-config": "^0.0.1", "fs-extra": "^4.0.2", "winston": "^2.4.0" }, diff --git a/packages/ace-logger/src/defaults.json b/packages/ace-logger/src/defaults.json new file mode 100644 index 00000000..b69ebc54 --- /dev/null +++ b/packages/ace-logger/src/defaults.json @@ -0,0 +1,6 @@ +{ + "logging": { + "level": "info", + "fileName": "ace.log" + } +} diff --git a/packages/ace-logger/src/index.js b/packages/ace-logger/src/index.js index 3ecdab7f..de39303a 100644 --- a/packages/ace-logger/src/index.js +++ b/packages/ace-logger/src/index.js @@ -1,20 +1,21 @@ 'use strict'; -const envPaths = require('env-paths'); +const { config, paths } = require('@daisy/ace-config'); const fs = require('fs-extra'); const path = require('path'); const winston = require('winston'); +const defaults = require('./defaults'); -const acePaths = envPaths('DAISY Ace', { suffix: null }); +const logConfig = config.get('logging', defaults.logging); module.exports.initLogger = function initLogger(options = {}) { // Check logging directoy exists - if (!fs.existsSync(acePaths.log)) { - fs.ensureDirSync(acePaths.log); + if (!fs.existsSync(paths.log)) { + fs.ensureDirSync(paths.log); } // OS-dependant path to log file - const logfile = path.join(acePaths.log, 'ace.log'); + const logfile = path.join(paths.log, logConfig.fileName); // clear old log file if (fs.existsSync(logfile)) { @@ -22,7 +23,7 @@ module.exports.initLogger = function initLogger(options = {}) { } // set up logger - const level = (options.verbose) ? 'verbose' : 'info'; + const level = (options.verbose) ? 'verbose' : logConfig.level; winston.configure({ level, transports: [