moved submodules into this project
This commit is contained in:
parent
61ceed5bf6
commit
97f6ceb27b
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
var rename = require('gulp-rename');
|
||||
var watch = require('gulp-watch');
|
||||
var gulpTraceur = require('./gulp-traceur');
|
||||
var shell = require('gulp-shell');
|
||||
var clean = require('gulp-rimraf');
|
||||
var mergeStreams = require('event-stream').merge;
|
||||
var ejs = require('gulp-ejs');
|
||||
var glob = require('glob');
|
||||
|
||||
var baseDir = __dirname;
|
||||
var traceurDir = baseDir+'/../traceur';
|
||||
var buildDir = baseDir + '/build';
|
||||
|
||||
var paths = {
|
||||
traceurSrc: traceurDir+'/src/**/*.js',
|
||||
js2dartSrc: baseDir + '/src/**/*.js',
|
||||
specTranspile: baseDir + '/spec/**/*.js',
|
||||
specTemplates: baseDir + '/spec/**/*.template',
|
||||
specCopy: baseDir + '/spec/**/*.dart'
|
||||
};
|
||||
paths.specSrc = [paths.specTranspile, paths.specTemplates, paths.specCopy];
|
||||
|
||||
module.exports.install = install;
|
||||
module.exports.paths = paths;
|
||||
|
||||
function install(gulp) {
|
||||
var runSequence = require('run-sequence').use(gulp);
|
||||
|
||||
// -- js2dart
|
||||
var buildJs2DartOptions = {
|
||||
modules: 'register',
|
||||
moduleName: true,
|
||||
referrer: 'js2dart/src/',
|
||||
script: false // parse as a module
|
||||
};
|
||||
|
||||
var js2dartOptions = {
|
||||
annotations: true, // parse annotations
|
||||
types: true, // parse types
|
||||
script: false, // parse as a module
|
||||
outputLanguage: 'dart',
|
||||
moduleName: true
|
||||
};
|
||||
|
||||
var js2es5Options = {
|
||||
annotations: true, // parse annotations
|
||||
types: true, // parse types
|
||||
script: false, // parse as a module
|
||||
modules: 'register',
|
||||
typeAssertions: true,
|
||||
moduleName: true
|
||||
};
|
||||
|
||||
gulp.task('js2dart/clean', function() {
|
||||
return gulp.src(buildDir, {read: false})
|
||||
.pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('js2dart/build', function() {
|
||||
return gulp
|
||||
.src(paths.js2dartSrc)
|
||||
.pipe(gulpTraceur(buildJs2DartOptions, false))
|
||||
.pipe(gulp.dest(buildDir + '/js2dart'))
|
||||
.on('end', gulpTraceur.reloadPatches);
|
||||
});
|
||||
|
||||
gulp.task('js2dart/test/build', function() {
|
||||
return mergeStreams(specTranspile(false), specCopy(false), specRunner(false));
|
||||
});
|
||||
|
||||
gulp.task('js2dart/test/run', shell.task([
|
||||
'cd '+baseDir+' && dart --checked run_specs.dart'
|
||||
]));
|
||||
|
||||
gulp.task('js2dart/test', function(done) {
|
||||
runSequence('js2dart/test/build', 'js2dart/test/run', done);
|
||||
});
|
||||
|
||||
gulp.task('js2dart/test/watch', function(done) {
|
||||
var streams = [];
|
||||
streams.push(specTranspile(true)
|
||||
.on('data', specRunner));
|
||||
streams.push(specCopy(true));
|
||||
streams.push(specRunner(true));
|
||||
streams.forEach(function(stream) {
|
||||
stream.on('error', done);
|
||||
stream.on('data', function() {
|
||||
runSequence('js2dart/test/run');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function specTranspile(isWatch) {
|
||||
var srcFn = isWatch ? watch : gulp.src.bind(gulp);
|
||||
return srcFn(paths.specTranspile)
|
||||
.pipe(gulpTraceur(js2dartOptions, true))
|
||||
.pipe(rename({extname: '.dart'}))
|
||||
.pipe(gulp.dest(buildDir+'/spec'));
|
||||
}
|
||||
|
||||
function specCopy(isWatch) {
|
||||
var srcFn = isWatch ? watch : gulp.src.bind(gulp);
|
||||
return srcFn(paths.specCopy).pipe(gulp.dest(buildDir+'/spec'));
|
||||
}
|
||||
|
||||
function specRunner(isWatch) {
|
||||
var srcFn = isWatch ? watch : gulp.src.bind(gulp);
|
||||
var builtSpecFiles = glob.sync('**/*_spec.js', {
|
||||
cwd: baseDir+'/spec'
|
||||
}).map(function(fileName) {
|
||||
return fileName.replace('.js', '.dart');
|
||||
});
|
||||
return srcFn(paths.specTemplates)
|
||||
.pipe(ejs({
|
||||
files: builtSpecFiles
|
||||
}))
|
||||
.pipe(rename(function(path) {
|
||||
path.basename = path.basename.replace(/\..*/g, '');
|
||||
path.extname = '.dart';
|
||||
}))
|
||||
.pipe(gulp.dest(buildDir+'/spec'));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
'use strict';
|
||||
var through = require('through2');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var originalTraceur = require('traceur');
|
||||
var glob = require('glob');
|
||||
|
||||
module.exports = gulpTraceur;
|
||||
gulpTraceur.reloadPatches = function() {
|
||||
loadPatches(true);
|
||||
};
|
||||
gulpTraceur.loadPatches = loadPatches;
|
||||
|
||||
|
||||
/// usePatches: whether to use plain traceur or apply
|
||||
/// our patches...
|
||||
function gulpTraceur(options, usePatches) {
|
||||
var lastLoadCounter = loadCounter;
|
||||
var lastCompiler = null;
|
||||
options = options || {};
|
||||
|
||||
return through.obj(function (file, enc, done) {
|
||||
if (file.isNull()) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isStream()) {
|
||||
throw new Error('gulp-traceur: Streaming not supported');
|
||||
}
|
||||
|
||||
var compiler = createCompilerIfNeeded();
|
||||
var ret;
|
||||
try {
|
||||
var fileName = file.relative;
|
||||
if (options.referrer) {
|
||||
fileName = options.referrer + '/' + fileName;
|
||||
}
|
||||
var compiled = compiler.compile(file.contents.toString(), fileName, fileName);
|
||||
file.contents = new Buffer(compiled);
|
||||
this.push(file);
|
||||
done();
|
||||
} catch (errors) {
|
||||
if (errors.join) {
|
||||
throw new Error('gulp-traceur: '+errors.join('\n'));
|
||||
} else {
|
||||
throw errors;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function createCompilerIfNeeded() {
|
||||
loadPatches(false);
|
||||
if (!lastCompiler || lastLoadCounter !== loadCounter) {
|
||||
lastLoadCounter = loadCounter;
|
||||
var CompilerBase;
|
||||
if (usePatches) {
|
||||
CompilerBase = System.get('js2dart/src/compiler').Compiler;
|
||||
} else {
|
||||
CompilerBase = System.get(System.map.traceur+'/src/Compiler').Compiler;
|
||||
}
|
||||
var Compiler = createCompilerConstructor(CompilerBase);
|
||||
lastCompiler = new Compiler(options);
|
||||
}
|
||||
return lastCompiler;
|
||||
}
|
||||
};
|
||||
|
||||
function createCompilerConstructor(CompilerBase) {
|
||||
// See traceur/src/NodeCompiler.js
|
||||
// Needed here as we want to be able to reload
|
||||
// traceur sources once they changed
|
||||
function NodeCompiler(options, sourceRoot) {
|
||||
var sourceRoot = sourceRoot || process.cwd();
|
||||
CompilerBase.call(this, options, sourceRoot);
|
||||
}
|
||||
|
||||
NodeCompiler.prototype = {
|
||||
__proto__: CompilerBase.prototype,
|
||||
|
||||
resolveModuleName: function(filename) {
|
||||
debugger;
|
||||
if (!filename)
|
||||
return;
|
||||
var moduleName = filename.replace(/\.js$/, '');
|
||||
return path.relative(this.sourceRoot, moduleName).replace(/\\/g,'/');
|
||||
},
|
||||
|
||||
sourceName: function(filename) {
|
||||
return path.relative(this.sourceRoot, filename);
|
||||
}
|
||||
}
|
||||
|
||||
return NodeCompiler;
|
||||
}
|
||||
|
||||
var loadCounter = 0;
|
||||
function loadPatches(reload) {
|
||||
if (loadCounter && !reload) {
|
||||
return;
|
||||
}
|
||||
loadCounter++;
|
||||
// see traceur/src/traceur.js
|
||||
// To reload the js2dart modules we need
|
||||
// to clear the registry. To do that we
|
||||
// reload the traceur module...
|
||||
loadModule(path.dirname(module.filename), './node_modules/traceur/bin/traceur.js');
|
||||
|
||||
var buildDir = __dirname + '/build/js2dart';
|
||||
var moduleNames = [].slice.call(glob.sync('**/*.js', {
|
||||
cwd: buildDir
|
||||
}));
|
||||
moduleNames.forEach(function(filename) {
|
||||
loadModule(buildDir, filename);
|
||||
});
|
||||
|
||||
function loadModule(baseFolder, filename) {
|
||||
filename = path.join(baseFolder, filename);
|
||||
var data = fs.readFileSync(filename, 'utf8');
|
||||
if (!data)
|
||||
throw new Error('Failed to import ' + filename);
|
||||
|
||||
('global', eval)(data);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
var gulp = require('gulp');
|
||||
var tasks = require('./gulp-tasks');
|
||||
var runSequence = require('run-sequence');
|
||||
var watch = require('gulp-watch');
|
||||
var mergeStreams = require('event-stream').merge;
|
||||
|
||||
tasks.install(gulp);
|
||||
|
||||
gulp.task('build', function() {
|
||||
return runSequence('js2dart/build');
|
||||
});
|
||||
|
||||
gulp.task('test', function() {
|
||||
return runSequence('build', 'js2dart/test');
|
||||
});
|
||||
|
||||
gulp.task('clean', ['js2dart/clean']);
|
||||
|
||||
gulp.task('watch', function() {
|
||||
var js2dartWatch = watch(tasks.paths.js2dartSrc, function(_, done) {
|
||||
runSequence('js2dart/build', 'js2dart/test', done);
|
||||
});
|
||||
runSequence('js2dart/test/watch');
|
||||
return js2dartWatch;
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "js2dart",
|
||||
"version": "0.0.0",
|
||||
"description": "Compile JavaScript to Dart so that you can compile it back to JavaScript and run.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "gulp js2dart/test",
|
||||
"postinstall": "pub install"
|
||||
},
|
||||
"author": "Vojta Jina <vojta.jina@gmail.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"gulp": "^3.8.8",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-shell": "^0.2.9",
|
||||
"gulp-watch": "^1.0.3",
|
||||
"q": "^1.0.1",
|
||||
"through2": "^0.6.1",
|
||||
"event-stream": "^3.1.5",
|
||||
"gulp-rimraf": "^0.1.0",
|
||||
"run-sequence": "^0.3.6",
|
||||
"glob": "^4.0.6",
|
||||
"gulp-ejs": "^0.3.1",
|
||||
"traceur": "^0.0.66"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
name: js2dart
|
||||
version: 0.0.0
|
||||
authors:
|
||||
- Vojta Jina <vojta.jina@gmail.com>
|
||||
description: Compile JavaScript to Dart so that you can compile it back to JavaScript and run.
|
||||
environment:
|
||||
sdk: '>=1.4.0'
|
||||
dependencies:
|
||||
dev_dependencies:
|
||||
unittest: '>=0.10.1 <0.12.0'
|
|
@ -0,0 +1,7 @@
|
|||
// Note: need this file here so that we can use the packages
|
||||
// in the main folder...
|
||||
import './build/spec/runner.dart' as runner;
|
||||
|
||||
void main() {
|
||||
runner.main();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import annotations from './fixtures/annotations';
|
||||
|
||||
class Inject {}
|
||||
class Bar {}
|
||||
|
||||
@annotations.Provide('Foo')
|
||||
class Foo {
|
||||
@Inject
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@annotations.Provide(Foo)
|
||||
function baz() {}
|
||||
|
||||
function annotatedParams(@Inject(Foo) f, @Inject(Bar) b) {}
|
||||
|
||||
function main() {
|
||||
annotations.main();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Constructor
|
||||
// Define fields
|
||||
class Foo {
|
||||
constructor(a, b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
sum() {
|
||||
return this.a + this.b;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
var foo = new Foo(2, 3);
|
||||
|
||||
assert(foo.a == 2);
|
||||
assert(foo.b == 3);
|
||||
assert(foo.sum() == 5);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
function same(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
function main() {
|
||||
var obj = {};
|
||||
assert(same({}, {}) == false);
|
||||
assert(same(obj, obj) == true);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './foo';
|
|
@ -0,0 +1,26 @@
|
|||
// This file is not generated,
|
||||
// but should be in the future.
|
||||
//
|
||||
// Problems:
|
||||
// - Dart requires annotations to be const (which makes sense).
|
||||
// Right now, I can't describe that in ES6.
|
||||
// - operator mapping `is`/`instanceof` is not yet implemented
|
||||
import 'dart:mirrors';
|
||||
|
||||
import '../annotations_spec.dart';
|
||||
|
||||
class Provide {
|
||||
final token;
|
||||
const Provide(this.token);
|
||||
}
|
||||
|
||||
readAnnotation(clazz) {
|
||||
return reflectClass(clazz).metadata.first.reflectee;
|
||||
}
|
||||
|
||||
main() {
|
||||
// Assert `Foo` class has `Provide` annotation.
|
||||
// TODO(vojta): test this more.
|
||||
var clazz = readAnnotation(Foo);
|
||||
assert(clazz is Provide);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
class MapWrapper {
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export var Foo = 'FOO';
|
||||
export var Bar = 'BAR';
|
|
@ -0,0 +1,7 @@
|
|||
function sum(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function main() {
|
||||
assert(sum(1, 2) == 3);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import {Foo, Bar} from './foo';
|
||||
// import {Foo as F} from './fixtures/foo';
|
||||
import fooModule from './foo';
|
||||
|
||||
import {MapWrapper wraps Map} from './fixtures/facade';
|
||||
|
||||
import exportModule from './export';
|
||||
|
||||
import unittest from 'unittest/unittest';
|
||||
|
||||
function main() {
|
||||
assert(Foo == 'FOO');
|
||||
assert(Bar == 'BAR');
|
||||
// assert(F == 'FOO');
|
||||
assert(fooModule.Foo == 'FOO');
|
||||
assert(fooModule.Bar == 'BAR');
|
||||
|
||||
assert(exportModule.Foo == 'FOO');
|
||||
assert(exportModule.Bar == 'BAR');
|
||||
|
||||
assert(unittest.PASS != null);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import 'package:unittest/unittest.dart';
|
||||
|
||||
<% files.forEach(function(file, index) { %>
|
||||
import '<%= file %>' as spec<%=index%>;
|
||||
<% }); %>
|
||||
|
||||
void main() {
|
||||
<% files.forEach(function(file, index) { %>
|
||||
test('<%= file %>', () {
|
||||
spec<%= index %>.main();
|
||||
});
|
||||
<% }); %>
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
function sum(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function not(a: boolean): boolean {
|
||||
return !a;
|
||||
}
|
||||
|
||||
function generics(a: A<Test>) {
|
||||
|
||||
}
|
||||
|
||||
function namedObjectType({a,b}:{a:A,b:B<C>}) {
|
||||
|
||||
}
|
||||
|
||||
class Bar {
|
||||
@CONST constructor({
|
||||
selector,
|
||||
lightDomServices,
|
||||
implementsTypes
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
constructor(a: number, b: number) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
sum(): number {
|
||||
return this.a + this.b;
|
||||
}
|
||||
|
||||
typedVariables() {
|
||||
// TODO(vojta): test this
|
||||
var foo:string = 'foo';
|
||||
var typed:bool, untyped;
|
||||
var oneTyped:string = 'one',
|
||||
another: bool = true;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
// TODO(vojta): test this better.
|
||||
var f = new Foo(1, 2);
|
||||
assert(f.sum() == 3);
|
||||
|
||||
f.typedVariables();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import {ParseTree} from 'traceur/src/syntax/trees/ParseTree';
|
||||
|
||||
var CLASS_FIELD = 'CLASS_FIELD';
|
||||
|
||||
export class ClassFieldParseTree extends ParseTree {
|
||||
constructor(location, identifier, typeAnnotation) {
|
||||
this.location = location;
|
||||
this.identifier = identifier;
|
||||
this.typeAnnotation = typeAnnotation;
|
||||
}
|
||||
get type() {
|
||||
return CLASS_FIELD;
|
||||
}
|
||||
visit(visitor) {
|
||||
visitor.visitClassField(this);
|
||||
}
|
||||
transform(transformer) {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import {Compiler as TraceurCompiler} from 'traceur/src/Compiler';
|
||||
import {ClassTransformer} from './dart_class_transformer';
|
||||
import {DartTreeWriter} from './dart_writer';
|
||||
import {CollectingErrorReporter} from 'traceur/src/util/CollectingErrorReporter';
|
||||
import {Parser} from './parser';
|
||||
import {SourceFile} from 'traceur/src/syntax/SourceFile';
|
||||
import {
|
||||
options as traceurOptions
|
||||
} from 'traceur/src/Options';
|
||||
|
||||
export class Compiler extends TraceurCompiler {
|
||||
constructor(options, sourceRoot) {
|
||||
super(options, sourceRoot);
|
||||
}
|
||||
compile(source, filename) {
|
||||
var parsed = this.parse(source, filename || '<unknown_file>');
|
||||
if (this.options_.outputLanguage === 'dart') {
|
||||
return this.writeDart(this.transformDart(parsed), filename);
|
||||
} else {
|
||||
return this.write(this.transform(parsed));
|
||||
}
|
||||
}
|
||||
transformDart(tree) {
|
||||
var transformer = new ClassTransformer();
|
||||
return transformer.transformAny(tree);
|
||||
}
|
||||
writeDart(tree, filename) {
|
||||
var writer = new DartTreeWriter();
|
||||
writer.visitAny(tree);
|
||||
// TODO: Do this in the writer...
|
||||
var library = 'library '+this.resolveModuleName(filename).replace(/\//g, '.')+';\n';
|
||||
return library + writer.toString();
|
||||
}
|
||||
// Copy of the original method to use our custom Parser
|
||||
parse(content, sourceName) {
|
||||
if (!content) {
|
||||
throw new Error('Compiler: no content to compile.');
|
||||
} else if (!sourceName) {
|
||||
throw new Error('Compiler: no source name for content.');
|
||||
}
|
||||
|
||||
this.sourceMapGenerator_ = null;
|
||||
// Here we mutate the global/module options object to be used in parsing.
|
||||
traceurOptions.setFromObject(this.options_);
|
||||
|
||||
var errorReporter = new CollectingErrorReporter();
|
||||
sourceName = this.sourceName(sourceName);
|
||||
var sourceFile = new SourceFile(sourceName, content);
|
||||
var parser = new Parser(sourceFile, errorReporter);
|
||||
var tree =
|
||||
this.options_.script ? parser.parseScript() : parser.parseModule();
|
||||
this.throwIfErrors(errorReporter);
|
||||
return tree;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
import {ParseTreeTransformer} from 'traceur/src/codegeneration/ParseTreeTransformer';
|
||||
import {createVariableStatement, createCallExpression, createIdentifierExpression, createArgumentList} from 'traceur/src/codegeneration/ParseTreeFactory';
|
||||
|
||||
// var token = traceur.syntax.TokenType;
|
||||
// var CONSTRUCTOR = token.CONSTRUCTOR;
|
||||
|
||||
import {PROPERTY_METHOD_ASSIGNMENT, MEMBER_EXPRESSION, THIS_EXPRESSION, BINARY_EXPRESSION} from 'traceur/src/syntax/trees/ParseTreeType';
|
||||
import {EQUAL_EQUAL_EQUAL} from 'traceur/src/syntax/TokenType';
|
||||
import {CONSTRUCTOR} from 'traceur/src/syntax/PredefinedName';
|
||||
|
||||
import {VariableStatement, VariableDeclarationList} from 'traceur/src/syntax/trees/ParseTrees';
|
||||
|
||||
import {propName} from 'traceur/src/staticsemantics/PropName';
|
||||
|
||||
import {ClassFieldParseTree} from './ast/class_field';
|
||||
|
||||
// - rename constructor (name of the class - default Dart constructor)
|
||||
export class ClassTransformer extends ParseTreeTransformer {
|
||||
// Transform multi-var declarations, into multiple statements:
|
||||
// var x, y;
|
||||
// ==>
|
||||
// var x;
|
||||
// var y;
|
||||
// TODO(vojta): move this into a separate transformer.
|
||||
|
||||
// Individual item transformer can return an array of items.
|
||||
// This is used in `transformVariableStatement`.
|
||||
// Otherwise this is copy/pasted from `ParseTreeTransformer`.
|
||||
transformList(list) {
|
||||
var transformedList = [];
|
||||
var transformedItem = null;
|
||||
|
||||
for (var i = 0, ii = list.length; i < ii; i++) {
|
||||
transformedItem = this.transformAny(list[i]);
|
||||
if (Array.isArray(transformedItem)) {
|
||||
transformedList = transformedList.concat(transformedItem);
|
||||
} else {
|
||||
transformedList.push(transformedItem);
|
||||
}
|
||||
}
|
||||
|
||||
return transformedList;
|
||||
}
|
||||
|
||||
transformVariableStatement(tree) {
|
||||
var declarations = tree.declarations.declarations;
|
||||
|
||||
if (declarations.length === 1 || declarations.length === 0) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
// Multiple var declaration, we will split it into multiple statements.
|
||||
// TODO(vojta): We can leave the multi-definition as long as they are all the same type/untyped.
|
||||
return declarations.map(function(declaration) {
|
||||
return new VariableStatement(tree.location, new VariableDeclarationList(tree.location,
|
||||
tree.declarations.declarationType, [declaration]));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Transform triple equals into identical() call.
|
||||
// TODO(vojta): move to a separate transformer
|
||||
transformBinaryExpression(tree) {
|
||||
if (tree.operator.type === EQUAL_EQUAL_EQUAL) {
|
||||
// a === b -> identical(a, b)
|
||||
return createCallExpression(createIdentifierExpression('identical'), createArgumentList([tree.left, tree.right]));
|
||||
}
|
||||
|
||||
return tree;
|
||||
};
|
||||
|
||||
transformClassDeclaration(tree) {
|
||||
var className = tree.name.identifierToken.toString();
|
||||
var argumentTypesMap = {};
|
||||
var fields = [];
|
||||
|
||||
tree.elements.forEach(function(elementTree) {
|
||||
if (elementTree.type === PROPERTY_METHOD_ASSIGNMENT &&
|
||||
!elementTree.isStatic &&
|
||||
propName(elementTree) === CONSTRUCTOR) {
|
||||
|
||||
// Store constructor argument types,
|
||||
// so that we can use them to set the types of simple-assigned fields.
|
||||
elementTree.parameterList.parameters.forEach(function(p) {
|
||||
var binding = p.parameter.binding;
|
||||
if (binding.identifierToken) {
|
||||
argumentTypesMap[binding.identifierToken.value] = p.typeAnnotation;
|
||||
}
|
||||
});
|
||||
|
||||
// Rename "constructor" to the class name.
|
||||
elementTree.name.literalToken.value = className;
|
||||
|
||||
// Collect all fields, defined in the constructor.
|
||||
elementTree.body.statements.forEach(function(statement) {
|
||||
if (statement.expression.type === BINARY_EXPRESSION &&
|
||||
statement.expression.operator.type === '=' &&
|
||||
statement.expression.left.type === MEMBER_EXPRESSION &&
|
||||
statement.expression.left.operand.type === THIS_EXPRESSION) {
|
||||
|
||||
var typeAnnotation = argumentTypesMap[statement.expression.left.memberName.value] || null;
|
||||
fields.push(new ClassFieldParseTree(tree.location, statement.expression.left.memberName, typeAnnotation));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add the field definitions to the begining of the class.
|
||||
tree.elements = fields.concat(tree.elements);
|
||||
|
||||
return super(tree);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
import {CONSTRUCTOR, FROM} from 'traceur/src/syntax/PredefinedName';
|
||||
import {EQUAL_EQUAL_EQUAL, OPEN_PAREN, CLOSE_PAREN, IMPORT, SEMI_COLON, STAR, OPEN_CURLY, CLOSE_CURLY, COMMA, AT, EQUAL} from 'traceur/src/syntax/TokenType';
|
||||
|
||||
import {ParseTreeWriter as JavaScriptParseTreeWriter} from 'traceur/src/outputgeneration/ParseTreeWriter';
|
||||
|
||||
export class DartTreeWriter extends JavaScriptParseTreeWriter {
|
||||
|
||||
// VARIABLES - types
|
||||
// ```
|
||||
// var foo:bool = true;
|
||||
// ==>
|
||||
// bool foo = true;
|
||||
// ```
|
||||
visitVariableDeclarationList(tree) {
|
||||
// Write `var`, only if no type declaration.
|
||||
if (!tree.declarations[0].typeAnnotation) {
|
||||
this.write_(tree.declarationType);
|
||||
this.writeSpace_();
|
||||
}
|
||||
|
||||
this.writeList_(tree.declarations, COMMA, true, 2);
|
||||
}
|
||||
|
||||
visitVariableDeclaration(tree) {
|
||||
this.writeType_(tree.typeAnnotation);
|
||||
this.visitAny(tree.lvalue);
|
||||
|
||||
if (tree.initializer !== null) {
|
||||
this.writeSpace_();
|
||||
this.write_(EQUAL);
|
||||
this.writeSpace_();
|
||||
this.visitAny(tree.initializer);
|
||||
}
|
||||
}
|
||||
|
||||
// FUNCTIONS
|
||||
// - remove the "function" keyword
|
||||
// - type annotation infront
|
||||
visitFunction_(tree) {
|
||||
this.writeAnnotations_(tree.annotations);
|
||||
if (tree.isAsyncFunction()) {
|
||||
this.write_(tree.functionKind);
|
||||
}
|
||||
|
||||
if (tree.isGenerator()) {
|
||||
this.write_(tree.functionKind);
|
||||
}
|
||||
|
||||
if (tree.name) {
|
||||
this.writeType_(tree.typeAnnotation);
|
||||
this.visitAny(tree.name);
|
||||
}
|
||||
|
||||
this.write_(OPEN_PAREN);
|
||||
this.visitAny(tree.parameterList);
|
||||
this.write_(CLOSE_PAREN);
|
||||
this.writeSpace_();
|
||||
this.visitAny(tree.body);
|
||||
};
|
||||
|
||||
// Class methods.
|
||||
// - type annotation infront
|
||||
visitPropertyMethodAssignment(tree) {
|
||||
this.writeAnnotations_(tree.annotations);
|
||||
|
||||
if (tree.isStatic) {
|
||||
this.write_(STATIC);
|
||||
this.writeSpace_();
|
||||
}
|
||||
|
||||
if (tree.isGenerator()) {
|
||||
this.write_(STAR);
|
||||
}
|
||||
|
||||
if (tree.isAsyncFunction()) {
|
||||
this.write_(ASYNC);
|
||||
}
|
||||
|
||||
this.writeType_(tree.typeAnnotation);
|
||||
this.visitAny(tree.name);
|
||||
this.write_(OPEN_PAREN);
|
||||
this.visitAny(tree.parameterList);
|
||||
this.write_(CLOSE_PAREN);
|
||||
this.writeSpace_();
|
||||
this.visitAny(tree.body);
|
||||
}
|
||||
|
||||
normalizeType_(typeName) {
|
||||
if (typeName === 'number') {
|
||||
return 'int';
|
||||
}
|
||||
|
||||
if (typeName === 'boolean') {
|
||||
return 'bool';
|
||||
}
|
||||
|
||||
if (typeName === 'string') {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
// FUNCTION/METHOD ARGUMENTS
|
||||
// - type infront of the arg name
|
||||
visitBindingElement(tree) {
|
||||
// TODO(vojta): This is awful, just copy/pasted from Traceur,
|
||||
// we should still clean it up.
|
||||
var typeAnnotation = this.currentParameterTypeAnnotation_;
|
||||
// resetting type annotation so it doesn't filter down recursively
|
||||
this.currentParameterTypeAnnotation_ = null;
|
||||
|
||||
this.writeType_(typeAnnotation);
|
||||
this.visitAny(tree.binding);
|
||||
|
||||
if (tree.initializer) {
|
||||
this.writeSpace_();
|
||||
this.write_(EQUAL);
|
||||
this.writeSpace_();
|
||||
this.visitAny(tree.initializer);
|
||||
}
|
||||
}
|
||||
|
||||
visitClassField(tree) {
|
||||
this.writeType_(tree.typeAnnotation);
|
||||
|
||||
if (!tree.typeAnnotation) {
|
||||
this.write_('var ');
|
||||
}
|
||||
|
||||
this.write_(tree.identifier);
|
||||
this.write_(SEMI_COLON);
|
||||
}
|
||||
|
||||
writeType_(typeAnnotation) {
|
||||
if (!typeAnnotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(vojta): Figure out why `typeAnnotation` has different structure when used with a variable.
|
||||
// This should probably be fixed in Traceur.
|
||||
var typeName = typeAnnotation.typeToken && typeAnnotation.typeToken.value || (typeAnnotation.name && typeAnnotation.name.value) || null;
|
||||
|
||||
if (!typeName) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.write_(this.normalizeType_(typeName));
|
||||
this.writeSpace_();
|
||||
}
|
||||
|
||||
// EXPORTS
|
||||
visitExportDeclaration(tree) {
|
||||
if (tree.declaration.moduleSpecifier) {
|
||||
this.write_('export ');
|
||||
this.visitModuleSpecifier(tree.declaration.moduleSpecifier);
|
||||
this.write_(SEMI_COLON);
|
||||
} else {
|
||||
// remove "export"
|
||||
this.writeAnnotations_(tree.annotations);
|
||||
this.visitAny(tree.declaration);
|
||||
}
|
||||
}
|
||||
|
||||
// visitExportDefault
|
||||
// visitNamedExport
|
||||
// visitExportSpecifier
|
||||
// visitExportSpecifierSet
|
||||
// visitExportStar
|
||||
|
||||
|
||||
// IMPORTS
|
||||
visitImportDeclaration(tree) {
|
||||
this.write_(IMPORT);
|
||||
this.writeSpace_();
|
||||
this.visitAny(tree.moduleSpecifier);
|
||||
|
||||
if (tree.importClause.binding) {
|
||||
// Default import - import the entire module.
|
||||
// import foo from './bar';
|
||||
this.write_(' as ');
|
||||
this.visitAny(tree.importClause.binding);
|
||||
} else {
|
||||
// Regular - import list of members.
|
||||
// import {Foo, Bar} from './baz';
|
||||
this.visitAny(tree.importClause);
|
||||
}
|
||||
|
||||
this.write_(SEMI_COLON);
|
||||
}
|
||||
|
||||
// Translate './foo' -> './foo.dart'
|
||||
transformModuleUrl(url) {
|
||||
var prefix = url.charAt(1) === '.' ? '' : 'package:';
|
||||
return "'" + prefix + url.substring(1, url.length - 1) + ".dart'";
|
||||
}
|
||||
|
||||
visitModuleSpecifier(tree) {
|
||||
this.write_(this.transformModuleUrl(tree.token.value));
|
||||
}
|
||||
|
||||
visitImportSpecifier(tree) {
|
||||
if (tree.name) {
|
||||
throw new Error('"as" syntax not supported');
|
||||
}
|
||||
this.visitAny(tree.binding);
|
||||
}
|
||||
|
||||
visitImportSpecifierSet(tree) {
|
||||
if (tree.specifiers.type == STAR) {
|
||||
throw new Error('"*" syntax not supported');
|
||||
} else {
|
||||
this.write_(' show ');
|
||||
this.writeList_(tree.specifiers, COMMA, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ANNOTATIONS
|
||||
// TODO(vojta): this is just fixing a bug in Traceur, send a PR.
|
||||
visitAnnotation(tree) {
|
||||
if (tree.name.identifierToken) {
|
||||
var nameValue = tree.name.identifierToken.value;
|
||||
if (nameValue === nameValue.toUpperCase()) {
|
||||
// control annotations for js2dart
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.write_(AT);
|
||||
this.visitAny(tree.name);
|
||||
|
||||
if (tree.args !== null) {
|
||||
this.write_(OPEN_PAREN);
|
||||
this.writeList_(tree.args.args, COMMA, false);
|
||||
this.write_(CLOSE_PAREN);
|
||||
}
|
||||
|
||||
this.writeSpace_()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import {Parser as TraceurParser} from 'traceur/src/syntax/Parser';
|
||||
import {SyntaxErrorReporter} from 'traceur/src/util/SyntaxErrorReporter';
|
||||
import {TypeName, ImportSpecifier, ImportedBinding, BindingIdentifier} from 'traceur/src/syntax/trees/ParseTrees';
|
||||
import {PERIOD, IMPORT, STAR, AS, FROM, CLOSE_ANGLE, OPEN_ANGLE, COMMA, OPEN_CURLY, CLOSE_CURLY, COLON} from 'traceur/src/syntax/TokenType';
|
||||
|
||||
var WRAPS = 'wraps';
|
||||
|
||||
export class Parser extends TraceurParser {
|
||||
constructor(file, errorReporter = new SyntaxErrorReporter()) {
|
||||
super(file, errorReporter);
|
||||
}
|
||||
parseTypeName_() {
|
||||
// Copy of original implementation
|
||||
var start = this.getTreeStartLocation_();
|
||||
var typeName = new TypeName(this.getTreeLocation_(start), null, this.eatId_());
|
||||
while (this.eatIf_(PERIOD)) {
|
||||
var memberName = this.eatIdName_();
|
||||
typeName = new TypeName(this.getTreeLocation_(start), typeName, memberName);
|
||||
}
|
||||
var next = this.peekType_();
|
||||
// Generics support
|
||||
if (this.eatIf_(OPEN_ANGLE)) {
|
||||
var generics = [];
|
||||
do {
|
||||
generics.push(this.eatId_());
|
||||
} while(this.eatIf_(COMMA));
|
||||
this.eat_(CLOSE_ANGLE);
|
||||
// TODO: save the generics into the typeName and use them e.g. for assertions, ...
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
parseImportSpecifier_() {
|
||||
// Copy of original implementation
|
||||
var start = this.getTreeStartLocation_();
|
||||
var token = this.peekToken_();
|
||||
var isKeyword = token.isKeyword();
|
||||
var binding;
|
||||
var name = this.eatIdName_();
|
||||
// Support for wraps keywoard
|
||||
if (this.peekToken_().value === WRAPS) {
|
||||
var token = this.nextToken_();
|
||||
var wrappedIdentifier = this.eatId_();
|
||||
// TODO: Save the fact that this is a wrapper type and
|
||||
// also the wrapped type
|
||||
}
|
||||
// Copy of original implementation
|
||||
if (isKeyword || this.peekPredefinedString_(AS)) {
|
||||
this.eatId_(AS);
|
||||
binding = this.parseImportedBinding_();
|
||||
} else {
|
||||
binding = new ImportedBinding(name.location, new BindingIdentifier(name.location, name));
|
||||
name = null;
|
||||
}
|
||||
return new ImportSpecifier(this.getTreeLocation_(start), binding, name);
|
||||
}
|
||||
parseObjectType_() {
|
||||
//TODO(misko): save the type information
|
||||
this.eat_(OPEN_CURLY)
|
||||
do {
|
||||
var identifier = this.eatId_();
|
||||
this.eat_(COLON);
|
||||
var type = this.parseNamedOrPredefinedType_();
|
||||
} while (this.eatIf_(COMMA));
|
||||
this.eat_(CLOSE_CURLY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Asserting APIs:
|
||||
// - generated by Traceur (based on type annotations)
|
||||
// - can be also used in tests for instance
|
||||
assert.type(something, Type);
|
||||
assert.returnType(returnValue, Type);
|
||||
assert.argumentTypes(firstArg, Type, secondArg, Type);
|
||||
|
||||
// this can be used anywhere in the code
|
||||
// (useful inside test, when we don't wanna define an interface)
|
||||
assert(value).is(...)
|
||||
|
||||
|
||||
// Custom type assert:
|
||||
// - i have a custom type
|
||||
// - adding an assert methos
|
||||
assert.define(MyUser, function(value) {
|
||||
assert(value).is(Type, Type2); // or
|
||||
assert(value, 'name').is(assert.string);
|
||||
assert(value, 'contact').is(assert.structure({
|
||||
email: assert.string,
|
||||
cell: assert.string
|
||||
}));
|
||||
assert(value, 'contacts').is(assert.arrayOf(assert.structure({email: assert.string})));
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Define interface (an empty type with assert method)
|
||||
// - returns an empty class with assert method
|
||||
var Email = assert.define('IEmail', function(value) {
|
||||
assert(value).is(String);
|
||||
|
||||
if (value.indexOf('@') !== -1) {
|
||||
assert.fail('has to contain "@"');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Predefined types
|
||||
assert.string
|
||||
assert.number
|
||||
assert.boolean
|
||||
assert.arrayOf(...types)
|
||||
assert.structure(object)
|
|
@ -0,0 +1 @@
|
|||
http://angular.github.io/assert/
|
|
@ -0,0 +1,37 @@
|
|||
var gulp = require('gulp');
|
||||
var pipe = require('pipe/gulp');
|
||||
var traceur = require('gulp-traceur');
|
||||
|
||||
|
||||
var path = {
|
||||
src: './src/**/*.js',
|
||||
};
|
||||
|
||||
|
||||
// TRANSPILE ES6
|
||||
gulp.task('build_source_amd', function() {
|
||||
gulp.src(path.src)
|
||||
.pipe(traceur(pipe.traceur()))
|
||||
.pipe(gulp.dest('dist/amd'));
|
||||
});
|
||||
|
||||
gulp.task('build_source_cjs', function() {
|
||||
gulp.src(path.src)
|
||||
.pipe(traceur(pipe.traceur({modules: 'commonjs'})))
|
||||
.pipe(gulp.dest('dist/cjs'));
|
||||
});
|
||||
|
||||
gulp.task('build_source_es6', function() {
|
||||
gulp.src(path.src)
|
||||
.pipe(traceur(pipe.traceur({outputLanguage: 'es6'})))
|
||||
.pipe(gulp.dest('dist/es6'));
|
||||
});
|
||||
|
||||
gulp.task('build_dist', ['build_source_cjs', 'build_source_amd', 'build_source_es6']);
|
||||
gulp.task('build', ['build_dist']);
|
||||
|
||||
|
||||
// WATCH FILES FOR CHANGES
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch(path.src, ['build']);
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
var sharedConfig = require('pipe/karma');
|
||||
|
||||
module.exports = function(config) {
|
||||
sharedConfig(config);
|
||||
|
||||
config.set({
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'test-main.js',
|
||||
|
||||
{pattern: 'src/**/*.js', included: false},
|
||||
{pattern: 'test/**/*.js', included: false}
|
||||
],
|
||||
|
||||
usePolling: true,
|
||||
|
||||
preprocessors: {
|
||||
'src/**/*.js': ['traceur'],
|
||||
'test/**/*.js': ['traceur']
|
||||
}
|
||||
});
|
||||
|
||||
config.sauceLabs.testName = 'assert';
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "rtts-assert",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"gulp-traceur": {
|
||||
"version": "0.4.0",
|
||||
"from": "gulp-traceur@0.4.0",
|
||||
"dependencies": {
|
||||
"gulp-util": {
|
||||
"version": "2.2.5",
|
||||
"from": "gulp-util@2.2.5"
|
||||
},
|
||||
"through2": {
|
||||
"version": "0.4.0",
|
||||
"from": "through2@0.4.0"
|
||||
},
|
||||
"traceur": {
|
||||
"version": "0.0..0",
|
||||
"from": "git://github.com/vojtajina/traceur-compiler#add-es6-pure-transformer-dist"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "rtts-assert",
|
||||
"version": "0.0.1",
|
||||
"description": "A type assertion library for Traceur.",
|
||||
"main": "./dist/cjs/assert.js",
|
||||
"homepage": "https://github.com/angular/assert",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/angular/assert.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/angular/assert/issues"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.5.6",
|
||||
"gulp-connect": "~1.0.5",
|
||||
"gulp-traceur": "~0.4.0",
|
||||
"karma": "^0.12.1",
|
||||
"karma-chrome-launcher": "^0.1.2",
|
||||
"karma-jasmine": "^0.2.2",
|
||||
"karma-requirejs": "^0.2.1",
|
||||
"karma-traceur-preprocessor": "^0.2.2",
|
||||
"pipe": "git://github.com/angular/pipe#remove-transitive-deps"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "karma start --single-run"
|
||||
},
|
||||
"author": "Vojta Jína <vojta.jina@gmail.com>",
|
||||
"license": "Apache-2.0"
|
||||
}
|
|
@ -0,0 +1,327 @@
|
|||
// TODO(vojta):
|
||||
// - extract into multiple files
|
||||
// - different error types
|
||||
// - simplify/humanize error messages
|
||||
// - throw when invalid input (such as odd number of args into assert.argumentTypes)
|
||||
|
||||
var POSITION_NAME = ['', '1st', '2nd', '3rd'];
|
||||
function argPositionName(i) {
|
||||
var position = (i / 2) + 1;
|
||||
|
||||
return POSITION_NAME[position] || (position + 'th');
|
||||
}
|
||||
|
||||
var primitives = $traceurRuntime.type;
|
||||
|
||||
function assertArgumentTypes(...params) {
|
||||
var actual, type;
|
||||
var currentArgErrors;
|
||||
var errors = [];
|
||||
var msg;
|
||||
|
||||
for (var i = 0, l = params.length; i < l; i = i + 2) {
|
||||
actual = params[i];
|
||||
type = params[i + 1];
|
||||
|
||||
currentArgErrors = [];
|
||||
|
||||
// currentStack = [];
|
||||
//
|
||||
|
||||
if (!isType(actual, type, currentArgErrors)) {
|
||||
|
||||
// console.log(JSON.stringify(errors, null, ' '));
|
||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||
errors.push(argPositionName(i) + ' argument has to be an instance of ' + prettyPrint(type) + ', got ' + prettyPrint(actual));
|
||||
if (currentArgErrors.length) {
|
||||
errors.push(currentArgErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
throw new Error('Invalid arguments given!\n' + formatErrors(errors));
|
||||
}
|
||||
}
|
||||
|
||||
function prettyPrint(value) {
|
||||
if (typeof value === 'undefined') {
|
||||
return 'undefined';
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return '"' + value + '"';
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
if (value.map) {
|
||||
return '[' + value.map(prettyPrint).join(', ') + ']';
|
||||
}
|
||||
|
||||
var properties = Object.keys(value);
|
||||
return '{' + properties.map((p) => p + ': ' + prettyPrint(value[p])).join(', ') + '}';
|
||||
}
|
||||
|
||||
return value.__assertName || value.name || value.toString();
|
||||
}
|
||||
|
||||
function isType(value, T, errors) {
|
||||
|
||||
if (T === primitives.void) {
|
||||
return typeof value === 'undefined';
|
||||
}
|
||||
|
||||
if (T === primitives.any || value === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (T === primitives.string) {
|
||||
return typeof value === 'string';
|
||||
}
|
||||
|
||||
if (T === primitives.number) {
|
||||
return typeof value === 'number';
|
||||
}
|
||||
|
||||
if (T === primitives.boolean) {
|
||||
return typeof value === 'boolean';
|
||||
}
|
||||
|
||||
// var parentStack = currentStack;
|
||||
// currentStack = [];
|
||||
|
||||
// shouldnt this create new stack?
|
||||
if (typeof T.assert === 'function') {
|
||||
var parentStack = currentStack;
|
||||
var isValid;
|
||||
currentStack = errors;
|
||||
try {
|
||||
isValid = T.assert(value) ;
|
||||
} catch (e) {
|
||||
fail(e.message);
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
currentStack = parentStack;
|
||||
|
||||
if (typeof isValid === 'undefined') {
|
||||
isValid = errors.length === 0;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
|
||||
// if (!currentStack.length) {
|
||||
// currentStack = parentStack;
|
||||
// return [];
|
||||
// }
|
||||
// var res = currentStack;
|
||||
// currentStack = parentStack;
|
||||
// return ['not instance of ' + prettyPrint(T), res];
|
||||
}
|
||||
|
||||
return value instanceof T;
|
||||
|
||||
// if (!(value instanceof T)) {
|
||||
// fail('not instance of ' + prettyPrint(T));
|
||||
// }
|
||||
|
||||
// var res = currentStack;
|
||||
// currentStack = parentStack;
|
||||
|
||||
// return res;
|
||||
}
|
||||
|
||||
function formatErrors(errors, indent = ' ') {
|
||||
return errors.map((e) => {
|
||||
if (typeof e === 'string') return indent + '- ' + e;
|
||||
return formatErrors(e, indent + ' ');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
|
||||
// assert a type of given value and throw if does not pass
|
||||
function type(actual, T) {
|
||||
var errors = [];
|
||||
// currentStack = [];
|
||||
|
||||
if (!isType(actual, T, errors)) {
|
||||
// console.log(JSON.stringify(errors, null, ' '));
|
||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||
var msg = 'Expected an instance of ' + prettyPrint(T) + ', got ' + prettyPrint(actual) + '!';
|
||||
if (errors.length) {
|
||||
msg += '\n' + formatErrors(errors);
|
||||
}
|
||||
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
function returnType(actual, T) {
|
||||
var errors = [];
|
||||
// currentStack = [];
|
||||
|
||||
if (!isType(actual, T, errors)) {
|
||||
// console.log(JSON.stringify(errors, null, ' '));
|
||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||
var msg = 'Expected to return an instance of ' + prettyPrint(T) + ', got ' + prettyPrint(actual) + '!';
|
||||
if (errors.length) {
|
||||
msg += '\n' + formatErrors(errors);
|
||||
}
|
||||
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
||||
|
||||
// TODO(vojta): define these with DSL?
|
||||
var string = define('string', function(value) {
|
||||
return typeof value === 'string';
|
||||
});
|
||||
|
||||
// function string() {}
|
||||
// string.assert = function(value) {
|
||||
// return typeof value === 'string';
|
||||
// };
|
||||
|
||||
var boolean = define('boolean', function(value) {
|
||||
return typeof value === 'boolean';
|
||||
});
|
||||
// function boolean() {}
|
||||
// boolean.assert = function(value) {
|
||||
// return typeof value === 'boolean';
|
||||
// };
|
||||
|
||||
var number = define('number', function(value) {
|
||||
return typeof value === 'number';
|
||||
});
|
||||
// function number() {}
|
||||
// number.assert = function(value) {
|
||||
// return typeof value === 'number';
|
||||
// };
|
||||
|
||||
|
||||
function arrayOf(...types) {
|
||||
return assert.define('array of ' + types.map(prettyPrint).join('/'), function(value) {
|
||||
if (assert(value).is(Array)) {
|
||||
for (var item of value) {
|
||||
assert(item).is(...types);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function structure(definition) {
|
||||
var properties = Object.keys(definition);
|
||||
return assert.define('object with properties ' + properties.join(', '), function(value) {
|
||||
if (assert(value).is(Object)) {
|
||||
for (var property of properties) {
|
||||
assert(value[property]).is(definition[property]);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// I'm sorry, bad global state... to make the API nice ;-)
|
||||
var currentStack = [];
|
||||
|
||||
function fail(message) {
|
||||
currentStack.push(message);
|
||||
}
|
||||
|
||||
function define(classOrName, check) {
|
||||
var cls = classOrName;
|
||||
|
||||
if (typeof classOrName === 'string') {
|
||||
cls = function() {};
|
||||
cls.__assertName = classOrName;
|
||||
}
|
||||
|
||||
cls.assert = function(value) {
|
||||
// var parentStack = currentStack;
|
||||
|
||||
// currentStack = [];
|
||||
|
||||
return check(value);
|
||||
|
||||
// if (currentStack.length) {
|
||||
// parentStack.push(currentStack)
|
||||
// }
|
||||
// currentStack = parentStack;
|
||||
};
|
||||
|
||||
return cls;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function assert(value) {
|
||||
return {
|
||||
is: function is(...types) {
|
||||
// var errors = []
|
||||
var allErrors = [];
|
||||
var errors;
|
||||
|
||||
for (var type of types) {
|
||||
errors = [];
|
||||
|
||||
if (isType(value, type, errors)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if no errors, merge multiple "is not instance of " into x/y/z ?
|
||||
allErrors.push(prettyPrint(value) + ' is not instance of ' + prettyPrint(type))
|
||||
if (errors.length) {
|
||||
allErrors.push(errors);
|
||||
}
|
||||
}
|
||||
|
||||
// if (types.length > 1) {
|
||||
// currentStack.push(['has to be ' + types.map(prettyPrint).join(' or '), ...allErrors]);
|
||||
// } else {
|
||||
currentStack.push(...allErrors);
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// PUBLIC API
|
||||
|
||||
// asserting API
|
||||
|
||||
// throw if no type provided
|
||||
assert.type = type;
|
||||
|
||||
// throw if odd number of args
|
||||
assert.argumentTypes = assertArgumentTypes;
|
||||
assert.returnType = returnType;
|
||||
|
||||
|
||||
// define AP;
|
||||
assert.define = define;
|
||||
assert.fail = fail;
|
||||
|
||||
// primitive value type;
|
||||
assert.string = string;
|
||||
assert.number = number;
|
||||
assert.boolean = boolean;
|
||||
|
||||
// custom types
|
||||
assert.arrayOf = arrayOf;
|
||||
assert.structure = structure;
|
||||
|
||||
|
||||
export {assert}
|
|
@ -0,0 +1,27 @@
|
|||
var allTestFiles = [];
|
||||
var TEST_REGEXP = /\.spec\.js$/;
|
||||
|
||||
var pathToModule = function(path) {
|
||||
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
|
||||
};
|
||||
|
||||
Object.keys(window.__karma__.files).forEach(function(file) {
|
||||
if (TEST_REGEXP.test(file)) {
|
||||
// Normalize paths to RequireJS module names.
|
||||
allTestFiles.push(pathToModule(file));
|
||||
}
|
||||
});
|
||||
|
||||
require.config({
|
||||
// Karma serves files under /base, which is the basePath from your config file
|
||||
baseUrl: '/base',
|
||||
paths: {
|
||||
'assert': 'src/assert'
|
||||
},
|
||||
|
||||
// Dynamically load all test files and ES6 polyfill.
|
||||
deps: allTestFiles,
|
||||
|
||||
// we have to kickoff jasmine, as it is asynchronous
|
||||
callback: window.__karma__.start
|
||||
});
|
|
@ -0,0 +1,377 @@
|
|||
// # Assert.js
|
||||
// A run-time type assertion library for JavaScript. Designed to be used with [Traceur](https://github.com/google/traceur-compiler).
|
||||
|
||||
|
||||
// - [Basic Type Check](#basic-type-check)
|
||||
// - [Custom Check](#custom-check)
|
||||
// - [Primitive Values](#primitive-values)
|
||||
// - [Describing more complex types](#describing-more-complex-types)
|
||||
// - [assert.arrayOf](#assert-arrayof)
|
||||
// - [assert.structure](#assert-structure)
|
||||
// - [Integrating with Traceur](#integrating-with-traceur)
|
||||
|
||||
import {assert} from 'assert';
|
||||
|
||||
|
||||
|
||||
// ## Basic Type Check
|
||||
// By default, `instanceof` is used to check the type.
|
||||
//
|
||||
// Note that you can use `assert.type()` in unit tests or anywhere in your code.
|
||||
// Most of the time, you will use it with Traceur.
|
||||
// Jump to the [Traceur section](#integrating-with-traceur) to see an example of that.
|
||||
describe('basic type check', function() {
|
||||
|
||||
class Type {}
|
||||
|
||||
it('should pass', function() {
|
||||
assert.type(new Type(), Type);
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => assert.type(123, Type))
|
||||
.toThrowError('Expected an instance of Type, got 123!');
|
||||
});
|
||||
|
||||
|
||||
it('should allow null', function() {
|
||||
assert.type(null, Type);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ## Custom Check
|
||||
// Often, `instanceof` is not flexible enough.
|
||||
// In that case, your type can define its own `assert` method which will be used instead.
|
||||
//
|
||||
// See [Describing More Complex Types](#describing-more-complex-types) for examples how to
|
||||
// define custom checks using `assert.define()`.
|
||||
describe('custom check', function() {
|
||||
|
||||
class Type {}
|
||||
|
||||
// the basic check can just return true/false, without specifying any reason
|
||||
it('should pass when returns true', function() {
|
||||
Type.assert = function(value) {
|
||||
return true;
|
||||
};
|
||||
|
||||
assert.type({}, Type);
|
||||
});
|
||||
|
||||
|
||||
it('should fail when returns false', function() {
|
||||
Type.assert = function(value) {
|
||||
return false;
|
||||
};
|
||||
|
||||
expect(() => assert.type({}, Type))
|
||||
.toThrowError('Expected an instance of Type, got {}!');
|
||||
});
|
||||
|
||||
|
||||
// Using `assert.fail()` allows to report even multiple errors.
|
||||
it('should fail when calls assert.fail()', function() {
|
||||
Type.assert = function(value) {
|
||||
assert.fail('not smart enough');
|
||||
assert.fail('not blue enough');
|
||||
};
|
||||
|
||||
expect(() => assert.type({}, Type))
|
||||
.toThrowError('Expected an instance of Type, got {}!\n' +
|
||||
' - not smart enough\n' +
|
||||
' - not blue enough');
|
||||
});
|
||||
|
||||
|
||||
it('should fail when throws an exception', function() {
|
||||
Type.assert = function(value) {
|
||||
throw new Error('not long enough');
|
||||
};
|
||||
|
||||
expect(function() {
|
||||
assert.type(12345, Type);
|
||||
}).toThrowError('Expected an instance of Type, got 12345!\n' +
|
||||
' - not long enough');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ## Primitive Values
|
||||
// You don't want to check primitive values (such as strings, numbers, or booleans) using `typeof` rather than
|
||||
// `instanceof`.
|
||||
//
|
||||
// Again, you probably won't write this code and rather use Traceur to do it for you, simply based on type annotations.
|
||||
describe('primitive value check', function() {
|
||||
var primitive = $traceurRuntime.type;
|
||||
|
||||
describe('string', function() {
|
||||
|
||||
it('should pass', function() {
|
||||
assert.type('xxx', primitive.string);
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => assert.type(12345, primitive.string))
|
||||
.toThrowError('Expected an instance of string, got 12345!');
|
||||
});
|
||||
|
||||
it('should allow null', function() {
|
||||
assert.type(null, primitive.string);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('number', function() {
|
||||
|
||||
it('should pass', function() {
|
||||
assert.type(123, primitive.number);
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => assert.type(false, primitive.number))
|
||||
.toThrowError('Expected an instance of number, got false!');
|
||||
});
|
||||
|
||||
it('should allow null', function() {
|
||||
assert.type(null, primitive.number);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('boolean', function() {
|
||||
|
||||
it('should pass', function() {
|
||||
assert.type(true, primitive.boolean);
|
||||
assert.type(false, primitive.boolean);
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => assert.type(123, primitive.boolean))
|
||||
.toThrowError('Expected an instance of boolean, got 123!');
|
||||
});
|
||||
|
||||
it('should allow null', function() {
|
||||
assert.type(null, primitive.boolean);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ## Describing more complex types
|
||||
//
|
||||
// Often, a simple type check using `instanceof` or `typeof` is not enough.
|
||||
// That's why you can define custom checks using this DSL.
|
||||
// The goal was to make them easy to compose and as descriptive as possible.
|
||||
// Of course you can write your own DSL on the top of this.
|
||||
describe('define', function() {
|
||||
|
||||
// If the first argument to `assert.define()` is a type (function), it will define `assert` method on that function.
|
||||
//
|
||||
// In this example, being a type of Type means being a either a function or object.
|
||||
it('should define assert for an existing type', function() {
|
||||
class Type {}
|
||||
|
||||
assert.define(Type, function(value) {
|
||||
assert(value).is(Function, Object);
|
||||
});
|
||||
|
||||
assert.type({}, Type);
|
||||
assert.type(function() {}, Type);
|
||||
expect(() => assert.type('str', Type))
|
||||
.toThrowError('Expected an instance of Type, got "str"!\n' +
|
||||
' - "str" is not instance of Function\n' +
|
||||
' - "str" is not instance of Object');
|
||||
});
|
||||
|
||||
|
||||
// If the first argument to `assert.define()` is a string,
|
||||
// it will create an interface - basically an empty class with `assert` method.
|
||||
it('should define an interface', function() {
|
||||
var User = assert.define('MyUser', function(user) {
|
||||
assert(user).is(Object);
|
||||
});
|
||||
|
||||
assert.type({}, User);
|
||||
expect(() => assert.type(12345, User))
|
||||
.toThrowError('Expected an instance of MyUser, got 12345!\n' +
|
||||
' - 12345 is not instance of Object');
|
||||
});
|
||||
|
||||
|
||||
// Here are a couple of more APIs to describe your custom types...
|
||||
//
|
||||
// ### assert.arrayOf
|
||||
// Checks if the value is an array and if so, it checks whether all the items are one the given types.
|
||||
// These types can be composed types, not just simple ones.
|
||||
describe('arrayOf', function() {
|
||||
|
||||
var Titles = assert.define('ListOfTitles', function(value) {
|
||||
assert(value).is(assert.arrayOf(assert.string, assert.number));
|
||||
});
|
||||
|
||||
it('should pass', function () {
|
||||
assert.type(['one', 55, 'two'], Titles);
|
||||
});
|
||||
|
||||
|
||||
it('should fail when non-array given', function () {
|
||||
expect(() => assert.type('foo', Titles))
|
||||
.toThrowError('Expected an instance of ListOfTitles, got "foo"!\n' +
|
||||
' - "foo" is not instance of array of string/number\n' +
|
||||
' - "foo" is not instance of Array');
|
||||
});
|
||||
|
||||
|
||||
it('should fail when an invalid item in the array', function () {
|
||||
expect(() => assert.type(['aaa', true], Titles))
|
||||
.toThrowError('Expected an instance of ListOfTitles, got ["aaa", true]!\n' +
|
||||
' - ["aaa", true] is not instance of array of string/number\n' +
|
||||
' - true is not instance of string\n' +
|
||||
' - true is not instance of number');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ### assert.structure
|
||||
// Similar to `assert.arrayOf` which checks a content of an array,
|
||||
// `assert.structure` checks if the value is an object with specific properties.
|
||||
describe('structure', function() {
|
||||
|
||||
var User = assert.define('MyUser', function(value) {
|
||||
assert(value).is(assert.structure({
|
||||
name: assert.string,
|
||||
age: assert.number
|
||||
}));
|
||||
});
|
||||
|
||||
it('should pass', function () {
|
||||
assert.type({name: 'Vojta', age: 28}, User);
|
||||
});
|
||||
|
||||
|
||||
it('should fail when non-object given', function () {
|
||||
expect(() => assert.type(123, User))
|
||||
.toThrowError('Expected an instance of MyUser, got 123!\n' +
|
||||
' - 123 is not instance of object with properties name, age\n' +
|
||||
' - 123 is not instance of Object');
|
||||
});
|
||||
|
||||
|
||||
it('should fail when an invalid property', function () {
|
||||
expect(() => assert.type({name: 'Vojta', age: true}, User))
|
||||
.toThrowError('Expected an instance of MyUser, got {name: "Vojta", age: true}!\n' +
|
||||
' - {name: "Vojta", age: true} is not instance of object with properties name, age\n' +
|
||||
' - true is not instance of number');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// ## Integrating with Traceur
|
||||
//
|
||||
// Manually calling `assert.type()` in your code is cumbersome. Most of the time, you'll want to
|
||||
// have Traceur add the calls to `assert.type()` to your code based on type annotations.
|
||||
//
|
||||
// This has several advantages:
|
||||
// - it's shorter and nicer,
|
||||
// - you can easily ignore it when generating production code.
|
||||
//
|
||||
// You'll need to run Traceur with `--types=true --type-assertions=true --type-assertion-module="path/to/assert"`.
|
||||
describe('Traceur', function() {
|
||||
|
||||
describe('arguments', function() {
|
||||
|
||||
function reverse(str: string) {
|
||||
return str ? reverse(str.substring(1)) + str[0] : ''
|
||||
}
|
||||
|
||||
it('should pass', function() {
|
||||
expect(reverse('angular')).toBe('ralugna');
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => reverse(123))
|
||||
.toThrowError('Invalid arguments given!\n' +
|
||||
' - 1st argument has to be an instance of string, got 123');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('return value', function() {
|
||||
|
||||
function foo(bar): number {
|
||||
return bar;
|
||||
}
|
||||
|
||||
it('should pass', function() {
|
||||
expect(foo(123)).toBe(123);
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => foo('bar'))
|
||||
.toThrowError('Expected to return an instance of number, got "bar"!');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('variables', function() {
|
||||
|
||||
it('should pass', function() {
|
||||
var count:number = 1;
|
||||
});
|
||||
|
||||
|
||||
it('should fail', function() {
|
||||
expect(() => {
|
||||
var count: number = true;
|
||||
}).toThrowError('Expected an instance of number, got true!');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('void', function() {
|
||||
function foo(bar): void {
|
||||
return bar;
|
||||
}
|
||||
|
||||
it('should pass when not defined', function() {
|
||||
function nonReturn(): void {}
|
||||
function returnNothing(): void { return; }
|
||||
function returnUndefined(): void { return undefined; }
|
||||
|
||||
foo();
|
||||
foo(undefined);
|
||||
nonReturn();
|
||||
returnNothing();
|
||||
returnUndefined();
|
||||
});
|
||||
|
||||
|
||||
it('should fail when a value returned', function() {
|
||||
expect(() => foo('bar'))
|
||||
.toThrowError('Expected to return an instance of voidType, got "bar"!');
|
||||
});
|
||||
|
||||
|
||||
it('should fail when null returned', function() {
|
||||
expect(() => foo(null))
|
||||
.toThrowError('Expected to return an instance of voidType, got null!');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// <center><small>
|
||||
// This documentation was generated from [assert.spec.js](https://github.com/vojtajina/assert/blob/master/test/assert.spec.js) using [Docco](http://jashkenas.github.io/docco/).
|
||||
// </small></center>
|
Loading…
Reference in New Issue