Socket
Socket
Sign inDemoInstall

catharsis

Package Overview
Dependencies
0
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.1 to 0.4.0

test/specs/html/html.js

70

catharsis.js
/**
* catharsis 0.3.1
* catharsis 0.4.0
* A parser for Google Closure Compiler type expressions, powered by PEG.js.

@@ -15,19 +15,49 @@ *

var typeExpressionCache = {};
var lenientTypeExpressionCache = {};
var parsedTypeCache = {};
var lenientParsedTypeCache = {};
function cachedParse(expr) {
if (!typeExpressionCache[expr]) {
typeExpressionCache[expr] = parse(expr);
function cachedParse(expr, options) {
var cache = options.lenient ? lenientTypeExpressionCache : typeExpressionCache;
var parsedType;
if (options.useCache !== false && cache[expr]) {
return cache[expr];
} else {
parsedType = parse(expr);
Object.defineProperties(parsedType, {
typeExpression: {
value: expr
},
lenient: {
value: options.lenient === true ? true : false
}
});
parsedType = Object.freeze(parsedType);
if (options.useCache !== false) {
cache[expr] = parsedType;
}
return parsedType;
}
return typeExpressionCache[expr];
}
function cachedStringify(parsedType) {
var json = JSON.stringify(parsedType);
if (!parsedTypeCache[json]) {
parsedTypeCache[json] = stringify(parsedType);
function cachedStringify(parsedType, options) {
var cache = options.lenient ? lenientParsedTypeCache : parsedTypeCache;
var json;
if (options.useCache !== false && Object.prototype.hasOwnProperty.call(parsedType,
'typeExpression')) {
// return the original type expression
return parsedType.typeExpression;
} else if (options.useCache !== false) {
json = JSON.stringify(parsedType);
cache[json] = cache[json] || stringify(parsedType);
return cache[json];
} else {
return stringify(parsedType);
}
return parsedTypeCache[json];
}

@@ -39,15 +69,15 @@

Catharsis.prototype.parse = function(type, opts) {
opts = opts || {};
Catharsis.prototype.parse = function(typeExpr, options) {
options = options || {};
return opts.useCache !== false ? cachedParse(type) : parse(type);
return cachedParse(typeExpr, options);
};
Catharsis.prototype.stringify = function(parsedType, opts) {
opts = opts || {};
Catharsis.prototype.stringify = function(parsedType, options) {
options = options || {};
var result;
result = opts.useCache !== false ? cachedStringify(parsedType) : stringify(parsedType);
if (opts.validate) {
this.parse(result);
result = cachedStringify(parsedType, options);
if (options.validate) {
this.parse(result, options);
}

@@ -54,0 +84,0 @@

@@ -10,3 +10,3 @@ 'use strict';

Stringifier.prototype.applications = function(applications) {
Stringifier.prototype.applications = function(applications, options) {
if (!applications) {

@@ -16,9 +16,18 @@ return '';

var result = [];
var parsedApplications = [];
var result = '';
for (var i = 0, l = applications.length; i < l; i++) {
result.push(this.type(applications[i]));
parsedApplications.push(this.type(applications[i]));
}
return '.<' + result.join(', ') + '>';
if (options.htmlSafe) {
result = '.&lt;';
} else {
result = '.<';
}
result += parsedApplications.join(', ') + '>';
return result;
};

@@ -60,2 +69,3 @@

Stringifier.prototype.optional = function(optional) {
/*jshint boss: true */ // TODO: remove after JSHint releases the fix for jshint/jshint#878
if (optional === true) {

@@ -105,6 +115,7 @@ return '=';

Stringifier.prototype.type = function(type) {
Stringifier.prototype.type = function(type, options) {
if (!type) {
return '';
}
options = options || {};

@@ -130,3 +141,3 @@ // nullable comes first

result += this.type(type.expression);
result += this.applications(type.applications);
result += this.applications(type.applications, options);
break;

@@ -237,4 +248,4 @@ case Types.UndefinedLiteral:

module.exports = function(type) {
return new Stringifier().stringify(type);
module.exports = function(type, options) {
return new Stringifier().stringify(type, options);
};
{
"version": "0.3.1",
"version": "0.4.0",
"name": "catharsis",

@@ -4,0 +4,0 @@ "description": "A JavaScript parser for Google Closure Compiler type expressions.",

@@ -12,3 +12,4 @@ # Catharsis #

+ **Fast**. Parse results are cached, so the parser is invoked only when necessary.
+ **Flexible**. Catharsis can also convert parse results back into type expressions.
+ **Flexible**. Catharsis can convert parse results back into type expressions. In addition, it
provides a lenient mode that can recover from common errors in type expressions.

@@ -20,8 +21,11 @@

var type = '!Object';
var type;
var malformedType;
var parsedType;
var expr;
var parsedMalformedType;
// normal parsing
try {
parsedType = catharsis.parse('!Object');
type = '!Object';
parsedType = catharsis.parse(type);
console.log('%j', parsedType); // {"type":"NameExpression,"name":"Object","nullable":false}

@@ -33,5 +37,17 @@ }

expr = catharsis.stringify(parsedType);
console.log(expr); // !Object
// lenient parsing
try {
malformedType = 'number|string'; // should be (number|string)
parsedMalformedType = catharsis.parse(malformedType, {lenient: true});
}
catch (e) {
console.error('you will not see this error, thanks to lenient mode!');
}
console.log(catharsis.stringify(parsedType)); // !Object
console.log(catharsis.stringify(parsedMalformedType)); // number|string
console.log(catharsis.stringify(parsedMalformedType, // (number|string)
{useCache: false}));
See the `test/specs/` directory for more examples of Catharsis' parse results.

@@ -42,15 +58,34 @@

### parse(type, opts) ###
### parse(type, options) ###
Parse the Closure Compiler type `type`, and return the parse results. Throws an error if the type
cannot be parsed.
When called without options, Catharsis attempts to parse type expressions in the same way as
Closure Compiler. When the `lenient` option is enabled, Catharsis can also parse several kinds of
malformed type expressions:
+ The string `function` is treated as a function type with no parameters.
+ The period may be omitted from type applications. For example, `Array.<string>` and
`Array<string>` will be parsed in the same way.
+ The enclosing parentheses may be omitted from type unions. For example, `(number|string)` and
`number|string` will be parsed in the same way.
+ Name expressions may contain the characters `#` and `~`.
+ Record types may use types other than name expressions for keys.
#### Parameters ####
+ `type`: A string containing a Closure Compiler type expression.
+ `opts`: Options for parsing the type expression.
+ `opts.useCache`: Specifies whether to use the cache of parsed types. Defaults to `true`.
+ `options`: Options for parsing the type expression.
+ `options.lenient`: Specifies whether to enable lenient mode. Defaults to `false`.
+ `options.useCache`: Specifies whether to use the cache of parsed types. Defaults to `true`.
#### Returns ####
An object containing the parse results.
An object containing the parse results. See the `test/specs/` directory for examples of the parse
results for different type expressions.
### stringify(parsedType, opts) ###
The object also includes two non-enumerable properties:
+ `lenient`: A boolean indicating whether the type expression was parsed in lenient mode.
+ `typeExpression`: A string containing the type expression that was parsed.
### stringify(parsedType, options) ###
Stringify the parsed Closure Compiler type expression `parsedType`, and return the type expression.

@@ -61,7 +96,11 @@ If validation is enabled, throws an error if the stringified type expression cannot be parsed.

+ `parsedType`: An object containing a parsed Closure Compiler type expression.
+ `opts`: Options for stringifying the parse results.
+ `opts.useCache`: Specifies whether to use the cache of stringified parse results. Defaults to
`true`.
+ `opts.validate`: Specifies whether to validate the stringified parse results by attempting to
parse them as a type expression. Defaults to `false`.
+ `options`: Options for stringifying the parse results.
+ `options.htmlSafe`: Specifies whether to return an HTML-safe string that replaces left angle
brackets (`<`) with the corresponding entity (`&lt;`). **Note**: Characters in name expressions
are not escaped.
+ `options.useCache`: Specifies whether to use the cache of stringified parse results. If the
cache is enabled, and the parsed type expression includes a `typeExpression` property, the
`typeExpression` property will be returned as-is. Defaults to `true`.
+ `options.validate`: Specifies whether to validate the stringified parse results by attempting
to parse them as a type expression. Defaults to `false`.

@@ -97,2 +136,12 @@ #### Returns ####

+ 0.4.0 (March 2013):
+ Catharsis now supports a lenient parsing option that can parse several kinds of malformed type
expressions. See the documentation for details.
+ The objects containing parse results are now frozen.
+ The objects containing parse results now have two non-enumerable properties:
+ `lenient`: A boolean indicating whether the type expression was parsed in lenient mode.
+ `typeExpression`: A string containing the original type expression.
+ The `stringify()` method now honors the `useCache` option. If a parsed type includes a
`typeExpression` property, and `useCache` is not set to `false`, the stringified type will be
identical to the original type expression.
+ 0.3.1 (March 2013): Type expressions that begin with a reserved word, such as `integer`, are now

@@ -99,0 +148,0 @@ parsed correctly.

@@ -1,2 +0,2 @@

/*global describe: true, it: true */
/*global describe: true, it: true, xit: true */
'use strict';

@@ -8,3 +8,2 @@

var simpleType = 'foo';
var invalidType = '{*<?';

@@ -32,5 +31,23 @@ var simpleParsedType = {

it('should return an object when given basic input', function() {
catharsis.parse(simpleType).should.be.a('object');
catharsis.parse('foo').should.be.a('object');
});
it('should return a frozen object', function() {
Object.isFrozen(catharsis.parse('foo')).should.equal(true);
});
it('should return an object with nonenumerable "typeExpression" and "lenient" properties',
function() {
var parsedType = catharsis.parse('foo');
var descriptor;
descriptor = Object.getOwnPropertyDescriptor(parsedType, 'typeExpression');
descriptor.enumerable.should.equal(false);
descriptor.value.should.equal('foo');
descriptor = Object.getOwnPropertyDescriptor(parsedType, 'lenient');
descriptor.enumerable.should.equal(false);
descriptor.value.should.equal(false);
});
it('should throw an error when given an invalid type', function() {

@@ -43,2 +60,19 @@ function invalid() {

});
it('should use the regular cache when lenient mode is disabled', function() {
// parse twice to make sure we're getting a cached version.
// there must be a less lame way to do this...
var bar = catharsis.parse('bar');
bar = catharsis.parse('bar');
bar.lenient.should.equal(false);
});
it('should use the lenient cache when lenient mode is enabled', function() {
// parse twice to make sure we're getting a cached version
var baz = catharsis.parse('baz', {lenient: true});
baz = catharsis.parse('baz', {lenient: true});
baz.lenient.should.equal(true);
});
});

@@ -75,3 +109,26 @@

});
it('should return the typeExpression property as-is if the cache is enabled', function() {
var quxString = catharsis.stringify({
type: Types.NameExpression,
name: 'qux',
typeExpression: 'fake type expression'
});
quxString.should.equal('fake type expression');
});
it('should not return the typeExpression property if the cache is disabled', function() {
var quuxString = catharsis.stringify({
type: Types.NameExpression,
name: 'quux',
typeExpression: 'fake type expression'
},
{
useCache: false
});
quuxString.should.equal('quux');
});
});
});

