diff --git a/.gitignore b/.gitignore
index 6848c12..89741c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
/node_modules/
/yarn.lock
/package-lock.json
-/test.js
/dist
# Mac OS X
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..3924486
--- /dev/null
+++ b/test.js
@@ -0,0 +1,500 @@
+'use strict';
+import findDeps, {findJsDeps, findHtmlDeps} from './index';
+import test from 'tape';
+import path from 'path';
+
+function buildReadFile(fakeFs = {}) {
+ return p => {
+ p = path.normalize(p).replace(/\\/g, '/');
+ if (fakeFs.hasOwnProperty(p)) return Promise.resolve(fakeFs[p]);
+ return Promise.reject('no file at ' + p);
+ };
+}
+
+let js = `
+define(['./a', 'aurelia-pal', 'exports'], function(a,b,e){
+ PLATFORM.moduleName('in1');
+ p.PLATFORM
+ .moduleName ( "/in2.js" );
+ p.PLATFORM
+ .moduleName ( "in1.js/foo.js" );
+ foo.moduleName('nope');
+ PLATFORM.bar('nope');
+ PLATFORM.moduleName(NOPE);
+ PLATFORM.moduleName('nope' + 4);
+ PLATFORM.moduleName('$\{nope}');
+ //duplicate
+ PLATFORM.moduleName('in1');
+});
+`;
+let jsDeps = ['in1', 'in1.js/foo', 'in2.js'];
+
+let html = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+let htmlDeps = ['./c.html', 'a/b', 'd/e.css', 'lv1', 'lv2', 'lvm2', 'v2', 'vm1', 'vm2'];
+
+let css = `
+@import 'other.css';
+.demo { color: blue; }
+`;
+
+
+test('findJsDeps ignores normal cjs/amd deps', t => {
+ let contents =
+ "define(['a', './b/c', 'exports', 'require', 'module'], function(a,b,e,r,m){return;})";
+
+ findJsDeps('ignore.js', contents, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.equal(result.length, 0);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps finds js deps when there is no deps', t => {
+ findJsDeps('ignore.js', 'define(() => 1);', {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.equal(result.length, 0);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps finds aurelia PLATFORM.moduleName deps', t => {
+ findJsDeps('ignore.js', js, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), jsDeps);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps throws at syntax error', t => {
+ t.throws(() => findJsDeps('ignore.js', 'define(func() {});'));
+ t.end();
+});
+
+test('findJsDeps finds plugins, but ignores plugin behind if condition', t => {
+/*
+import environment from './environment';
+import {PLATFORM} from 'aurelia-pal';
+
+export function configure(aurelia) {
+ aurelia.use
+ .feature('resources');
+ .standardConfiguration();
+ .plugin('p1')
+ .developmentLogging(environment.debug ? 'debug' : 'warn');
+ aurelia.use.plugin(PLATFORM.moduleName('pm'));
+ aurelia.use.plugin('p2', {foo: 1});
+ aurelia.use.plugin('p3', c => c.foo = 1);
+ if (environment.testing) {
+ aurelia.use.plugin('nope');
+ aurelia.use.plugin('nope1', {foo: 1});
+ aurelia.use.plugin('nope2', c => c.foo = 1);
+ }
+ aurelia.start().then(() => aurelia.setRoot());
+}
+*/
+ let file = `
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.configure = configure;
+var _environment = require('./environment');
+var _environment2 = _interopRequireDefault(_environment);
+var _aureliaPal = require('aurelia-pal');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+function configure(aurelia) {
+aurelia.use.feature('resources').standardConfiguration().plugin('p1').developmentLogging(_environment2.default.debug ? 'debug' : 'warn');
+aurelia.use.plugin(_aureliaPal.PLATFORM.moduleName('pm'));
+aurelia.use.plugin('p2', { foo: 1 });
+aurelia.use.plugin('p3', function (c) {
+ return c.foo = 1;
+});
+if (_environment2.default.testing) {
+ aurelia.use.plugin('nope');
+ aurelia.use.plugin('nope1', { foo: 1 });
+ aurelia.use.plugin('nope2', function (c) {
+ return c.foo = 1;
+ });
+}
+aurelia.start().then(function () {
+ return aurelia.setRoot();
+});
+}
+`;
+ findJsDeps('main.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), [
+ 'aurelia-event-aggregator',
+ 'aurelia-history-browser',
+ 'aurelia-logging-console',
+ 'aurelia-templating-binding',
+ 'aurelia-templating-resources',
+ 'aurelia-templating-router',
+ 'p1',
+ 'p2',
+ 'p3',
+ 'pm',
+ 'resources'
+ ]);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps finds plugins and global resources in configure, but ignores plugin behind if condition', t => {
+/*
+import {BcxService} from './bcx-service';
+import environment from '../environment';
+
+export function configure(config) {
+ config.globalResources([
+ PLATFORM.moduleName('./elements/x-y'),
+ './binding-behaviors/z'
+ ]);
+
+ config.globalResources('./elements/a');
+
+ config.plugin(PLATFORM.moduleName('ab'));
+
+ config.plugin('p1');
+ config.plugin('p2', {foo: 1})
+ .plugin('p3', c => c.foo = 1);
+
+ if (environment.testing) {
+ config.plugin('nope');
+ config.plugin('nope1', {foo: 1})
+ .plugin('nope2', c => c.foo = 1);
+ }
+}
+*/
+ let file = `
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.configure = configure;
+var _bcxService = require('./bcx-service');
+var _environment = require('../environment');
+var _environment2 = _interopRequireDefault(_environment);
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+function configure(config) {
+config.globalResources([PLATFORM.moduleName('./elements/x-y'), './binding-behaviors/z']);
+config.globalResources('./elements/a');
+config.plugin(PLATFORM.moduleName('ab'));
+config.plugin('p1');
+config.plugin('p2', { foo: 1 }).plugin('p3', function (c) {
+ return c.foo = 1;
+});
+if (_environment2.default.testing) {
+ config.plugin('nope');
+ config.plugin('nope1', { foo: 1 }).plugin('nope2', function (c) {
+ return c.foo = 1;
+ });
+}
+}
+`;
+
+ findJsDeps('index.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), [
+ './binding-behaviors/z',
+ './elements/a',
+ './elements/x-y',
+ 'ab', 'p1', 'p2', 'p3'
+ ]);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find deps on noView', t => {
+/*
+import {noView} from 'aurelia-framework';
+@noView(['a.css', './b.css'])
+export class MyComp {}
+*/
+ let file = `
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.MyComp = undefined;
+var _dec, _class;
+var _aureliaFramework = require('aurelia-framework');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var MyComp = exports.MyComp = (_dec = (0, _aureliaFramework.noView)(['a.css', './b.css']), _dec(_class = function MyComp() {
+_classCallCheck(this, MyComp);
+}) || _class);
+`;
+ findJsDeps('my-comp.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./b.css', 'a.css']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find deps on useView', t => {
+/*
+import {useView} from 'aurelia-framework';
+@useView('./a.html')
+export class MyComp {}
+*/
+
+ let file = `
+'use strict';
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.MyComp = undefined;
+var _dec, _class;
+var _aureliaFramework = require('aurelia-framework');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var MyComp = exports.MyComp = (_dec = (0, _aureliaFramework.useView)('./a.html'), _dec(_class = function MyComp() {
+_classCallCheck(this, MyComp);
+}) || _class);
+`;
+
+ findJsDeps('my-comp.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./a.html']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find deps in inlineView html', t => {
+/*
+import {inlineView} from 'aurelia-framework';
+@inlineView('')
+export class MyComp {}
+*/
+ let file = `
+'use strict';
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.MyComp = undefined;
+var _dec, _class;
+var _aureliaFramework = require('aurelia-framework');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var MyComp = exports.MyComp = (_dec = (0, _aureliaFramework.inlineView)(''), _dec(_class = function MyComp() {
+_classCallCheck(this, MyComp);
+}) || _class);
+`;
+
+ findJsDeps('my-comp.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./a.css']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find deps in inlineView html for TypeScript compiled code', t => {
+/*
+import {inlineView} from 'aurelia-framework';
+@inlineView('')
+export class MyComp {}
+*/
+ let file = `
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
+switch (arguments.length) {
+ case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
+ case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
+ case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
+}
+};
+var aurelia_framework_1 = require('aurelia-framework');
+var MyComp = (function () {
+function MyComp() {
+}
+MyComp = __decorate([
+ aurelia_framework_1.inlineView('')
+], MyComp);
+return MyComp;
+})();
+exports.MyComp = MyComp;
+`;
+
+ findJsDeps('my-comp.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./a.css']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find deps in inlineView html, and additional deps', t => {
+/*
+import {inlineView} from 'aurelia-framework';
+import {PLATFORM} from 'aurelia-pal';
+@inlineView('', ['./b.css', PLATFORM.moduleName('./c.css')])
+export class MyComp {}
+*/
+ let file = `
+'use strict';
+Object.defineProperty(exports, "__esModule", {
+value: true
+});
+exports.MyComp = undefined;
+var _dec, _class;
+var _aureliaFramework = require('aurelia-framework');
+var _aureliaPal = require('aurelia-pal');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var MyComp = exports.MyComp = (_dec = (0, _aureliaFramework.inlineView)('', ['./b.css', _aureliaPal.PLATFORM.moduleName('./c.css')]), _dec(_class = function MyComp() {
+_classCallCheck(this, MyComp);
+}) || _class);
+`;
+
+ findJsDeps('my-comp.js', file, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./a.css', './b.css', './c.css']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findJsDeps find html file by aurelia view convention', t => {
+ findJsDeps('src/foo.js', 'a();', {readFile: buildReadFile({
+ 'src/foo.html': 'contents'
+ })})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./foo.html']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+
+test('findHtmlDeps finds all require deps', t => {
+ t.deepEqual(findHtmlDeps('ignore.html', html).sort(), htmlDeps);
+ t.end();
+});
+
+test('findHtmlDeps silents at syntax error', t => {
+ t.equal(findHtmlDeps('ignore.html', '').length, 0);
+ t.end();
+});
+
+test('findDeps find html file by aurelia view convention', t => {
+ findDeps('src/foo.js', 'a();', {readFile: buildReadFile({
+ 'src/foo.html': 'contents'
+ })})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), ['./foo.html']);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findDeps finds js deps', t => {
+ findDeps('ignore.js', js, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), jsDeps);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findDeps finds js deps', t => {
+ findDeps('IGNORE.js', js, {readFile: buildReadFile({})})
+ .then(
+ result => {
+ t.deepEqual(result.sort(), jsDeps);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findDeps finds html deps', t => {
+ Promise.resolve(findDeps('ignore.html', html, {readFile: buildReadFile({})}))
+ .then(
+ result => {
+ t.deepEqual(result.sort(), htmlDeps);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});
+
+test('findDeps passes other files', t => {
+ Promise.resolve(findDeps('ignore.css', css, {readFile: buildReadFile({})}))
+ .then(
+ result => {
+ t.equal(result.length, 0);
+ },
+ err => {
+ t.fail(err.message);
+ }
+ ).then(t.end);
+});