diff --git a/.editorconfig b/.editorconfig index 1033e2d..aa6a9d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,10 +5,17 @@ root = true # Unix-style newlines with a newline ending every file [*] +indent_style = space +indent_size = 2 end_of_line = lf -insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false + +[*.md] +trim_trailing_whitespace = false # 2 space indentation [**.*] indent_style = space -indent_size = 2 \ No newline at end of file +indent_size = 2 diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 107c619..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./node_modules/aurelia-tools/.eslintrc.json", - "rules": { - "no-cond-assign": 0, - "no-extend-native": 0 - } -} diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md similarity index 100% rename from ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9209488 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,6 @@ +Make sure you check the following: +* [ ] unless trivial, a corresponding issue exists for this PR (reference it) +* [ ] if this PR fixes the issue, then include `fix #` and the issue number +* [ ] if this PR adds a feature, then you've included tests in `spec/` +* [ ] you've ran `gulp test` and it passes the lint and spec +* [ ] you've prepended the PR description i.e. (chore):, (feat):, (fix): \ No newline at end of file diff --git a/.gitignore b/.gitignore index 76489e1..cda2b80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules jspm_packages -bower_components .idea .DS_STORE build/reports +dist/ +spec/*.js +spec/*.map diff --git a/.npmignore b/.npmignore index cafe9b6..6065693 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,14 @@ -jspm_packages -bower_components -.idea \ No newline at end of file +.vscode +.idea +*.map +doc/ +spec/ +.editorconfig +circle.yml +CONTRIBUTING.md +gulpfile.js +ISSUE_TEMPLATE.md +tsconfig.json +tsfmt.json +tslint.json + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..34c5b74 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Tests", + "type": "node", + "request": "launch", + "program": "${workspaceRoot}/node_modules/gulp/bin/gulp.js", + "stopOnEntry": false, + "args": [ + "dev:debug" + ], + "cwd": "${workspaceRoot}", + "preLaunchTask": "dev:pre-debug", + "internalConsoleOptions": "openOnSessionStart", + "runtimeExecutable": null, + "runtimeArgs": [ + "--nolazy" + ], + "env": { + "NODE_ENV": "development" + }, + "externalConsole": false, + "sourceMaps": true, + "outDir": "${workspaceRoot}/dist" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d8f30f9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "**/*.map":true, + "**/*.js": { + "when": "$(basename).ts" + } + } +} \ No newline at end of file diff --git a/bower.json b/bower.json deleted file mode 100644 index c913ee5..0000000 --- a/bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "aurelia-pal-nodejs", - "version": "0.1.0", - "description": "The Node.js-specific implementation of Aurelia's platform abstraction layer.", - "keywords": [ - "aurelia", - "pal", - "nodejs" - ], - "homepage": "http://aurelia.io", - "main": "dist/commonjs/aurelia-pal-nodejs.js", - "moduleType": "node", - "license": "MIT", - "authors": [ - "Rob Eisenberg (http://robeisenberg.com/)" - ], - "repository": { - "type": "git", - "url": "http://github.com/aurelia/pal-nodejs" - }, - "dependencies": { - "aurelia-pal": "^1.0.0", - "jsdom": "^9.2.1" - } -} diff --git a/build/babel-options.js b/build/babel-options.js deleted file mode 100644 index decca42..0000000 --- a/build/babel-options.js +++ /dev/null @@ -1,74 +0,0 @@ -var path = require('path'); -var paths = require('./paths'); - -exports.base = function(isTest) { - var config = { - filename: '', - filenameRelative: '', - sourceMap: true, - sourceRoot: '', - moduleRoot: path.resolve('src').replace(/\\/g, '/'), - moduleIds: false, - comments: false, - compact: false, - code: true, - presets: [ 'es2015-loose', 'stage-1' ], - plugins: [ - 'syntax-flow', - 'transform-decorators-legacy', - ] - }; - if (!paths.useTypeScriptForDTS && !isTest) { - config.plugins.push( - ['babel-dts-generator', { - packageName: paths.packageName, - typings: '', - suppressModulePath: true, - suppressComments: false, - memberOutputFilter: /^_.*/, - suppressAmbientDeclaration: true - }] - ); - }; - config.plugins.push('transform-flow-strip-types'); - return config; -} - -exports.commonjs = function() { - var options = exports.base(); - options.plugins.push('transform-es2015-modules-commonjs'); - return options; -}; - -exports.amd = function() { - var options = exports.base(); - options.plugins.push('transform-es2015-modules-amd'); - return options; -}; - -exports.system = function() { - var options = exports.base(); - options.plugins.push('transform-es2015-modules-systemjs'); - return options; -}; - -exports.es2015 = function() { - var options = exports.base(); - options.presets = ['stage-1'] - return options; -}; - -exports['native-modules'] = function() { - var options = exports.base(); - options.presets[0] = 'es2015-loose-native-modules'; - return options; -} - -exports.test = function() { - var baseOptions = exports.base(true); - var options = { - presets: baseOptions.presets, - plugins: baseOptions.plugins - }; - return options; -} diff --git a/build/paths.js b/build/paths.js index 7c5a3de..eea945a 100644 --- a/build/paths.js +++ b/build/paths.js @@ -1,46 +1,13 @@ var path = require('path'); var fs = require('fs'); -// hide warning // -var emitter = require('events'); -emitter.defaultMaxListeners = 20; - var appRoot = 'src/'; var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); -var paths = { - root: appRoot, - source: appRoot + '**/*.js', - html: appRoot + '**/*.html', - style: 'styles/**/*.css', +module.exports = { + source: "src/", output: 'dist/', - doc:'./doc', - e2eSpecsSrc: 'test/e2e/src/*.js', - e2eSpecsDist: 'test/e2e/dist/', + doc:'doc/', packageName: pkg.name, - specsSrc: 'test/**/*.spec.js', - ignore: [], - useTypeScriptForDTS: false, - importsToAdd: [], - sort: false + spec: 'spec/', }; - -paths.files = [ -'disposable.js', -'dom.js', -'feature.js', -'global.js', -'index.js', -'nodejs-dom.js', -'nodejs-feature.js', -'nodejs-mutation-emulator.js', -'nodejs-mutation-observer.js', -'nodejs-platform.js', -'observer.js', -'performance.js', -'platform.js' -].map(function(file){ - return paths.root + file; -}); - -module.exports = paths; diff --git a/build/tasks/build.js b/build/tasks/build.js index b37ba4d..f4442e2 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -1,130 +1,63 @@ var gulp = require('gulp'); -var runSequence = require('run-sequence'); -var to5 = require('gulp-babel'); -var paths = require('../paths'); -var compilerOptions = require('../babel-options'); -var compilerTsOptions = require('../typescript-options'); -var assign = Object.assign || require('object.assign'); -var through2 = require('through2'); -var concat = require('gulp-concat'); -var insert = require('gulp-insert'); -var rename = require('gulp-rename'); -var tools = require('aurelia-tools'); var ts = require('gulp-typescript'); -var gutil = require('gulp-util'); -var gulpIgnore = require('gulp-ignore'); +var jasmine = require('gulp-jasmine'); +var plumber = require('gulp-plumber'); +var sourcemap = require('gulp-sourcemaps'); +var replace = require('gulp-replace'); +var path = require('path'); var merge = require('merge2'); -var jsName = paths.packageName + '.js'; -var compileToModules = ['es2015', 'commonjs', 'amd', 'system', 'native-modules']; - -function cleanGeneratedCode() { - return through2.obj(function(file, enc, callback) { - file.contents = new Buffer(tools.cleanGeneratedCode(file.contents.toString('utf8'))); - this.push(file); - return callback(); - }); -} - -gulp.task('build-index', function() { - var importsToAdd = paths.importsToAdd.slice(); - - var src = gulp.src(paths.files); - - if (paths.sort) { - src = src.pipe(tools.sortFiles()); - } +var sequence = require('run-sequence'); - if (paths.ignore) { - paths.ignore.forEach(function(filename){ - src = src.pipe(gulpIgnore.exclude(filename)); - }); - } +var paths = require('../paths'); - return src.pipe(through2.obj(function(file, enc, callback) { - file.contents = new Buffer(tools.extractImports(file.contents.toString('utf8'), importsToAdd)); - this.push(file); - return callback(); - })) - .pipe(concat(jsName)) - .pipe(insert.transform(function(contents) { - return tools.createImportBlock(importsToAdd) + contents; - })) - .pipe(gulp.dest(paths.output)); +gulp.task('build', function (done) { + sequence('build:source', 'build:spec', done); }); -function gulpFileFromString(filename, string) { - var src = require('stream').Readable({ objectMode: true }); - src._read = function() { - this.push(new gutil.File({ cwd: paths.appRoot, base: paths.output, path: filename, contents: new Buffer(string) })) - this.push(null) - } - return src; -} - -function srcForBabel() { - return merge( - gulp.src(paths.output + jsName), - gulpFileFromString(paths.output + 'index.js', "export * from './" + paths.packageName + "';") - ); -} - -function srcForTypeScript() { - return gulp - .src(paths.output + paths.packageName + '.js') - .pipe(rename(function (path) { - if (path.extname == '.js') { - path.extname = '.ts'; - } - })); -} - -compileToModules.forEach(function(moduleType){ - gulp.task('build-babel-' + moduleType, function () { - return srcForBabel() - .pipe(to5(assign({}, compilerOptions[moduleType]()))) - .pipe(cleanGeneratedCode()) - .pipe(gulp.dest(paths.output + moduleType)); - }); - - if (moduleType === 'native-modules') return; // typescript doesn't support the combination of: es5 + native modules - - gulp.task('build-ts-' + moduleType, function () { - var tsProject = ts.createProject( - compilerTsOptions({ module: moduleType, target: moduleType == 'es2015' ? 'es2015' : 'es5' }), ts.reporter.defaultReporter()); - var tsResult = srcForTypeScript().pipe(ts(tsProject)); - return tsResult.js - .pipe(gulp.dest(paths.output + moduleType)); +gulp.task('build:source', function () { + var tsProject = ts.createProject('tsconfig.json', { + typescript: require('typescript') }); -}); -gulp.task('build-dts', function() { - var tsProject = ts.createProject( - compilerTsOptions({ removeComments: false, target: "es2015", module: "es2015" }), ts.reporter.defaultReporter()); - var tsResult = srcForTypeScript().pipe(ts(tsProject)); - return tsResult.dts - .pipe(gulp.dest(paths.output)); + var tsResult = + gulp.src([paths.source + '**/*.ts', "node_modules/@types/**/index.d.ts", "!node_modules/@types/**/node_modules/**/*.d.ts"]) + .pipe(sourcemap.init()) + .pipe(tsProject()); + + return merge([ + tsResult.dts.pipe(gulp.dest(paths.output)), + tsResult.js + //hack fix for https://github.com/ivogabe/gulp-typescript/issues/395 + .pipe(sourcemap.write('.', { + sourceRoot: function (file) { + var relative = path.relative(file.path, path.normalize(path.join(__dirname, "..", "..", paths.source))); + var relativeSource = path.join(relative, paths.source) + return relativeSource; + } + })) + .pipe(gulp.dest(paths.output)) + ]); }); -gulp.task('build', function(callback) { - return runSequence( - 'clean', - 'build-index', - compileToModules - .map(function(moduleType) { return 'build-babel-' + moduleType }) - .concat(paths.useTypeScriptForDTS ? ['build-dts'] : []), - callback - ); -}); +gulp.task('build:spec', function () { + var tsProject = ts.createProject('tsconfig.json', { + typescript: require('typescript') + }); -gulp.task('build-ts', function(callback) { - return runSequence( - 'clean', - 'build-index', - 'build-babel-native-modules', - compileToModules - .filter(function(moduleType) { return moduleType !== 'native-modules' }) - .map(function(moduleType) { return 'build-ts-' + moduleType }) - .concat(paths.useTypeScriptForDTS ? ['build-dts'] : []), - callback - ); + var tsResult = + gulp.src([paths.spec + '**/*spec.ts', "node_modules/@types/**/index.d.ts", "!node_modules/@types/**/node_modules/**/index.d.ts"]) + .pipe(sourcemap.init()) + .pipe(tsProject()); + + return tsResult.js + //hack fix for https://github.com/ivogabe/gulp-typescript/issues/395 + .pipe(sourcemap.write('.', { + sourceRoot: function (file) { + var relative = path.relative(file.path, path.normalize(path.join(__dirname, "..", "..", paths.spec))); + var relativeSource = path.join(relative, paths.spec) + return relativeSource; + } + })) + .pipe(replace(/(require\('\..\/src\/)/g, 'require(\'..\/dist\/')) + .pipe(gulp.dest(paths.spec)); }); diff --git a/build/tasks/clean.js b/build/tasks/clean.js index 800cb0b..5247e84 100644 --- a/build/tasks/clean.js +++ b/build/tasks/clean.js @@ -1,9 +1,18 @@ var gulp = require('gulp'); var paths = require('../paths'); -var del = require('del'); -var vinylPaths = require('vinyl-paths'); +var rimraf = require('gulp-rimraf'); +var sequence = require('run-sequence'); -gulp.task('clean', function() { +gulp.task('clean', function(done) { + sequence('clean:dist', 'clean:spec', done); +}); + +gulp.task('clean:dist', function() { return gulp.src([paths.output]) - .pipe(vinylPaths(del)); + .pipe(rimraf()); }); + +gulp.task('clean:spec', function() { + return gulp.src([paths.spec + "**/*.js", paths.spec + "**/*.map"]) + .pipe(rimraf()); +}); \ No newline at end of file diff --git a/build/tasks/dev.js b/build/tasks/dev.js index 2d8c619..4fc1f48 100644 --- a/build/tasks/dev.js +++ b/build/tasks/dev.js @@ -1,5 +1,6 @@ var gulp = require('gulp'); var tools = require('aurelia-tools'); +var sequence = require('run-sequence'); gulp.task('update-own-deps', function(){ tools.updateOwnDependenciesFromLocalRepositories(); @@ -8,3 +9,11 @@ gulp.task('update-own-deps', function(){ gulp.task('build-dev-env', function () { tools.buildDevEnv(); }); + +gulp.task('dev:pre-debug', ["clean"], function (done) { + sequence('build', done); +}); + +gulp.task('dev:debug', function (done) { + sequence('test', done); +}); diff --git a/build/tasks/doc.js b/build/tasks/doc.js index 1bb4f36..ec25d7f 100644 --- a/build/tasks/doc.js +++ b/build/tasks/doc.js @@ -4,8 +4,8 @@ var typedoc = require('gulp-typedoc'); var runSequence = require('run-sequence'); var through2 = require('through2'); -gulp.task('doc-generate', function(){ - return gulp.src([paths.output + paths.packageName + '.d.ts']) +gulp.task('doc:generate', function(){ + return gulp.src([paths.output + 'index.d.ts']) .pipe(typedoc({ target: 'es6', includeDeclarations: true, @@ -19,7 +19,7 @@ gulp.task('doc-generate', function(){ })); }); -gulp.task('doc-shape', function(){ +gulp.task('doc:shape', function(){ return gulp.src([paths.doc + '/api.json']) .pipe(through2.obj(function(file, enc, callback) { var json = JSON.parse(file.contents.toString('utf8')).children[0]; @@ -39,8 +39,8 @@ gulp.task('doc-shape', function(){ gulp.task('doc', function(callback){ return runSequence( - 'doc-generate', - 'doc-shape', + 'doc:generate', + 'doc:shape', callback ); }); diff --git a/build/tasks/format.js b/build/tasks/format.js new file mode 100644 index 0000000..809f29e --- /dev/null +++ b/build/tasks/format.js @@ -0,0 +1,25 @@ +var gulp = require('gulp'); +var typescriptFormatter = require('gulp-typescript-formatter'); + +var paths = require('../paths'); + +function format(sourcePattern, targetDir) { + return gulp.src(sourcePattern) + .pipe(typescriptFormatter({ + baseDir: '.', + tslint: true, // use tslint.json file ? + editorconfig: true, // use .editorconfig file ? + tsfmt: true, // use tsfmt.json ? + })) + .pipe(gulp.dest(targetDir)); +} + +gulp.task('format:sources', function () { + return format(paths.source + '**/*.ts', paths.source); +}); + +gulp.task('format:specs', function () { + return format(paths.spec + '**/*.ts', paths.spec); +}); + +gulp.task('format', ['format:sources', 'format:specs'], function () { }); diff --git a/build/tasks/lint.js b/build/tasks/lint.js index b690fa4..f957957 100644 --- a/build/tasks/lint.js +++ b/build/tasks/lint.js @@ -1,10 +1,11 @@ var gulp = require('gulp'); var paths = require('../paths'); -var eslint = require('gulp-eslint'); +var tslint = require('gulp-tslint'); -gulp.task('lint', function() { - return gulp.src(paths.source) - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(eslint.failOnError()); +gulp.task('lint', function () { + return gulp.src([paths.source + '**/*.ts', paths.spec + '**/*.ts']) + .pipe(tslint({ + formatter: "verbose" + })) + .pipe(tslint.report()); }); diff --git a/build/tasks/prepare-release.js b/build/tasks/prepare-release.js index b374e6b..1e436c0 100644 --- a/build/tasks/prepare-release.js +++ b/build/tasks/prepare-release.js @@ -23,6 +23,7 @@ gulp.task('bump-version', function(){ gulp.task('prepare-release', function(callback){ return runSequence( + 'format', 'build', 'lint', 'bump-version', diff --git a/build/tasks/test.js b/build/tasks/test.js index 640e0de..fda5b6d 100644 --- a/build/tasks/test.js +++ b/build/tasks/test.js @@ -1,4 +1,3 @@ -require("babel-register")(require('../babel-options').test()); var gulp = require('gulp'); var jasmine = require('gulp-jasmine'); var paths = require('../paths'); @@ -7,8 +6,9 @@ var paths = require('../paths'); * Run test once and exit */ gulp.task('test', () => { - gulp.src([paths.source, paths.specsSrc]) + return gulp.src([paths.spec + "**/*.js" ]) .pipe(jasmine({ + verbose: true, includeStackTrace: true })); }); diff --git a/build/typescript-options.js b/build/typescript-options.js deleted file mode 100644 index 8a22abe..0000000 --- a/build/typescript-options.js +++ /dev/null @@ -1,9 +0,0 @@ -var tsconfig = require('../tsconfig.json'); -var assign = Object.assign || require('object.assign'); - -module.exports = function(override) { - return assign(tsconfig.compilerOptions, { - "target": override && override.target || "es5", - "typescript": require('typescript') - }, override || {}); -} diff --git a/doc/api.json b/doc/api.json index 8d63055..62c02dc 100644 --- a/doc/api.json +++ b/doc/api.json @@ -1 +1 @@ -{"name":"aurelia-pal-nodejs","children":[{"id":2,"name":"initialize","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":3,"name":"initialize","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Initializes the PAL with nodejs."},"type":{"type":"instrinct","name":"void"}}]}],"groups":[{"title":"Functions","kind":64,"children":[2]}]} \ No newline at end of file +{"name":"aurelia-pal-nodejs","children":[{"id":2,"name":"initialize","kind":64,"kindString":"Function","flags":{"isExported":true},"signatures":[{"id":3,"name":"initialize","kind":4096,"kindString":"Call signature","flags":{},"comment":{"shortText":"Initializes the PAL with the Browser-targeted implementation."},"type":{"type":"instrinct","name":"void"}}],"sources":[{"fileName":"index.d.ts","line":4,"character":34}]}],"groups":[{"title":"Functions","kind":64,"children":[2]}]} \ No newline at end of file diff --git a/package.json b/package.json index 03123df..69d1420 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aurelia-pal-nodejs", - "version": "0.1.0", + "version": "1.0.0-alpha.1", "description": "The Node.js-specific implementation of Aurelia's platform abstraction layer.", "keywords": [ "aurelia", @@ -13,8 +13,11 @@ }, "license": "MIT", "author": "Rob Eisenberg (http://robeisenberg.com/)", - "main": "dist/commonjs/aurelia-pal-nodejs.js", - "typings": "dist/aurelia-pal-nodejs.d.ts", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "scripts": { + "test":"gulp build && gulp test && gulp clean:spec" + }, "repository": { "type": "git", "url": "http://github.com/aurelia/pal-nodejs" @@ -24,21 +27,8 @@ "jsdom": "^9.2.1" }, "devDependencies": { + "@types/jsdom": "^2.0.29", "aurelia-tools": "^0.2.4", - "babel-dts-generator": "^0.6.1", - "babel-eslint": "^6.1.2", - "babel-plugin-syntax-flow": "^6.8.0", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-es2015-modules-amd": "^6.8.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.11.5", - "babel-plugin-transform-es2015-modules-systemjs": "^6.11.6", - "babel-plugin-transform-flow-strip-types": "^6.8.0", - "babel-preset-es2015": "^6.9.0", - "babel-preset-es2015-loose": "^7.0.0", - "babel-preset-es2015-loose-native-modules": "^1.0.0", - "babel-preset-stage-1": "^6.5.0", - "babel-register": "^6.11.6", - "del": "^2.2.1", "gulp": "^3.9.1", "gulp-babel": "^6.1.2", "gulp-bump": "^2.2.0", @@ -47,12 +37,15 @@ "gulp-eslint": "^3.0.1", "gulp-ignore": "^2.0.1", "gulp-insert": "^0.5.0", - "gulp-jasmine": "^2.4.0", + "gulp-jasmine": "^2.3.0", "gulp-plumber": "^1.1.0", "gulp-rename": "^1.2.2", + "gulp-replace": "^0.5.4", + "gulp-sourcemaps": "^1.6.0", "gulp-typedoc": "^2.0.0", "gulp-typedoc-extractor": "^0.0.8", - "gulp-typescript": "^2.13.6", + "gulp-typescript": "^3.0.1", + "gulp-typescript-formatter": "^0.1.3", "gulp-util": "^3.0.7", "jasmine-core": "^2.4.1", "merge2": "^1.0.2", @@ -60,8 +53,10 @@ "require-dir": "^0.3.0", "run-sequence": "^1.2.2", "through2": "^2.0.1", + "tslint": "^3.15.1", "typedoc": "^0.4.4", - "typescript": "^1.9.0-dev.20160622-1.0", + "typescript": "^2.0.0", + "typescript-formatter": "^3.0.1", "vinyl": "^1.1.1", "vinyl-paths": "^2.1.0", "yargs": "^4.8.1" diff --git a/test/nodejs-dom.spec.js b/spec/nodejs-dom.spec.ts similarity index 93% rename from test/nodejs-dom.spec.js rename to spec/nodejs-dom.spec.ts index b996cf8..ee5b62f 100644 --- a/test/nodejs-dom.spec.js +++ b/spec/nodejs-dom.spec.ts @@ -1,6 +1,6 @@ -import {initialize} from '../src/index' -import {DOM} from 'aurelia-pal'; -import {jsdom} from 'jsdom'; +import { initialize } from '../src/index'; +import { DOM } from 'aurelia-pal'; +import { jsdom } from 'jsdom'; initialize(); @@ -27,10 +27,8 @@ describe('NodeJs Dom', () => { expect(elmt.tagName).toBe("DIV"); }); - it('createTextNode is defined', () => { expect(DOM.createTextNode).toBeDefined(); - }); it('createTextNode creates valid text node', () => { @@ -81,7 +79,7 @@ describe('NodeJs Dom', () => { let event = DOM.createCustomEvent("Foo", { bubbles: true, cancelable: false, detail: {} }); - elmt.addEventListener("Foo", () => { wasCalled = true }, true); + elmt.addEventListener("Foo", () => { wasCalled = true; }, true); elmt.dispatchEvent(event); expect(wasCalled).toBeTruthy(); @@ -94,4 +92,4 @@ describe('NodeJs Dom', () => { it('dispatchEvent is defined', () => { expect(DOM.dispatchEvent).toBeDefined(); }); -}); \ No newline at end of file +}); diff --git a/spec/nodejs-mutation-source.spec.ts b/spec/nodejs-mutation-source.spec.ts new file mode 100644 index 0000000..11633c0 --- /dev/null +++ b/spec/nodejs-mutation-source.spec.ts @@ -0,0 +1,132 @@ +import { NodeJsMutationEmulator } from '../src/nodejs-mutation-emulator'; +import { IObserver } from '../src/observer'; +import { jsdom } from 'jsdom'; + +describe("Mutation Source", function () { + describe("Attributes", function () { + it("doesn't raise mutation if attribute not changed", function () { + var source = new NodeJsMutationEmulator(0); + var dom = jsdom(undefined); + + let observer = { + }; + + var target = dom.createElement("div"); + + target.setAttribute("foo", "moo"); + + var callback = (records: MutationRecord[]) => { + wasCalled = true; + }; + + source.registerObserver({ + target: target, + callback: callback + }); + + var wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + }); + + it("does raise mutation after attribute is changed", function () { + var source = new NodeJsMutationEmulator(0); + var dom = jsdom(undefined); + let observer = {}; + + var target = dom.createElement("div"); + + target.setAttribute("foo", "moo"); + + var wasCalled; + + var callback = (records: MutationRecord[]) => { + wasCalled = true; + }; + + source.registerObserver({ + target: target, + callback: callback + }); + + wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + + wasCalled = false; + target.setAttribute("foo", "boo"); + source.cycle(); + expect(wasCalled).toBe(true); + + wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + + wasCalled = false; + target.setAttribute("foo", "choo"); + source.cycle(); + expect(wasCalled).toBe(true); + + }); + }); + + describe("Node Value", function () { + it("doesn't raise mutation if nodeValue not changed", function () { + var source = new NodeJsMutationEmulator(0); + var dom = jsdom(undefined); + let observer = {}; + + var target = dom.createTextNode("foo"); + + var callback = (records: MutationRecord[]) => { + wasCalled = true; + }; + + source.registerObserver({ + target: target, + callback: callback + }); + + var wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + }); + + it("does raise mutation after nodeValue is changed", function () { + var source = new NodeJsMutationEmulator(0); + var dom = jsdom(undefined); + let observer = {}; + + var target = dom.createTextNode("foo"); + + var wasCalled; + var callback = (records: MutationRecord[]) => { + wasCalled = true; + }; + + source.registerObserver({ + target: target, + callback: callback + }); + + wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + + wasCalled = false; + target.nodeValue = "boo"; + source.cycle(); + expect(wasCalled).toBe(true); + + wasCalled = false; + source.cycle(); + expect(wasCalled).toBe(false); + + wasCalled = false; + target.nodeValue = "choo"; + source.cycle(); + expect(wasCalled).toBe(true); + + }); + }); +}); diff --git a/spec/nodejs-platform.spec.ts b/spec/nodejs-platform.spec.ts new file mode 100644 index 0000000..aba9288 --- /dev/null +++ b/spec/nodejs-platform.spec.ts @@ -0,0 +1,37 @@ +import { initialize } from '../src/index'; +import { PLATFORM } from 'aurelia-pal'; + +initialize(); + +describe('NodeJs Platform', () => { + it('addEventListener is defined', () => { + expect(PLATFORM.addEventListener).toBeDefined(); + }); + it('removeEventListener is defined', () => { + expect(PLATFORM.removeEventListener).toBeDefined(); + }); + it('global is defined', () => { + expect(PLATFORM.global).toBeDefined(); + }); + it('history is defined', () => { + expect(PLATFORM.history).toBeDefined(); + }); + it('location is defined', () => { + expect(PLATFORM.location).toBeDefined(); + }); + it('noop is defined', () => { + expect(PLATFORM.noop).toBeDefined(); + }); + it('performance is defined', () => { + expect(PLATFORM.performance).toBeDefined(); + }); + it('XMLHttpRequest is defined', () => { + expect(PLATFORM.XMLHttpRequest).toBeDefined(); + }); + it('requestAnimationFrame is defined', () => { + expect(PLATFORM.requestAnimationFrame).toBeDefined(); + }); + it('eachModule is defined', () => { + expect(PLATFORM.eachModule).toBeDefined(); + }); +}); diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json new file mode 100644 index 0000000..3ea3166 --- /dev/null +++ b/spec/support/jasmine.json @@ -0,0 +1,11 @@ +{ + "spec_dir": "spec", + "spec_files": [ + "**/*[sS]pec.js" + ], + "helpers": [ + "helpers/**/*.js" + ], + "stopSpecOnExpectationFailure": false, + "random": false +} diff --git a/src/disposable.js b/src/disposable.ts similarity index 73% rename from src/disposable.js rename to src/disposable.ts index 2ea83fe..e2e9070 100644 --- a/src/disposable.js +++ b/src/disposable.ts @@ -1,3 +1,3 @@ export interface IDisposable { - ():void + (): void; } diff --git a/src/dom.js b/src/dom.ts similarity index 95% rename from src/dom.js rename to src/dom.ts index 728bc8d..38e2e3c 100644 --- a/src/dom.js +++ b/src/dom.ts @@ -71,7 +71,7 @@ export interface IDom { * @param callback A callback that will recieve the change records with the mutations. * @return A MutationObservere. */ - createMutationObserver(callback:(changes:MutationRecord[], instance:MutationObserver)=>void): MutationObserver; + createMutationObserver(callback: (changes: MutationRecord[], instance: MutationObserver) => void): MutationObserver; /** * Creates a new CustomEvent. * @param eventType A string representing the event type. @@ -119,7 +119,7 @@ export interface IDom { * @param newNode The node to append. * @param parentNode The node to append to, otherwise the document.body. */ - appendNode(newNode: Node, parentNode?:Node): void; + appendNode(newNode: Node, parentNode?: Node): void; /** * Replaces a node in the parent with a new node. * @param newNode The node to replace the old node with. @@ -140,5 +140,5 @@ export interface IDom { * @param prepend Indicates whether or not the styles should be prepended to the destination. By default they are appended. * @return The Style node that was created. */ - injectStyles(styles: string, destination?: Element, prepend?:boolean): Node; + injectStyles(styles: string, destination?: Element, prepend?: boolean): Node; } diff --git a/src/feature.js b/src/feature.ts similarity index 100% rename from src/feature.js rename to src/feature.ts diff --git a/src/global.js b/src/global.js deleted file mode 100644 index 1778535..0000000 --- a/src/global.js +++ /dev/null @@ -1,7 +0,0 @@ -export interface IGlobal extends Window -{ - Element?:any; - SVGElement?:any; - XMLHttpRequest?:any; - CustomEvent?:{new(eventType: string, options: Object ):CustomEvent }; -} diff --git a/src/global.ts b/src/global.ts new file mode 100644 index 0000000..c1c5dfa --- /dev/null +++ b/src/global.ts @@ -0,0 +1,6 @@ +export interface IGlobal extends Window { + Element?: any; + SVGElement?: any; + XMLHttpRequest?: any; + CustomEvent?: { new (eventType: string, options: Object): CustomEvent }; +} diff --git a/src/index.js b/src/index.ts similarity index 69% rename from src/index.js rename to src/index.ts index a7458bb..0a6b478 100644 --- a/src/index.js +++ b/src/index.ts @@ -1,11 +1,11 @@ -import {initializePAL} from 'aurelia-pal'; -import {IPlatform} from './platform'; -import {IGlobal} from './global'; -import {MutationObserver} from './nodejs-mutation-observer'; -import {NodeJsPlatform} from './nodejs-platform'; -import {NodeJsFeature} from './nodejs-feature'; -import {NodeJsDom} from './nodejs-dom'; -import {jsdom} from 'jsdom'; +import { initializePAL } from 'aurelia-pal'; +import { IPlatform } from './platform'; +import { IGlobal } from './global'; +import { NodeJsMutationObserver } from './nodejs-mutation-observer'; +import { NodeJsPlatform } from './nodejs-platform'; +import { NodeJsFeature } from './nodejs-feature'; +import { NodeJsDom } from './nodejs-dom'; +import { jsdom } from 'jsdom'; let isInitialized = false; /** @@ -18,13 +18,13 @@ export function initialize(): void { isInitialized = true; - let _global: IGlobal = jsdom(undefined, {}).defaultView; + var _global: IGlobal = jsdom(undefined, {}).defaultView; + ensurePerformance(_global.window); - let _platform = new NodeJsPlatform(_global); - let _dom = new NodeJsDom(_global); - let _feature = new NodeJsFeature(_global); - let _mutationObserver = new MutationObserver(_global, () => {}).mutationObserver; + var _platform = new NodeJsPlatform(_global); + var _dom = new NodeJsDom(_global); + var _feature = new NodeJsFeature(_global); initializePAL((platform, feature, dom) => { Object.assign(platform, _platform); @@ -36,16 +36,13 @@ export function initialize(): void { Object.assign(feature, _feature); Object.setPrototypeOf(feature, _feature.constructor.prototype); - Object.assign(MutationObserver, _mutationObserver); - Object.setPrototypeOf(MutationObserver, _mutationObserver.constructor.prototype); - - (function(global) { + (function (global) { global.console = global.console || {}; let con = global.console; let prop; let method; let empty = {}; - let dummy = function() { }; + let dummy = function () { }; let properties = 'memory'.split(','); let methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + @@ -55,28 +52,28 @@ export function initialize(): void { })(platform.global); if (platform.global.console && typeof console.log === 'object') { - ['log', 'info', 'warn', 'error', 'assert', 'dir', 'clear', 'profile', 'profileEnd'].forEach(function(method) { + ['log', 'info', 'warn', 'error', 'assert', 'dir', 'clear', 'profile', 'profileEnd'].forEach(function (method) { console[method] = this.bind(console[method], console); }, Function.prototype.call); } Object.defineProperty(dom, 'title', { - get: function() { + get: function () { return _global.document.title; }, - set: function(value) { + set: function (value) { _global.document.title = value; } }); Object.defineProperty(dom, 'activeElement', { - get: function() { + get: function () { return _global.document.activeElement; } }); Object.defineProperty(platform, 'XMLHttpRequest', { - get: function() { + get: function () { return _global.XMLHttpRequest; } }); @@ -84,6 +81,7 @@ export function initialize(): void { } function ensurePerformance(window) { + if (window.performance === undefined) { window.performance = {}; } diff --git a/src/nodejs-dom.js b/src/nodejs-dom.ts similarity index 84% rename from src/nodejs-dom.js rename to src/nodejs-dom.ts index bf0aea4..6a36844 100644 --- a/src/nodejs-dom.js +++ b/src/nodejs-dom.ts @@ -1,25 +1,26 @@ -import {IDom} from './dom'; -import {IGlobal} from './global'; -import {NodeJsMutationEmulator} from './nodejs-mutation-emulator'; -import {NodeJsMutationObserver} from './nodejs-mutation-observer'; +import { IDom } from './dom'; +import { IGlobal } from './global'; +import { NodeJsMutationEmulator } from './nodejs-mutation-emulator'; +import { NodeJsMutationObserver } from './nodejs-mutation-observer'; /** * Represents the core APIs of the DOM. */ export class NodeJsDom implements IDom { - mutationEmulator: NodeJsMutationEmulator; - constructor(global: IGlobal) { - this.global = global; - this.Element = global.Element; - this.SVGElement = global.SVGElement; + public mutationEmulator: NodeJsMutationEmulator; + + constructor(public global: IGlobal) { + + this.Element = (global).Element; + this.SVGElement = (global).SVGElement; this.mutationEmulator = new NodeJsMutationEmulator(); } Element: { new (): Element }; SVGElement: { new (): SVGElement }; boundary: string = 'aurelia-dom-boundary'; - title: string = ''; + title: string = ""; activeElement: Element = null; addEventListener(eventName: string, callback: EventListener, capture: boolean): void { @@ -41,7 +42,7 @@ export class NodeJsDom implements IDom { return this.global.document.createDocumentFragment(); } createMutationObserver(callback: (changes: MutationRecord[], instance: MutationObserver) => void): MutationObserver { - return (this.global.window).MutationObserver || (!this.mutationEmulator) ? new NodeJsMutationObserver(this.mutationEmulator, callback) : null; + return (this.global.window).MutationObserver || (this.mutationEmulator != null) ? new NodeJsMutationObserver(this.mutationEmulator, callback) : null; } createCustomEvent(eventType: string, options: Object): CustomEvent { return new this.global.CustomEvent(eventType, options); @@ -106,7 +107,8 @@ export class NodeJsDom implements IDom { removeNode(node: Node, parentNode?: Node): void { if (node.parentNode) { node.parentNode.removeChild(node); - } else { + } + else { parentNode.removeChild(node); } } diff --git a/src/nodejs-feature.js b/src/nodejs-feature.js deleted file mode 100644 index e5d1796..0000000 --- a/src/nodejs-feature.js +++ /dev/null @@ -1,17 +0,0 @@ -import {IFeature} from './feature'; -import {IGlobal} from './global'; - -export class NodeJsFeature implements IFeature { - constructor(global: IGlobal) { - this.gloabl = global; - this.shadowDOM = (global.window).HTMLElement.prototype.attachShadow !== undefined; - this.scopedCSS = 'scoped' in global.document.createElement('style'); - this.htmlTemplateElement = true; - this.mutationObserver = true; // partial - } - - shadowDOM: boolean; - scopedCSS: boolean; - htmlTemplateElement: boolean; - mutationObserver: boolean; -} diff --git a/src/nodejs-feature.ts b/src/nodejs-feature.ts new file mode 100644 index 0000000..24b1436 --- /dev/null +++ b/src/nodejs-feature.ts @@ -0,0 +1,16 @@ +import { IFeature } from './feature'; +import { IGlobal } from './global'; + +export class NodeJsFeature implements IFeature { + constructor(private global: IGlobal) { + this.shadowDOM = (this.global.window).HTMLElement.prototype.attachShadow != undefined; + this.scopedCSS = 'scoped' in this.global.document.createElement('style'); + this.htmlTemplateElement = true; + this.mutationObserver = false; // partial + } + + shadowDOM: boolean; + scopedCSS: boolean; + htmlTemplateElement: boolean; + mutationObserver: boolean; +} diff --git a/src/nodejs-mutation-emulator.js b/src/nodejs-mutation-emulator.ts similarity index 56% rename from src/nodejs-mutation-emulator.js rename to src/nodejs-mutation-emulator.ts index 9fa0a9a..b1499a7 100644 --- a/src/nodejs-mutation-emulator.js +++ b/src/nodejs-mutation-emulator.ts @@ -1,12 +1,13 @@ -import {IObserver} from './observer'; -import {IDisposable} from './disposable'; +import { EventEmitter } from 'events'; +import { IObserver } from './observer'; +import { IDisposable } from './disposable'; export class NodeJsMutationEmulator { - cycleMutations: MutationRecord[]; - cycleTimerId: NodeJS.Timer; - targets: { target: Node, last: Node }[]; - observers: IObserver[]; - interval:number; + private cycleMutations: MutationRecord[]; + private cycleTimerId: NodeJS.Timer; + private targets: { target: Node, last: Node }[]; + private observers: IObserver[]; + public interval: number; constructor(interval?: number) { this.interval = (interval === undefined) ? 100 : interval; @@ -17,9 +18,8 @@ export class NodeJsMutationEmulator { } start() { - if (this.interval > 0) { + if (this.interval > 0) this.cycleTimerId = setInterval(() => this.cycle(), this.interval); - } } stop() { @@ -33,36 +33,35 @@ export class NodeJsMutationEmulator { registerObserver(observer: IObserver): IDisposable { this.observers.push(observer); - let target = observer.target; - let entry = this.targets.find(x => x.target === target); + var target = observer.target; + var entry = this.targets.find(x => x.target == target); if (!entry) { entry = { target: target, - last: target.cloneNode(true) + last: target.cloneNode(true), }; this.targets.push(entry); } return () => { - let index = this.observers.indexOf(observer); - if (index !== -1) { + var index = this.observers.indexOf(observer); + if (index != -1) this.observers.splice(index, 1); - } }; } - cycle() { - this._cycleDirtyCheck(); - this._cycleReport(); - this._cycleTidy(); + public cycle() { + this.cycleDirtyCheck(); + this.cycleReport(); + this.cycleTidy(); } - _cycleTidy() { - //remove targets no longer having any observer; + private cycleTidy() { + //remove targets no longer having any observer; } - _cycleReport() { + private cycleReport() { let mutations = this.cycleMutations; this.cycleMutations = []; @@ -73,17 +72,15 @@ export class NodeJsMutationEmulator { for (let i = 0; i < count; i++) { let mutation = mutations[i]; - if (observer.target === mutation.target) { + if (observer.target == mutation.target) observerMutations.push(mutation); - } } - if (observerMutations.length > 0) { + if (observerMutations.length > 0) observer.callback(observerMutations); - } }); } - _cycleDirtyCheck() { + private cycleDirtyCheck() { let targets = this.targets; let targetsCount = targets.length; @@ -92,18 +89,17 @@ export class NodeJsMutationEmulator { let targetNode = target.target; let previous = target.last; - this._cycleDirtyCheckAttributes(targetNode, previous); - this._cycleDirtyCheckNodeValue(targetNode, previous); - this._cycleDirtyCheckChildList(targetNode, previous); + this.cycleDirtyCheckAttributes(targetNode, previous); + this.cycleDirtyCheckNodeValue(targetNode, previous); + this.cycleDirtyCheckChildList(targetNode, previous); target.last = targetNode.cloneNode(true); } } - _cycleDirtyCheckAttributes(target: Node, previous: Node) { - if (!target.attributes) { + private cycleDirtyCheckAttributes(target: Node, previous: Node) { + if (!target.attributes) return; - } let attrNew = target.attributes; let attrOld = previous.attributes; @@ -111,19 +107,21 @@ export class NodeJsMutationEmulator { for (let i = 0; i < countNew; i++) { let attr = attrNew.item(i); - let old = this._findAttr(attrOld, attr.name); + let old = this.findAttr(attrOld, attr.name); - if (!old || old.value !== attr.value) { - let mutation = { + let mutated = false; + + if (!old || old.value != attr.value) { + let mutation = { target: target, - type: 'attributes', + type: "attributes", addedNodes: {}, removedNodes: {}, previousSibling: null, nextSibling: null, oldValue: old.value, attributeName: attr.name, - attributeNamespace: attr.namespaceURI + attributeNamespace: attr.namespaceURI, }; this.registerMutation(mutation); } @@ -132,19 +130,20 @@ export class NodeJsMutationEmulator { let countOld = attrOld.length; for (let i = 0; i < countOld; i++) { + let old = attrOld.item(i); - if (!this._findAttr(attrNew, old.name)) { - let mutation = { + if (!this.findAttr(attrNew, old.name)) { + let mutation = { target: target, - type: 'attributes', + type: "attributes", addedNodes: {}, removedNodes: {}, previousSibling: null, nextSibling: null, oldValue: old.value, attributeName: old.name, - attributeNamespace: old.namespaceURI + attributeNamespace: old.namespaceURI, }; this.registerMutation(mutation); @@ -152,38 +151,36 @@ export class NodeJsMutationEmulator { } } - _cycleDirtyCheckNodeValue(target: Node, previous:Node ) { - if (target.nodeValue !== previous.nodeValue) { - let mutation = { + private cycleDirtyCheckNodeValue(target: Node, previous: Node) { + if (target.nodeValue != previous.nodeValue) { + let mutation = { target: target, - type: 'characterData', + type: "characterData", addedNodes: {}, removedNodes: {}, previousSibling: null, nextSibling: null, oldValue: previous.nodeValue, attributeName: null, - attributeNamespace: null + attributeNamespace: null, }; this.registerMutation(mutation); } } - _cycleDirtyCheckChildList(target: Node, previous:Node ) { - if (!target.nodeValue) { + private cycleDirtyCheckChildList(target: Node, previous: Node) { + if (!target.nodeValue) return; - } } - _findAttr(attrs: NamedNodeMap, name: string): Attr { - let count = attrs.length; + private findAttr(attrs: NamedNodeMap, name: string): Attr { + var count = attrs.length; for (let i = 0; i < count; i++) { - let attr = attrs.item(i); - if (attr.name === name) { + var attr = attrs.item(i); + if (attr.name == name) return attr; - } } return null; } diff --git a/src/nodejs-mutation-observer.js b/src/nodejs-mutation-observer.js deleted file mode 100644 index 3d121f9..0000000 --- a/src/nodejs-mutation-observer.js +++ /dev/null @@ -1,600 +0,0 @@ -export class MutationObserver { - constructor(global, callback) { - let document = global.document; - let window = global.window; - window.MutationObserver = window.MutationObserver || (function(undefined) { - "use strict"; - /** - * @param {function(Array., MutationObserver)} listener - * @constructor - */ - function MutationObserver(listener) { - /** - * @type {Array.} - * @private - */ - this._watched = []; - /** @private */ - this._listener = listener; - } - - /** - * Start a recursive timeout function to check all items being observed for mutations - * @type {MutationObserver} observer - * @private - */ - function startMutationChecker(observer) { - (function check() { - var mutations = observer.takeRecords(); - - if (mutations.length) { // fire away - // calling the listener with context is not spec but currently consistent with FF and WebKit - observer._listener(mutations, observer); - } - /** @private */ - observer._timeout = setTimeout(check, MutationObserver._period); - })(); - } - - /** - * Period to check for mutations (~32 times/sec) - * @type {number} - * @expose - */ - MutationObserver._period = 30 /*ms+runtime*/ ; - - /** - * Exposed API - * @expose - * @final - */ - MutationObserver.prototype = { - /** - * see http:// dom.spec.whatwg.org/#dom-mutationobserver-observe - * not going to throw here but going to follow the current spec config sets - * @param {Node|null} $target - * @param {Object|null} config : MutationObserverInit configuration dictionary - * @expose - * @return undefined - */ - observe: function($target, config) { - /** - * Using slightly different names so closure can go ham - * @type {!Object} : A custom mutation config - */ - var settings = { - attr: !! (config.attributes || config.attributeFilter || config.attributeOldValue), - - // some browsers enforce that subtree must be set with childList, attributes or characterData. - // We don't care as spec doesn't specify this rule. - kids: !! config.childList, - descendents: !! config.subtree, - charData: !! (config.characterData || config.characterDataOldValue) - }; - - var watched = this._watched; - - // remove already observed target element from pool - for (var i = 0; i < watched.length; i++) { - if (watched[i].tar === $target) watched.splice(i, 1); - } - - if (config.attributeFilter) { - /** - * converts to a {key: true} dict for faster lookup - * @type {Object.} - */ - settings.afilter = reduce(config.attributeFilter, function(a, b) { - a[b] = true; - return a; - }, {}); - } - - watched.push({ - tar: $target, - fn: createMutationSearcher($target, settings) - }); - - // reconnect if not connected - if (!this._timeout) { - startMutationChecker(this); - } - }, - - /** - * Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once - * @expose - * @return {Array.} - */ - takeRecords: function() { - var mutations = []; - var watched = this._watched; - - for (var i = 0; i < watched.length; i++) { - watched[i].fn(mutations); - } - - return mutations; - }, - - /** - * @expose - * @return undefined - */ - disconnect: function() { - this._watched = []; // clear the stuff being observed - clearTimeout(this._timeout); // ready for garbage collection - /** @private */ - this._timeout = null; - } - }; - - /** - * Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant - * @param {Object} data - * @return {Object} a MutationRecord - */ - function MutationRecord(data) { - var settings = { // technically these should be on proto so hasOwnProperty will return false for non explicitly props - type: null, - target: null, - addedNodes: [], - removedNodes: [], - previousSibling: null, - nextSibling: null, - attributeName: null, - attributeNamespace: null, - oldValue: null - }; - for (var prop in data) { - if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop]; - } - return settings; - } - - /** - * Creates a func to find all the mutations - * - * @param {Node} $target - * @param {!Object} config : A custom mutation config - */ - function createMutationSearcher($target, config) { - /** type {Elestuct} */ - var $oldstate = clone($target, config); // create the cloned datastructure - - /** - * consumes array of mutations we can push to - * - * @param {Array.} mutations - */ - return function(mutations) { - var olen = mutations.length, dirty; - - // Alright we check base level changes in attributes... easy - if (config.attr && $oldstate.attr) { - findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter); - } - - // check childlist or subtree for mutations - if (config.kids || config.descendents) { - dirty = searchSubtree(mutations, $target, $oldstate, config); - } - - // reclone data structure if theres changes - if (dirty || mutations.length !== olen) { - /** type {Elestuct} */ - $oldstate = clone($target, config); - } - }; - } - - /* attributes + attributeFilter helpers */ - - // Check if the environment has the attribute bug (#4) which cause - // element.attributes.style to always be null. - var hasAttributeBug = document.createElement("i"); - hasAttributeBug.style.top = 0; - hasAttributeBug = hasAttributeBug.attributes.style.value != "null"; - - /** - * Gets an attribute value in an environment without attribute bug - * - * @param {Node} el - * @param {Attr} attr - * @return {String} an attribute value - */ - function getAttributeSimple(el, attr) { - // There is a potential for a warning to occur here if the attribute is a - // custom attribute in IE<9 with a custom .toString() method. This is - // just a warning and doesn't affect execution (see #21) - return attr.value; - } - - /** - * Gets an attribute value with special hack for style attribute (see #4) - * - * @param {Node} el - * @param {Attr} attr - * @return {String} an attribute value - */ - function getAttributeWithStyleHack(el, attr) { - // As with getAttributeSimple there is a potential warning for custom attribtues in IE7. - return attr.name !== "style" ? attr.value : el.style.cssText; - } - - var getAttributeValue = hasAttributeBug ? getAttributeSimple : getAttributeWithStyleHack; - - /** - * fast helper to check to see if attributes object of an element has changed - * doesnt handle the textnode case - * - * @param {Array.} mutations - * @param {Node} $target - * @param {Object.} $oldstate : Custom attribute clone data structure from clone - * @param {Object} filter - */ - function findAttributeMutations(mutations, $target, $oldstate, filter) { - var checked = {}; - var attributes = $target.attributes; - var attr; - var name; - var i = attributes.length; - while (i--) { - attr = attributes[i]; - name = attr.name; - if (!filter || has(filter, name)) { - if (getAttributeValue($target, attr) !== $oldstate[name]) { - // The pushing is redundant but gzips very nicely - mutations.push(MutationRecord({ - type: "attributes", - target: $target, - attributeName: name, - oldValue: $oldstate[name], - attributeNamespace: attr.namespaceURI // in ie<8 it incorrectly will return undefined - })); - } - checked[name] = true; - } - } - for (name in $oldstate) { - if (!(checked[name])) { - mutations.push(MutationRecord({ - target: $target, - type: "attributes", - attributeName: name, - oldValue: $oldstate[name] - })); - } - } - } - - /** - * searchSubtree: array of mutations so far, element, element clone, bool - * synchronous dfs comparision of two nodes - * This function is applied to any observed element with childList or subtree specified - * Sorry this is kind of confusing as shit, tried to comment it a bit... - * codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func - * - * @param {Array} mutations - * @param {Node} $target - * @param {!Object} $oldstate : A custom cloned node from clone() - * @param {!Object} config : A custom mutation config - */ - function searchSubtree(mutations, $target, $oldstate, config) { - // Track if the tree is dirty and has to be recomputed (#14). - var dirty; - /* - * Helper to identify node rearrangment and stuff... - * There is no gaurentee that the same node will be identified for both added and removed nodes - * if the positions have been shuffled. - * conflicts array will be emptied by end of operation - */ - function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) { - // the distance between the first conflicting node and the last - var distance = conflicts.length - 1; - // prevents same conflict being resolved twice consider when two nodes switch places. - // only one should be given a mutation event (note -~ is used as a math.ceil shorthand) - var counter = -~((distance - numAddedNodes) / 2); - var $cur; - var oldstruct; - var conflict; - while ((conflict = conflicts.pop())) { - $cur = $kids[conflict.i]; - oldstruct = $oldkids[conflict.j]; - - // attempt to determine if there was node rearrangement... won't gaurentee all matches - // also handles case where added/removed nodes cause nodes to be identified as conflicts - if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) { - mutations.push(MutationRecord({ - type: "childList", - target: node, - addedNodes: [$cur], - removedNodes: [$cur], - // haha don't rely on this please - nextSibling: $cur.nextSibling, - previousSibling: $cur.previousSibling - })); - counter--; // found conflict - } - - // Alright we found the resorted nodes now check for other types of mutations - if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); - if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) { - mutations.push(MutationRecord({ - type: "characterData", - target: $cur - })); - } - // now look @ subtree - if (config.descendents) findMutations($cur, oldstruct); - } - } - - /** - * Main worker. Finds and adds mutations if there are any - * @param {Node} node - * @param {!Object} old : A cloned data structure using internal clone - */ - function findMutations(node, old) { - var $kids = node.childNodes; - var $oldkids = old.kids; - var klen = $kids.length; - // $oldkids will be undefined for text and comment nodes - var olen = $oldkids ? $oldkids.length : 0; - // if (!olen && !klen) return; // both empty; clearly no changes - - // we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused) - // map of checked element of ids to prevent registering the same conflict twice - var map; - // array of potential conflicts (ie nodes that may have been re arranged) - var conflicts; - var id; // element id from getElementId helper - var idx; // index of a moved or inserted element - - var oldstruct; - // current and old nodes - var $cur; - var $old; - // track the number of added nodes so we can resolve conflicts more accurately - var numAddedNodes = 0; - - // iterate over both old and current child nodes at the same time - var i = 0, j = 0; - // while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;) - while( i < klen || j < olen ) { - // current and old nodes at the indexs - $cur = $kids[i]; - oldstruct = $oldkids[j]; - $old = oldstruct && oldstruct.node; - - if ($cur === $old) { // expected case - optimized for this case - // check attributes as specified by config - if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); - // check character data if node is a comment or textNode and it's being observed - if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) { - mutations.push(MutationRecord({ - type: "characterData", - target: $cur - })); - } - - // resolve conflicts; it will be undefined if there are no conflicts - otherwise an array - if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); - - // recurse on next level of children. Avoids the recursive call when there are no children left to iterate - if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct); - - i++; - j++; - } else { // (uncommon case) lookahead until they are the same again or the end of children - dirty = true; - if (!map) { // delayed initalization (big perf benefit) - map = {}; - conflicts = []; - } - if ($cur) { - // check id is in the location map otherwise do a indexOf search - if (!(map[id = getElementId($cur)])) { // to prevent double checking - // mark id as found - map[id] = true; - // custom indexOf using comparitor checking oldkids[i].node === $cur - if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) { - if (config.kids) { - mutations.push(MutationRecord({ - type: "childList", - target: node, - addedNodes: [$cur], // $cur is a new node - nextSibling: $cur.nextSibling, - previousSibling: $cur.previousSibling - })); - numAddedNodes++; - } - } else { - conflicts.push({ // add conflict - i: i, - j: idx - }); - } - } - i++; - } - - if ($old && - // special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case - $old !== $kids[i] - ) { - if (!(map[id = getElementId($old)])) { - map[id] = true; - if ((idx = indexOf($kids, $old, i)) === -1) { - if (config.kids) { - mutations.push(MutationRecord({ - type: "childList", - target: old.node, - removedNodes: [$old], - nextSibling: $oldkids[j + 1], // praise no indexoutofbounds exception - previousSibling: $oldkids[j - 1] - })); - numAddedNodes--; - } - } else { - conflicts.push({ - i: idx, - j: j - }); - } - } - j++; - } - }// end uncommon case - }// end loop - - // resolve any remaining conflicts - if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); - } - findMutations($target, $oldstate); - return dirty; - } - - /** - * Utility - * Cones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012 - * - * @param {Node} $target - * @param {!Object} config : A custom mutation config - * @return {!Object} : Cloned data structure - */ - function clone($target, config) { - var recurse = true; // set true so childList we'll always check the first level - return (function copy($target) { - var elestruct = { - /** @type {Node} */ - node: $target - }; - - // Store current character data of target text or comment node if the config requests - // those properties to be observed. - if (config.charData && ($target.nodeType === 3 || $target.nodeType === 8)) { - elestruct.charData = $target.nodeValue; - } - // its either a element, comment, doc frag or document node - else { - // Add attr only if subtree is specified or top level and avoid if - // attributes is a document object (#13). - if (config.attr && recurse && $target.nodeType === 1) { - /** - * clone live attribute list to an object structure {name: val} - * @type {Object.} - */ - elestruct.attr = reduce($target.attributes, function(memo, attr) { - if (!config.afilter || config.afilter[attr.name]) { - memo[attr.name] = getAttributeValue($target, attr); - } - return memo; - }, {}); - } - - // whether we should iterate the children of $target node - if (recurse && ((config.kids || config.charData) || (config.attr && config.descendents)) ) { - /** @type {Array.} : Array of custom clone */ - elestruct.kids = map($target.childNodes, copy); - } - - recurse = config.descendents; - } - return elestruct; - })($target); - } - - /** - * indexOf an element in a collection of custom nodes - * - * @param {NodeList} set - * @param {!Object} $node : A custom cloned node - * @param {number} idx : index to start the loop - * @return {number} - */ - function indexOfCustomNode(set, $node, idx) { - return indexOf(set, $node, idx, JSCompiler_renameProperty("node")); - } - - // using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like
  • - var counter = 1; // don't use 0 as id (falsy) - /** @const */ - var expando = "mo_id"; - - /** - * Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern - * - * @param {Node} $ele - * @return {(string|number)} - */ - function getElementId($ele) { - try { - return $ele.id || ($ele[expando] = $ele[expando] || counter++); - } catch (o_O) { // ie <8 will throw if you set an unknown property on a text node - try { - return $ele.nodeValue; // naive - } catch (shitie) { // when text node is removed: https://gist.github.com/megawac/8355978 :( - return counter++; - } - } - } - - /** - * **map** Apply a mapping function to each item of a set - * @param {Array|NodeList} set - * @param {Function} iterator - */ - function map(set, iterator) { - var results = []; - for (var index = 0; index < set.length; index++) { - results[index] = iterator(set[index], index, set); - } - return results; - } - - /** - * **Reduce** builds up a single result from a list of values - * @param {Array|NodeList|NamedNodeMap} set - * @param {Function} iterator - * @param {*} [memo] Initial value of the memo. - */ - function reduce(set, iterator, memo) { - for (var index = 0; index < set.length; index++) { - memo = iterator(memo, set[index], index, set); - } - return memo; - } - - /** - * **indexOf** find index of item in collection. - * @param {Array|NodeList} set - * @param {Object} item - * @param {number} idx - * @param {string} [prop] Property on set item to compare to item - */ - function indexOf(set, item, idx, prop) { - for (/*idx = ~~idx*/; idx < set.length; idx++) {// start idx is always given as this is internal - if ((prop ? set[idx][prop] : set[idx]) === item) return idx; - } - return -1; - } - - /** - * @param {Object} obj - * @param {(string|number)} prop - * @return {boolean} - */ - function has(obj, prop) { - return obj[prop] !== undefined; // will be nicely inlined by gcc - } - - // GCC hack see http:// stackoverflow.com/a/23202438/1517919 - const JSCompiler_renameProperty = a => a; - - return MutationObserver; - })(void 0); - - this.mutationObserver = new window.MutationObserver(callback); - } -} diff --git a/src/nodejs-mutation-observer.ts b/src/nodejs-mutation-observer.ts new file mode 100644 index 0000000..dcbe8ae --- /dev/null +++ b/src/nodejs-mutation-observer.ts @@ -0,0 +1,30 @@ +import { NodeJsMutationEmulator } from './nodejs-mutation-emulator'; + +//https://developer.mozilla.org/en/docs/Web/API/MutationObserver + +export class NodeJsMutationObserver implements MutationObserver { + private disposable: () => void; + + constructor( + private source: NodeJsMutationEmulator, + private callback: (changes: MutationRecord[], instance: MutationObserver) => void) { + } + + disconnect(): void { + if (this.disposable) + this.disposable(); + this.disposable = null; + } + + observe(target: Node, options: MutationObserverInit): void { + this.disposable = this.source.registerObserver({ + target: target, + options: options, + callback: (changes: MutationRecord[]) => this.callback(changes, this) + }); + } + + takeRecords(): MutationRecord[] { + throw new Error("NotImplementedException"); + } +} diff --git a/src/nodejs-platform.js b/src/nodejs-platform.ts similarity index 77% rename from src/nodejs-platform.js rename to src/nodejs-platform.ts index 6d1ec0c..5912006 100644 --- a/src/nodejs-platform.js +++ b/src/nodejs-platform.ts @@ -1,21 +1,20 @@ -import {IPlatform} from './platform'; -import {IPerformance} from './performance'; -import {IGlobal} from './global'; +import { IPlatform } from './platform'; +import { IPerformance } from './performance'; +import { IGlobal } from './global'; export class NodeJsPlatform implements IPlatform { - constructor(global: IGlobal) { - this.global = global; - this.performance = global.performance; - this.location = global.location; - this.history = global.history; - this.XMLHttpRequest = global.XMLHttpRequest; + constructor(public global: IGlobal) { + this.performance = this.global.performance; + this.location = this.global.location; + this.history = this.global.history; + this.XMLHttpRequest = this.global.XMLHttpRequest; } /** * A function wich does nothing. */ - noop: Function = ()=>{}; + noop: Function = () => { }; /** * The runtime's location API. */ @@ -42,7 +41,7 @@ export class NodeJsPlatform implements IPlatform { * @param callback A callback that will receive each module id along with the module object. Return true to end enumeration. */ eachModule(callback: (key: string, value: Object) => boolean): void { - //TODO: What is this? + //TODO: What is this? } /** * Add a global event listener. @@ -51,7 +50,7 @@ export class NodeJsPlatform implements IPlatform { * @param capture If true, useCapture indicates that the user wishes to initiate capture. */ addEventListener(eventName: string, callback: Function, capture?: boolean): void { - this.global.addEventListener(eventName, callback, capture); + this.global.addEventListener(eventName, callback, capture); } /** * Remove a global event listener. @@ -60,7 +59,7 @@ export class NodeJsPlatform implements IPlatform { * @param capture Specifies whether the listener to be removed was registered as a capturing listener or not. */ removeEventListener(eventName: string, callback: Function, capture?: boolean): void { - this.global.removeEventListener(eventName, callback, capture); + this.global.removeEventListener(eventName, callback, capture); } /** diff --git a/src/observer.js b/src/observer.ts similarity index 62% rename from src/observer.js rename to src/observer.ts index cc7678a..849fd81 100644 --- a/src/observer.js +++ b/src/observer.ts @@ -1,5 +1,5 @@ export interface IObserver { - target: Node, - options?: MutationObserverInit, + target: Node; + options?: MutationObserverInit; callback: (mutations: MutationRecord[]) => void; } diff --git a/src/performance.js b/src/performance.ts similarity index 99% rename from src/performance.js rename to src/performance.ts index 118feb9..72839f9 100644 --- a/src/performance.js +++ b/src/performance.ts @@ -8,4 +8,3 @@ export interface IPerformance { */ now(): number; } - diff --git a/src/platform.js b/src/platform.ts similarity index 96% rename from src/platform.js rename to src/platform.ts index 626f1c1..e150d18 100644 --- a/src/platform.js +++ b/src/platform.ts @@ -1,4 +1,4 @@ -import {IPerformance} from './performance'; +import { IPerformance } from './performance'; /** * Represents the core APIs of the runtime environment. @@ -7,7 +7,7 @@ export interface IPlatform { /** * The runtime environment's global. */ - global: any, + global: any; /** * A function wich does nothing. */ diff --git a/test/nodejs-mutation-source.spec.js b/test/nodejs-mutation-source.spec.js deleted file mode 100644 index 6ba7142..0000000 --- a/test/nodejs-mutation-source.spec.js +++ /dev/null @@ -1,146 +0,0 @@ -import {initialize} from '../src/index' -import {jsdom} from 'jsdom'; -import {MutationObserver} from '../src/nodejs-mutation-observer'; - -initialize(); - -describe("Mutation Observer", () => { - let observer, dom, document; - const noop = () => {}; - - beforeEach(() => { - dom = jsdom(undefined, {}).defaultView; - document = dom.document; - observer = new MutationObserver(dom, noop).mutationObserver; - }); - - afterEach(() => { - observer.disconnect(); - }); - - it('should be defined', () => { - expect(observer).toBeDefined(); - }); - - it('should not detect no changes', () => { - const target = document.createElement('div'); - - target.setAttribute('attribute', 'attribute'); - - observer.observe(target, { - attributes: true, - attributeOldValue: true - }); - - let records = observer.takeRecords(); - - expect(records.length).toBe(0); - - target.setAttribute('attribute', 'attribute'); - - records = observer.takeRecords(); - - expect(records.length).toBe(0); - }); - - it('should detect changes for a single element', () => { - const target = document.createElement('div'); - - target.setAttribute('class', 100); - - observer.observe(target, { - attributes: true, - attributeOldValue: true - }); - - target.removeAttribute('class'); - - const records = observer.takeRecords(); - - expect(records.length).toBe(1); - expect(records[0].oldValue).toBe('100'); - }); - - it('should detect changes for a parents elements', () => { - const target = document.createElement('div'); - const child = document.createElement('div'); - - target.setAttribute('id', 'parent'); - child.setAttribute('id', 'child'); - target.appendChild(child); - - observer.observe(target, { - attributes: true, - childList: true - }); - - target.removeAttribute('id'); - - const records = observer.takeRecords(); - - expect(records.length).toBe(1); - expect(records[0].oldValue).toBe('parent'); - }); - - it('should detect removing child nodes', () => { - const target = document.createElement('div'); - const child = document.createTextNode(`I'm a text node`); - - target.setAttribute('id', 'parent'); - target.appendChild(child); - - observer.observe(target, { - attributes: true, - childList: true - }); - - target.removeChild(child); - - const records = observer.takeRecords(); - - expect(records.length).toBe(1); - expect(records[0].removedNodes).toBeDefined(); - }); - - it('should detect both parent and child changes', () => { - const target = document.createElement('div'); - const child = document.createElement('div'); - - target.setAttribute('id', 'parent'); - child.setAttribute('id', 'child'); - - target.appendChild(child); - - observer.observe(target, { - attributes: true, - childList: true, - attributeOldValue: true - }); - - target.setAttribute('id', 'changedParent'); - child.setAttribute('id', 'changedChild'); - - const records = observer.takeRecords(); - - expect(records.length).toBe(2); - expect(records[0].oldValue).toBe('parent'); - expect(records[1].oldValue).toBe('child'); - }); - - xit('should detect changes for a single text node', () => { - const textNode = document.createTextNode(`I'm a text node`); - console.dir(textNode); - - observer.observe(textNode, { - attributes: true, - attributeOldValue: true - }); - - textNode.innerText = 'class'; - - const records = observer.takeRecords(); - - expect(records.length).toBe(1); - expect(records[0].oldValue).toBe('100'); - }); -}); diff --git a/test/nodejs-platform.spec.js b/test/nodejs-platform.spec.js deleted file mode 100644 index 22e35a3..0000000 --- a/test/nodejs-platform.spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import {initialize} from '../src/index' -import {PLATFORM} from 'aurelia-pal'; - -initialize(); - -describe('NodeJs Platform', () => { - it('addEventListener is defined', () => { - expect(PLATFORM.addEventListener).toBeDefined(); - }); - it('removeEventListener is defined', () => { - expect(PLATFORM.removeEventListener).toBeDefined(); - }); - it('global is defined', () => { - expect(PLATFORM.global).toBeDefined(); - }); - it('history is defined', () => { - expect(PLATFORM.history).toBeDefined(); - }); - it('location is defined', () => { - expect(PLATFORM.location).toBeDefined(); - }); - it('noop is defined', () => { - expect(PLATFORM.noop).toBeDefined(); - }); - it('performance is defined', () => { - expect(PLATFORM.performance).toBeDefined(); - }); - it('XMLHttpRequest is defined', () => { - expect(PLATFORM.XMLHttpRequest).toBeDefined(); - }); - it('requestAnimationFrame is defined', () => { - expect(PLATFORM.requestAnimationFrame).toBeDefined(); - }); - it('eachModule is defined', () => { - expect(PLATFORM.eachModule).toBeDefined(); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index 4adcc86..859719c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,16 @@ { "compilerOptions": { - "target": "es2015", - "module": "es2015", + "target": "es6", + "module": "commonjs", "experimentalDecorators": true, "emitDecoratorMetadata": false, "moduleResolution": "node", "stripInternal": true, - "preserveConstEnums": true, - "listFiles": true, + "preserveConstEnums": true, "declaration": true, - "removeComments": true, - "lib": ["es2015", "dom"] + "removeComments": false }, "exclude": [ - "node_modules", - "dist", - "build", - "doc", - "test", - "config.js", - "gulpfile.js", - "karma.conf.js" + "node_modules" ] } diff --git a/tsfmt.json b/tsfmt.json new file mode 100644 index 0000000..0e9a8af --- /dev/null +++ b/tsfmt.json @@ -0,0 +1,4 @@ +{ + "convertTabsToSpaces": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": true +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..0992b5d --- /dev/null +++ b/tslint.json @@ -0,0 +1,63 @@ +{ + "rules": { + "use-isnan": true, + "linebreak-style": [ + true, + "LF" + ], + "class-name": true, + "comment-format": [ + false, + "check-space" + ], + "indent": [ + true, + "spaces" + ], + "no-duplicate-variable": true, + "no-eval": true, + "no-internal-module": true, + "no-trailing-whitespace": false, + "no-unsafe-finally": true, + "no-var-keyword": false, + "one-line": [ + false, + "check-open-brace", + "check-whitespace" + ], + "quotemark": [ + false, + "double" + ], + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + false, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": [ + true, + "ban-keywords" + ], + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ] + } +} diff --git a/typings.json b/typings.json deleted file mode 100644 index 056abde..0000000 --- a/typings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "aurelia-pal-nodejs", - "main": "dist/aurelia-pal-nodejs.d.ts", - "dependencies": { - "aurelia-pal": "github:aurelia/pal" - } -}