@@ -7,11 +7,13 @@ 'use strict';

exports.testSpecs = function(tester) {
exports.testSpecs = function(filepath, tester, options) {
var basename;
var specPath = path.resolve('./test/specs');
var specPath = path.resolve(filepath);
var specs = fs.readdirSync(specPath);
specs.forEach(function(spec) {
basename = path.basename(spec, '.js');
tester.call(this, specPath, basename);
if (!fs.statSync(path.join(specPath, spec)).isDirectory()) {
basename = path.basename(spec, '.js');
tester.call(this, specPath, basename, options);
}
});
};

@@ -13,22 +13,18 @@ /*global describe: true, it: true */

function parseIt(item) {
function parseIt(item, options) {
var parsed;
try {
parsed = parse(item[1]);
parsed = parse(item.expression, options);
} catch(e) {
throw new Error(util.format('unable to parse type expression "%s": %s', item[1],
throw new Error(util.format('unable to parse type expression "%s": %s', item.expression,
e.message));
}
if (!_.isEqual(parsed, item[2])) {
throw new Error(util.format('parse tree should be "%j", NOT "%j"', item[2], parsed));
if (!_.isEqual(parsed, item.parsed)) {
throw new Error(util.format('parse tree should be "%j", NOT "%j"', item.parsed, parsed));
}
}
// each item in the 'types' array looks like:
// item[0]: {string} description
// item[1]: {string} type
// item[2]: {object} expected parsed type
function checkTypes(filepath) {
function checkTypes(filepath, options) {
var types = require(filepath);

@@ -40,3 +36,3 @@

try {
parseIt(type);
parseIt(type, options);
} catch(e) {

@@ -52,10 +48,20 @@ errors.push(e.message);

describe('parse()', function() {
var specs = './test/specs';
var lenientSpecs = path.join(specs, 'lenient');
function tester(specPath, basename) {
it('can parse types in the "' + basename + '" spec', function() {
checkTypes(path.join(specPath, basename));
checkTypes(path.join(specPath, basename), {});
});
}
function lenientTester(specPath, basename) {
it('can parse types in the "' + basename + '" spec when in lenient mode', function() {
checkTypes(path.join(specPath, basename), {lenient: true});
});
}
helper.testSpecs(tester);
helper.testSpecs(specs, tester);
helper.testSpecs(lenientSpecs, lenientTester);
});
});

@@ -6,30 +6,30 @@ 'use strict';

module.exports = [
[
'boolean',
'boolean',
{
{
description: 'boolean',
expression: 'boolean',
parsed: {
type: Types.NameExpression,
name: 'boolean'
}
],
[
'object',
'Window',
{
},
{
description: 'object',
expression: 'Window',
parsed: {
type: Types.NameExpression,
name: 'Window'
}
],
[
'object with properties',
'goog.ui.Menu',
{
},
{
description: 'object with properties',
expression: 'goog.ui.Menu',
parsed: {
type: Types.NameExpression,
name: 'goog.ui.Menu'
}
],
[
'variable number of parameters',
'...number',
{
},
{
description: 'variable number of parameters',
expression: '...number',
parsed: {
type: Types.NameExpression,

@@ -39,7 +39,7 @@ name: 'number',

}
],
[
'optional number parameter',
'number=',
{
},
{
description: 'optional number parameter',
expression: 'number=',
parsed: {
type: Types.NameExpression,

@@ -49,7 +49,7 @@ name: 'number',

}
],
[
'optional Object parameter',
'Object=',
{
},
{
description: 'optional Object parameter',
expression: 'Object=',
parsed: {
type: Types.NameExpression,

@@ -59,39 +59,39 @@ name: 'Object',

}
],
[
'null',
'null',
{
},
{
description: 'null',
expression: 'null',
parsed: {
type: Types.NullLiteral
}
],
[
'undefined',
'undefined',
{
},
{
description: 'undefined',
expression: 'undefined',
parsed: {
type: Types.UndefinedLiteral
}
],
[
'all',
'*',
{
},
{
description: 'all',
expression: '*',
parsed: {
type: Types.AllLiteral
}
],
[
'unknown',
'?',
{
},
{
description: 'unknown',
expression: '?',
parsed: {
type: Types.UnknownLiteral
}
],
[
'name that starts with a reserved word',
'forsooth',
{
},
{
description: 'name that starts with a reserved word',
expression: 'forsooth',
parsed: {
type: Types.NameExpression,
name: 'forsooth'
}
]
}
];

@@ -6,6 +6,6 @@ 'use strict';

module.exports = [
[
'function with two basic parameters',
'function(string, boolean)',
{
{
description: 'function with two basic parameters',
expression: 'function(string, boolean)',
parsed: {
type: Types.FunctionType,

@@ -23,7 +23,7 @@ params: [

}
],
[
'function with two basic parameters and a return value',
'function(string, string): boolean',
{
},
{
description: 'function with two basic parameters and a return value',
expression: 'function(string, string): boolean',
parsed: {
type: Types.FunctionType,

@@ -45,7 +45,7 @@ params: [

}
],
[
'optional function with one basic parameter',
'function(string)=',
{
},
{
description: 'optional function with one basic parameter',
expression: 'function(string)=',
parsed: {
type: Types.FunctionType,

@@ -60,7 +60,7 @@ params: [

}
],
[
'function with no parameters and a return value',
'function(): number',
{
},
{
description: 'function with no parameters and a return value',
expression: 'function(): number',
parsed: {
type: Types.FunctionType,

@@ -73,7 +73,7 @@ params: [],

}
],
[
'function with a "this" type and one parameter',
'function(this:goog.ui.Menu, string)',
{
},
{
description: 'function with a "this" type and one parameter',
expression: 'function(this:goog.ui.Menu, string)',
parsed: {
type: Types.FunctionType,

@@ -91,7 +91,7 @@ params: [

}
],
[
'function with a "new" type and one parameter',
'function(new:goog.ui.Menu, string)',
{
},
{
description: 'function with a "new" type and one parameter',
expression: 'function(new:goog.ui.Menu, string)',
parsed: {
type: Types.FunctionType,

@@ -109,8 +109,8 @@ params: [

}
],
[
'function with a fixed parameter, followed by a variable number of parameters, as well ' +
'as a return value',
'function(string, ...[number]): number',
{
},
{
description: 'function with a fixed parameter, followed by a variable number of ' +
'parameters, as well as a return value',
expression: 'function(string, ...[number]): number',
parsed: {
type: Types.FunctionType,

@@ -133,7 +133,7 @@ params: [

}
],
[
'function with a variable number of parameters containing the value `null`',
'function(...[null])',
{
},
{
description: 'function with a variable number of parameters containing the value `null`',
expression: 'function(...[null])',
parsed: {
type: Types.FunctionType,

@@ -147,7 +147,8 @@ params: [

}
],
[
'function with a variable number of parameters containing the value `undefined`',
'function(...[undefined])',
{
},
{
description: 'function with a variable number of parameters containing the value ' +
'`undefined`',
expression: 'function(...[undefined])',
parsed: {
type: Types.FunctionType,

@@ -161,9 +162,9 @@ params: [

}
],
[
'function with a variable number of parameters, a "new" type, a "this" type, and a ' +
'return value',
'function(new:Master, this:Everyone, string, goog.ui.Menu, Array.<Object>, ...[string]): ' +
'boolean',
{
},
{
description: 'function with a variable number of parameters, a "new" type, a "this" ' +
'type, and a return value',
expression: 'function(new:Master, this:Everyone, string, goog.ui.Menu, Array.<Object>, ' +
'...[string]): boolean',
parsed: {
type: Types.FunctionType,

@@ -211,10 +212,10 @@ params: [

}
],
},
// The following type expressions are adapted from the Closure Compiler test suite:
// http://goo.gl/rgKSk
[
'function that returns a type union',
'function(): (number|string)',
{
{
description: 'function that returns a type union',
expression: 'function(): (number|string)',
parsed: {
type: Types.FunctionType,

@@ -236,15 +237,15 @@ params: [],

}
],
[
'function with no parameters and no return value',
'function()',
{
},
{
description: 'function with no parameters and no return value',
expression: 'function()',
parsed: {
type: Types.FunctionType,
params: []
}
],
[
'function with a variable number of parameters containing any values',
'function(...[*])',
{
},
{
description: 'function with a variable number of parameters containing any values',
expression: 'function(...[*])',
parsed: {
type: Types.FunctionType,

@@ -258,7 +259,7 @@ params: [

}
],
[
'function with a "this" type that returns a type union',
'function(this:Object): (number|string)',
{
},
{
description: 'function with a "this" type that returns a type union',
expression: 'function(this:Object): (number|string)',
parsed: {
type: Types.FunctionType,

@@ -284,7 +285,8 @@ params: [],

}
],
[
'function with a "this" type that is a type union, and that returns a type union',
'function(this:(Array|Date)): (number|string)',
{
},
{
description: 'function with a "this" type that is a type union, and that returns a ' +
'type union',
expression: 'function(this:(Array|Date)): (number|string)',
parsed: {
type: Types.FunctionType,

@@ -319,8 +321,8 @@ params: [],

}
],
[
'function with a "new" type and a variable number of params that accept all types, ' +
'returning a name expression',
'function(new:Array, ...[*]): Array',
{
},
{
description: 'function with a "new" type and a variable number of params that accept ' +
'all types, returning a name expression',
expression: 'function(new:Array, ...[*]): Array',
parsed: {
type: Types.FunctionType,

@@ -342,8 +344,8 @@ params: [

}
],
[
'function with a "new" type that accepts an optional parameter of any type, as well as a ' +
'return value',
'function(new:Boolean, *=): boolean',
{
},
{
description: 'function with a "new" type that accepts an optional parameter of any ' +
'type, as well as a return value',
expression: 'function(new:Boolean, *=): boolean',
parsed: {
type: Types.FunctionType,

@@ -365,7 +367,7 @@ params: [

}
],
[
'function with a variable number of parameters and a return value',
'function(...[number]): boolean',
{
},
{
description: 'function with a variable number of parameters and a return value',
expression: 'function(...[number]): boolean',
parsed: {
type: Types.FunctionType,

@@ -384,7 +386,7 @@ params: [

}
],
[
'function with a "this" type and a parameter that returns a type union',
'function(this:Date, number): (boolean|number|string)',
{
},
{
description: 'function with a "this" type and a parameter that returns a type union',
expression: 'function(this:Date, number): (boolean|number|string)',
parsed: {
type: Types.FunctionType,

@@ -419,3 +421,3 @@ params: [

}
]
}
];

@@ -6,6 +6,6 @@ 'use strict';

module.exports = [
[
'number or null',
'?number',
{
{
description: 'number or null',
expression: '?number',
parsed: {
type: Types.NameExpression,

@@ -15,7 +15,7 @@ name: 'number',

}
],
[
'object, not null',
'!Object',
{
},
{
description: 'object, not null',
expression: '!Object',
parsed: {
type: Types.NameExpression,

@@ -25,3 +25,3 @@ name: 'Object',

}
]
}
];

@@ -6,14 +6,14 @@ 'use strict';

module.exports = [
[
'empty record type',
'{}',
{
{
description: 'empty record type',
expression: '{}',
parsed: {
type: Types.RecordType,
fields: []
}
],
[
'record type with 1 typed property',
'{myNum: number}',
{
},
{
description: 'record type with 1 typed property',
expression: '{myNum: number}',
parsed: {
type: Types.RecordType,

@@ -34,7 +34,7 @@ fields: [

}
],
[
'optional record type with 1 typed property',
'{myNum: number}=',
{
},
{
description: 'optional record type with 1 typed property',
expression: '{myNum: number}=',
parsed: {
type: Types.RecordType,

@@ -56,7 +56,7 @@ fields: [

}
],
[
'nullable record type with 1 typed property',
'?{myNum: number}',
{
},
{
description: 'nullable record type with 1 typed property',
expression: '?{myNum: number}',
parsed: {
type: Types.RecordType,

@@ -78,7 +78,7 @@ fields: [

}
],
[
'non-nullable record type with 1 typed property',
'!{myNum: number}',
{
},
{
description: 'non-nullable record type with 1 typed property',
expression: '!{myNum: number}',
parsed: {
type: Types.RecordType,

@@ -100,7 +100,7 @@ fields: [

}
],
[
'record type with 1 typed property and 1 untyped property',
'{myNum: number, myObject}',
{
},
{
description: 'record type with 1 typed property and 1 untyped property',
expression: '{myNum: number, myObject}',
parsed: {
type: Types.RecordType,

@@ -129,7 +129,7 @@ fields: [

}
],
[
'record type with a property that uses a type application as a key',
'{Array.<string>: number}',
{
},
{
description: 'record type with a property that uses a type application as a value',
expression: '{myArray: Array.<string>}',
parsed: {
type: Types.RecordType,

@@ -140,32 +140,3 @@ fields: [

key: {
type: Types.TypeApplication,
expression: {
type: Types.NameExpression,
name: 'Array'
},
applications: [
{
type: Types.NameExpression,
name: 'string'
}
]
},
value: {
type: Types.NameExpression,
name: 'number'
}
}
]
}
],
[
'record type with a property that uses a type application as a value',
'{myArray: Array.<string>}',
{
type: Types.RecordType,
fields: [
{
type: Types.FieldType,
key: {
type: Types.NameExpression,
name: 'myArray'

@@ -189,7 +160,7 @@ },

}
],
[
'record type with a property that uses a type union as a key',
'{(number|boolean|string): number}',
{
},
{
description: 'record type with a property that uses a type union as a value',
expression: '{myKey: (number|boolean|string)}',
parsed: {
type: Types.RecordType,

@@ -200,36 +171,3 @@ fields: [

key: {
type: Types.TypeUnion,
elements: [
{
type: Types.NameExpression,
name: 'number'
},
{
type: Types.NameExpression,
name: 'boolean'
},
{
type: Types.NameExpression,
name: 'string'
}
]
},
value: {
type: Types.NameExpression,
name: 'number'
}
}
]
}
],
[
'record type with a property that uses a type union as a value',
'{myKey: (number|boolean|string)}',
{
type: Types.RecordType,
fields: [
{
type: Types.FieldType,
key: {
type: Types.NameExpression,
name: 'myKey'

@@ -257,7 +195,7 @@ },

}
],
[
'record type with a property that uses a JavaScript keyword as a key',
'{continue: string}',
{
},
{
description: 'record type with a property that uses a JavaScript keyword as a key',
expression: '{continue: string}',
parsed: {
type: Types.RecordType,

@@ -279,7 +217,8 @@ fields: [

}
],
[
'record type with a property that uses a JavaScript future reserved word as a key',
'{class: string}',
{
},
{
description: 'record type with a property that uses a JavaScript future reserved word as ' +
'a key',
expression: '{class: string}',
parsed: {
type: Types.RecordType,

@@ -301,8 +240,8 @@ fields: [

}
],
[
'record type with a property that uses a string representation of a JavaScript boolean ' +
'literal as a key',
'{true: string}',
{
},
{
description: 'record type with a property that uses a string representation of a ' +
'JavaScript boolean literal as a key',
expression: '{true: string}',
parsed: {
type: Types.RecordType,

@@ -324,3 +263,3 @@ fields: [

}
]
}
];

@@ -6,6 +6,6 @@ 'use strict';

module.exports = [
[
'array of strings',
'Array.<string>',
{
{
description: 'array of strings',
expression: 'Array.<string>',
parsed: {
type: Types.TypeApplication,

@@ -23,7 +23,7 @@ expression: {

}
],
[
'object whose properties are strings and property values are numbers',
'Object.<string, number>',
{
},
{
description: 'object whose properties are strings and property values are numbers',
expression: 'Object.<string, number>',
parsed: {
type: Types.TypeApplication,

@@ -45,7 +45,9 @@ expression: {

}
],
[
'object whose properties are a type application and property values are a type union',
'Object.<Array.<(boolean|{myKey: Error})>, (boolean|string|function(new:foo): string)>',
{
},
{
description: 'object whose properties are a type application and property values are a ' +
'type union',
expression: 'Object.<Array.<(boolean|{myKey: Error})>, ' +
'(boolean|string|function(new:foo): string)>',
parsed: {
type: Types.TypeApplication,

@@ -118,7 +120,7 @@ expression: {

}
],
[
'array of objects that have a length property',
'Array.<{length}>',
{
},
{
description: 'array of objects that have a length property',
expression: 'Array.<{length}>',
parsed: {
type: Types.TypeApplication,

@@ -145,7 +147,7 @@ expression: {

}
],
[
'array of unknown type',
'Array.<?>',
{
},
{
description: 'array of unknown type',
expression: 'Array.<?>',
parsed: {
type: Types.TypeApplication,

@@ -162,3 +164,3 @@ expression: {

}
]
}
];

@@ -6,6 +6,6 @@ 'use strict';

module.exports = [
[
'union with 2 types (number and boolean)',
'(number|boolean)',
{
{
description: 'union with 2 types (number and boolean)',
expression: '(number|boolean)',
parsed: {
type: Types.TypeUnion,

@@ -23,7 +23,7 @@ elements: [

}
],
[
'union with 2 types (Object and undefined)',
'(Object|undefined)',
{
},
{
description: 'union with 2 types (Object and undefined)',
expression: '(Object|undefined)',
parsed: {
type: Types.TypeUnion,

@@ -40,7 +40,7 @@ elements: [

}
],
[
'union with 3 types (number, Window, and goog.ui.Menu)',
'(number|Window|goog.ui.Menu)',
{
},
{
description: 'union with 3 types (number, Window, and goog.ui.Menu)',
expression: '(number|Window|goog.ui.Menu)',
parsed: {
type: Types.TypeUnion,

@@ -62,7 +62,7 @@ elements: [

}
],
[
'nullable union with 2 types (number and boolean)',
'?(number|boolean)',
{
},
{
description: 'nullable union with 2 types (number and boolean)',
expression: '?(number|boolean)',
parsed: {
type: Types.TypeUnion,

@@ -81,7 +81,7 @@ elements: [

}
],
[
'non-nullable union with 2 types (number and boolean)',
'!(number|boolean)',
{
},
{
description: 'non-nullable union with 2 types (number and boolean)',
expression: '!(number|boolean)',
parsed: {
type: Types.TypeUnion,

@@ -100,7 +100,7 @@ elements: [

}
],
[
'optional union with 2 types (number and boolean)',
'(number|boolean)=',
{
},
{
description: 'optional union with 2 types (number and boolean)',
expression: '(number|boolean)=',
parsed: {
type: Types.TypeUnion,

@@ -119,10 +119,10 @@ elements: [

}
],
},
// The following type expressions are adapted from the Closure Compiler test suite:
// http://goo.gl/vpRTe, http://goo.gl/DVh3f
[
'union with 2 types (array and object with unknown value type)',
'(Array|Object.<string, ?>)',
{
{
description: 'union with 2 types (array and object with unknown value type)',
expression: '(Array|Object.<string, ?>)',
parsed: {
type: Types.TypeUnion,

@@ -152,7 +152,7 @@ elements: [

}
],
[
'union with 2 type applications',
'(Array.<string>|Object.<string, ?>)',
{
},
{
description: 'union with 2 type applications',
expression: '(Array.<string>|Object.<string, ?>)',
parsed: {
type: Types.TypeUnion,

@@ -191,7 +191,7 @@ elements: [

}
],
[
'union with 2 types (an error, or a function that returns an error)',
'(Error|function(): Error)',
{
},
{
description: 'union with 2 types (an error, or a function that returns an error)',
expression: '(Error|function(): Error)',
parsed: {
type: Types.TypeUnion,

@@ -213,3 +213,108 @@ elements: [

}
]
},
// The following type expressions are adapted from the Doctrine parser:
// http://constellation.github.com/doctrine/demo/
{
description: 'optional union with multiple types',
expression: '(jQuerySelector|Element|Object|Array.<Element>|jQuery|string|function())=',
parsed: {
type: Types.TypeUnion,
elements: [
{
type: Types.NameExpression,
name: 'jQuerySelector'
},
{
type: Types.NameExpression,
name: 'Element'
},
{
type: Types.NameExpression,
name: 'Object'
},
{
type: Types.TypeApplication,
expression: {
type: Types.NameExpression,
name: 'Array'
},
applications: [
{
type: Types.NameExpression,
name: 'Element'
}
]
},
{
type: Types.NameExpression,
name: 'jQuery'
},
{
type: Types.NameExpression,
name: 'string'
},
{
type: Types.FunctionType,
params: []
}
],
optional: true
}
},
{
description: 'optional union with multiple types, including a nested union type',
expression: '(Element|Object|Document|Object.<string, (string|function(!jQuery.event=))>)=',
parsed: {
type: Types.TypeUnion,
elements: [
{
type: Types.NameExpression,
name: 'Element'
},
{
type: Types.NameExpression,
name: 'Object'
},
{
type: Types.NameExpression,
name: 'Document'
},
{
type: Types.TypeApplication,
expression: {
type: Types.NameExpression,
name: 'Object'
},
applications: [
{
type: Types.NameExpression,
name: 'string'
},
{
type: Types.TypeUnion,
elements: [
{
type: Types.NameExpression,
name: 'string'
},
{
type: Types.FunctionType,
params: [
{
type: Types.NameExpression,
name: 'jQuery.event',
optional: true,
nullable: false
}
]
}
]
}
]
}
],
optional: true
}
}
];

@@ -12,22 +12,21 @@ /*global describe: true, it: true */

// each item looks like:
// item[0]: {string} description
// item[1]: {string} type
// item[2]: {object} expected parsed type
function stringifyIt(item) {
var string = stringify(item[2]);
if (string !== item[1]) {
throw new Error(util.format('type expression "%s" was stringified as "%s"', item[1],
function stringifyIt(item, options) {
var string = stringify(item.parsed, options);
var expression = item.newExpression || item.expression;
if (string !== expression) {
throw new Error(util.format('type expression "%s" was stringified as "%s"', expression,
string));
}
try {
parse(string);
} catch(e) {
throw new Error(util.format('unable to parse string "%s", created from %j: %s', string,
item[2], e.message));
if (options.validate === undefined || options.validate === true) {
try {
parse(string, options);
} catch(e) {
throw new Error(util.format('unable to parse string "%s", created from %j: %s', string,
item.parsed, e.message));
}
}
}
function checkStringifiedTypes(filepath) {
function checkStringifiedTypes(filepath, options) {
var types = require(filepath);

@@ -39,3 +38,3 @@

try {
stringifyIt(type);
stringifyIt(type, options);
} catch(e) {

@@ -50,9 +49,13 @@ errors.push(e.message);

describe('stringify', function() {
function tester(specPath, basename) {
var specs = './test/specs';
var htmlSpecs = './test/specs/html';
function tester(specPath, basename, options) {
it('can stringify types in the "' + basename + '" spec', function() {
checkStringifiedTypes(path.join(specPath, basename));
checkStringifiedTypes(path.join(specPath, basename), options);
});
}
helper.testSpecs(tester);
helper.testSpecs(specs, tester, {});
helper.testSpecs(htmlSpecs, tester, {htmlSafe: true, validate: false});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc