diff --git a/angular-media-queries/match-media-tests.ts b/angular-media-queries/match-media-tests.ts
new file mode 100644
index 000000000..a9331751a
--- /dev/null
+++ b/angular-media-queries/match-media-tests.ts
@@ -0,0 +1,60 @@
+///
+
+var myApp = angular.module('testModule', ['matchMedia']);
+
+myApp.controller('TestController', ($log: angular.ILogService,
+ $scope: angular.IScope,
+ screenSize: angular.matchmedia.IScreenSize) => {
+
+ var fnCallback = (result: boolean) => {
+ $log.info(`Result: ${result}`);
+ }
+
+ // '.isRetina' examples
+ if(screenSize.isRetina) {
+ $log.info("Retina screen detected")
+ }
+
+ // '.is(...)' examples
+ var res = screenSize.is(["xs", "sm"]);
+ fnCallback(res);
+
+ res = screenSize.is("xs, lg")
+ fnCallback(res);
+
+ // '.on(...)' examples
+
+ res = screenSize.on(["xs", "sm"], fnCallback);
+ fnCallback(res);
+
+ res = screenSize.on("xs, lg", fnCallback);
+ fnCallback(res);
+
+ res = screenSize.on(["xs", "sm"], fnCallback, $scope);
+ fnCallback(res);
+
+ res = screenSize.on("xs, lg", fnCallback, $scope);
+ fnCallback(res);
+
+ // '.onChange(...)' examples
+
+ res = screenSize.onChange($scope, ["xs", "sm"], fnCallback);
+ fnCallback(res);
+
+ res = screenSize.onChange($scope, "xs, lg", fnCallback);
+ fnCallback(res);
+
+ // '.when(...)' examples
+
+ res = screenSize.when(["xs", "sm"], fnCallback);
+ fnCallback(res);
+
+ res = screenSize.when("xs, lg", fnCallback);
+ fnCallback(res);
+
+ res = screenSize.when(["xs", "sm"], fnCallback, $scope);
+ fnCallback(res);
+
+ res = screenSize.when("xs, lg", fnCallback, $scope);
+ fnCallback(res);
+});
\ No newline at end of file
diff --git a/angular-media-queries/match-media.d.ts b/angular-media-queries/match-media.d.ts
new file mode 100644
index 000000000..401c61f46
--- /dev/null
+++ b/angular-media-queries/match-media.d.ts
@@ -0,0 +1,30 @@
+// Type definitions for Angular matchMedia 0.6.0 (angular.matchMedia module)
+// Project: https://github.com/jacopotarantino/angular-match-media
+// Definitions by: Joao Monteiro
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+///
+declare namespace angular.matchmedia {
+
+ interface IScreenSize {
+
+ // Returns a value indicating if the current device has a retina screen
+ isRetina: boolean;
+
+ is(list: Array | string): boolean;
+
+ // Executes the callback function on window resize with the match truthiness as the first argument.
+ // Returns the current match truthiness.
+ // The 'scope' parameter is optional. If it's not passed in, '$rootScope' is used.
+ on(list: Array | string, callback: (result: boolean) => void, scope?: angular.IScope): boolean;
+
+ // Executes the callback function ONLY when the match differs from previous match.
+ // Returns the current match truthiness.
+ // The 'scope' parameter is required for cleanup reasons (destroy event).
+ onChange(scope: angular.IScope, list: Array | string, callback: (result: boolean) => void): boolean;
+
+ // Executes the callback only when inside of the particular screensize.
+ // The 'scope' parameter is optional. If it's not passed in, '$rootScope' is used.
+ when(list: Array | string, callback: (result: boolean) => void, scope?: angular.IScope): boolean;
+ }
+}
\ No newline at end of file
diff --git a/angularjs/angular-component-router.d.ts b/angularjs/angular-component-router.d.ts
index e015a712a..2c56ef3a2 100644
--- a/angularjs/angular-component-router.d.ts
+++ b/angularjs/angular-component-router.d.ts
@@ -45,7 +45,7 @@ declare namespace angular {
specificity(): number;
- resolveComponent(): Promise;
+ resolveComponent(): IPromise;
/**
* converts the instruction into a URL string
@@ -87,20 +87,20 @@ declare namespace angular {
* Called by the Router to instantiate a new component during the commit phase of a navigation.
* This method in turn is responsible for calling the `routerOnActivate` hook of its child.
*/
- activate(nextInstruction: ComponentInstruction): Promise;
+ activate(nextInstruction: ComponentInstruction): IPromise;
/**
* Called by the {@link Router} during the commit phase of a navigation when an outlet
* reuses a component between different routes.
* This method in turn is responsible for calling the `routerOnReuse` hook of its child.
*/
- reuse(nextInstruction: ComponentInstruction): Promise;
+ reuse(nextInstruction: ComponentInstruction): IPromise;
/**
* Called by the {@link Router} when an outlet disposes of a component's contents.
* This method in turn is responsible for calling the `routerOnDeactivate` hook of its child.
*/
- deactivate(nextInstruction: ComponentInstruction): Promise;
+ deactivate(nextInstruction: ComponentInstruction): IPromise;
/**
* Called by the {@link Router} during recognition phase of a navigation.
@@ -110,7 +110,7 @@ declare namespace angular {
* This method delegates to the child component's `routerCanDeactivate` hook if it exists,
* and otherwise resolves to true.
*/
- routerCanDeactivate(nextInstruction: ComponentInstruction): Promise;
+ routerCanDeactivate(nextInstruction: ComponentInstruction): IPromise;
/**
* Called by the {@link Router} during recognition phase of a navigation.
@@ -122,7 +122,7 @@ declare namespace angular {
* Otherwise, this method delegates to the child component's `routerCanReuse` hook if it exists,
* or resolves to true if the hook is not present.
*/
- routerCanReuse(nextInstruction: ComponentInstruction): Promise;
+ routerCanReuse(nextInstruction: ComponentInstruction): IPromise;
}
interface RouteRegistry {
@@ -140,7 +140,7 @@ declare namespace angular {
* Given a URL and a parent component, return the most specific instruction for navigating
* the application into the state specified by the url
*/
- recognize(url: string, ancestorInstructions: Instruction[]): Promise;
+ recognize(url: string, ancestorInstructions: Instruction[]): IPromise;
/**
* Given a normalized list with component names and params like: `['user', {id: 3 }]`
@@ -197,14 +197,14 @@ declare namespace angular {
*
* You probably don't need to use this unless you're writing a reusable component.
*/
- registerPrimaryOutlet(outlet: RouterOutlet): Promise;
+ registerPrimaryOutlet(outlet: RouterOutlet): IPromise;
/**
* Register an outlet to notified of auxiliary route changes.
*
* You probably don't need to use this unless you're writing a reusable component.
*/
- registerAuxOutlet(outlet: RouterOutlet): Promise;
+ registerAuxOutlet(outlet: RouterOutlet): IPromise;
/**
* Given an instruction, returns `true` if the instruction is currently active,
@@ -224,7 +224,7 @@ declare namespace angular {
* ]);
* ```
*/
- config(definitions: RouteDefinition[]): Promise;
+ config(definitions: RouteDefinition[]): IPromise;
/**
* Navigate based on the provided Route Link DSL. It's preferred to navigate with this method
@@ -238,7 +238,7 @@ declare namespace angular {
* ```
* See the {@link RouterLink} directive for more.
*/
- navigate(linkParams: any[]): Promise;
+ navigate(linkParams: any[]): IPromise;
/**
* Navigate to a URL. Returns a promise that resolves when navigation is complete.
@@ -247,19 +247,19 @@ declare namespace angular {
* If the given URL begins with a `/`, router will navigate absolutely.
* If the given URL does not begin with `/`, the router will navigate relative to this component.
*/
- navigateByUrl(url: string, _skipLocationChange?: boolean): Promise;
+ navigateByUrl(url: string, _skipLocationChange?: boolean): IPromise;
/**
* Navigate via the provided instruction. Returns a promise that resolves when navigation is
* complete.
*/
navigateByInstruction(instruction: Instruction,
- _skipLocationChange?: boolean): Promise;
+ _skipLocationChange?: boolean): IPromise;
/**
* Updates this router and all descendant routers according to the given instruction
*/
- commit(instruction: Instruction, _skipLocationChange?: boolean): Promise;
+ commit(instruction: Instruction, _skipLocationChange?: boolean): IPromise;
/**
* Subscribe to URL updates from the router
@@ -269,18 +269,18 @@ declare namespace angular {
/**
* Removes the contents of this router's outlet and all descendant outlets
*/
- deactivate(instruction: Instruction): Promise;
+ deactivate(instruction: Instruction): IPromise;
/**
* Given a URL, returns an instruction representing the component graph
*/
- recognize(url: string): Promise;
+ recognize(url: string): IPromise;
/**
* Navigates to either the last URL successfully navigated to, or the last URL requested if the
* router has yet to successfully navigate.
*/
- renavigate(): Promise;
+ renavigate(): IPromise;
/**
* Generate an `Instruction` based on the provided Route Link DSL.
@@ -364,7 +364,7 @@ declare namespace angular {
* {@example router/ts/can_deactivate/can_deactivate_example.ts region='routerCanDeactivate'}
*/
interface CanDeactivate {
- $routerCanDeactivate(next?: ComponentInstruction, prev?: ComponentInstruction): boolean | Promise;
+ $routerCanDeactivate(next?: ComponentInstruction, prev?: ComponentInstruction): boolean | IPromise;
}
/**
@@ -407,7 +407,7 @@ declare namespace angular {
* {@example router/ts/reuse/reuse_example.ts region='reuseCmp'}
*/
interface CanReuse {
- $routerCanReuse(next?: angular.ComponentInstruction, prev?: angular.ComponentInstruction): boolean | Promise;
+ $routerCanReuse(next?: angular.ComponentInstruction, prev?: angular.ComponentInstruction): boolean | IPromise;
}
/**
diff --git a/angularjs/angular.d.ts b/angularjs/angular.d.ts
index 6d72c4e2d..e86fd3705 100644
--- a/angularjs/angular.d.ts
+++ b/angularjs/angular.d.ts
@@ -1845,6 +1845,11 @@ declare namespace angular {
controller(name: string): any;
injector(): any;
scope(): IScope;
+
+ /**
+ * Overload for custom scope interfaces
+ */
+ scope(): T;
isolateScope(): IScope;
inheritedData(key: string, value: any): JQuery;
diff --git a/cordova/cordova-tests.ts b/cordova/cordova-tests.ts
index d0e6e6889..7e97305a2 100644
--- a/cordova/cordova-tests.ts
+++ b/cordova/cordova-tests.ts
@@ -192,7 +192,7 @@ file.upload('cdvfile://localhost/persistent/path/to/downloads/',
console.error('Failed with exception ' + err.exception);
}
},
- { headers: null, httpMethod: "PUT" },
+ { headers: {"X-Email": "user@mail.com", 'X-Token': "asdf3w234"}, httpMethod: "PUT" },
true);
file.abort();
diff --git a/cordova/plugins/FileTransfer.d.ts b/cordova/plugins/FileTransfer.d.ts
index 140973cd5..40829668a 100644
--- a/cordova/plugins/FileTransfer.d.ts
+++ b/cordova/plugins/FileTransfer.d.ts
@@ -93,7 +93,7 @@ interface FileUploadOptions {
/** Whether to upload the data in chunked streaming mode. Defaults to true. */
chunkedMode?: boolean;
/** A map of header name/header values. Use an array to specify more than one value. */
- headers?: Object[];
+ headers?: Object;
}
/** Optional parameters for download method. */
diff --git a/dotenv/dotenv-tests.ts b/dotenv/dotenv-tests.ts
new file mode 100644
index 000000000..555c104c9
--- /dev/null
+++ b/dotenv/dotenv-tests.ts
@@ -0,0 +1,15 @@
+///
+
+import dotenv = require('dotenv');
+
+dotenv.config({
+ silent: true
+});
+
+dotenv.config({
+ path: '.env'
+})
+
+dotenv.config({
+ encoding: 'utf8'
+})
\ No newline at end of file
diff --git a/dotenv/dotenv.d.ts b/dotenv/dotenv.d.ts
new file mode 100644
index 000000000..b18e9bd03
--- /dev/null
+++ b/dotenv/dotenv.d.ts
@@ -0,0 +1,14 @@
+// Type definitions for dotenv 2.0.0
+// Project: https://github.com/motdotla/dotenv
+// Definitions by: Jussi Kinnula
+// Definitions: https://github.com/jussikinnula/DefinitelyTyped
+
+interface dotenvOptions {
+ silent?: boolean;
+ path?: string;
+ encoding?: string;
+}
+
+declare module 'dotenv' {
+ export function config(options?: dotenvOptions): boolean;
+}
diff --git a/evaporate/evaporate-tests.ts b/evaporate/evaporate-tests.ts
new file mode 100644
index 000000000..559d61fe7
--- /dev/null
+++ b/evaporate/evaporate-tests.ts
@@ -0,0 +1,7 @@
+///
+
+function test_upload() {
+ var evaporate = new Evaporate({});
+ var uploadId = evaporate.add({});
+ evaporate.cancel(uploadId);
+}
diff --git a/evaporate/evaporate.d.ts b/evaporate/evaporate.d.ts
new file mode 100644
index 000000000..2a6745546
--- /dev/null
+++ b/evaporate/evaporate.d.ts
@@ -0,0 +1,13 @@
+// Type definitions for EvaporateJS
+// Project: https://github.com/TTLabs/EvaporateJS
+// Definitions by: Andrew Kuklewicz , Chris Rhoden
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+declare class Evaporate {
+ cancel(id:string): boolean;
+ constructor(config:any);
+ add(config:any): string;
+}
+
+declare module 'evaporate' {
+ export = Evaporate;
+}
diff --git a/fixed-data-table/fixed-data-table-tests.tsx b/fixed-data-table/fixed-data-table-tests.tsx
index 2c8e04a7d..a5f1ab9f0 100644
--- a/fixed-data-table/fixed-data-table-tests.tsx
+++ b/fixed-data-table/fixed-data-table-tests.tsx
@@ -88,16 +88,16 @@ interface RowData {
interface MyCellProps extends CellProps {
rowIndex?: number;
field: string;
- data: RowData[];
+ myData: RowData[];
}
class MyTextCell extends React.Component {
render(): React.ReactElement {
- const {rowIndex, field, data} = this.props;
+ const {rowIndex, field, myData} = this.props;
return (
-
- {data[rowIndex][field]}
+ |
+ {myData[rowIndex][field]}
|
);
}
@@ -105,11 +105,11 @@ class MyTextCell extends React.Component {
class MyLinkCell extends React.Component {
render(): React.ReactElement {
- const {rowIndex, field, data} = this.props;
- const link: string = data[rowIndex][field];
+ const {rowIndex, field, myData} = this.props;
+ const link: string = myData[rowIndex][field];
return (
-
+ |
{link}
|
);
@@ -150,7 +150,7 @@ class MyTable4 extends React.Component<{}, MyTable4State> {
header={{field} | }
cell={
}
diff --git a/fixed-data-table/fixed-data-table.d.ts b/fixed-data-table/fixed-data-table.d.ts
index b4e404a57..e4bc79ff5 100644
--- a/fixed-data-table/fixed-data-table.d.ts
+++ b/fixed-data-table/fixed-data-table.d.ts
@@ -458,11 +458,11 @@ declare namespace FixedDataTable {
* />
* );
*/
- export interface CellProps {
+ export interface CellProps extends __React.HTMLAttributes {
/**
* The row index of the cell.
*/
- rowIndex?: number
+ rowIndex?: number;
/**
* Outer height of the cell.
diff --git a/fromnow/fromnow-tests.ts b/fromnow/fromnow-tests.ts
index b95a23640..4ed78816a 100644
--- a/fromnow/fromnow-tests.ts
+++ b/fromnow/fromnow-tests.ts
@@ -6,6 +6,10 @@ function dateOnly() {
fromnow( '2015-12-31' );
}
+function dateObjectOnly() {
+ fromnow( new Date() );
+}
+
function maxChunks() {
fromnow( '2015-12-31', {
maxChunks: 12
@@ -22,4 +26,4 @@ function useAnd() {
fromnow( '2015-12-31', {
useAnd: true
});
-}
\ No newline at end of file
+}
diff --git a/fromnow/fromnow.d.ts b/fromnow/fromnow.d.ts
index ea7ef657a..d2b90891e 100644
--- a/fromnow/fromnow.d.ts
+++ b/fromnow/fromnow.d.ts
@@ -12,13 +12,13 @@ declare namespace FromNow {
export interface FromNowStatic {
/**
* Get readable time differences from now vs past or future dates.
- * @param {string} date
+ * @param {string|Date} date
* @param {object} [opts]
* @param {number} [opts.maxChucks=10]
* @param {boolean} [opts.useAgo=false]
* @param {boolean} [opts.useAnd=false]
*/
- (date: string, opts?: FromNowOpts): string
+ (date: string|Date, opts?: FromNowOpts): string
}
}
diff --git a/fs-extra-promise/fs-extra-promise.d.ts b/fs-extra-promise/fs-extra-promise.d.ts
index 77de92934..2243a4d1c 100644
--- a/fs-extra-promise/fs-extra-promise.d.ts
+++ b/fs-extra-promise/fs-extra-promise.d.ts
@@ -166,7 +166,8 @@ declare module "fs-extra-promise" {
export function watch(filename: string, options?: { persistent?: boolean; }, listener?: (event: string, filename: string) => any): FSWatcher;
export function exists(path: string, callback?: (exists: boolean) => void): void;
export function existsSync(path: string): boolean;
- export function ensureDir(path: string, cb: (err: Error) => void): void;
+ export function ensureDir(path: string, cb: (err: Error) => void): void;
+ export function ensureDirSync(path: string): void;
export interface OpenOptions {
encoding?: string;
diff --git a/gapi/gapi.d.ts b/gapi/gapi.d.ts
index 9a5f32eba..9e4e603bb 100644
--- a/gapi/gapi.d.ts
+++ b/gapi/gapi.d.ts
@@ -127,13 +127,21 @@ declare namespace gapi.auth {
}
declare namespace gapi.client {
+ /**
+ * Loads the client library interface to a particular API. If a callback is not provided, a promise is returned.
+ * @param name The name of the API to load.
+ * @param version The version of the API to load.
+ * @return promise The promise that get's resolved after the request is finished.
+ */
+ export function load(name: string, version: string): Promise
+
/**
* Loads the client library interface to a particular API. The new API interface will be in the form gapi.client.api.collection.method.
* @param name The name of the API to load.
* @param version The version of the API to load
* @param callback the function that is called once the API interface is loaded
*/
- export function load(name: string, version: string, callback?: () => any): void;
+ export function load(name: string, version: string, callback: () => any): void;
/**
* Creates a HTTP request for making RESTful requests.
* An object encapsulating the various arguments for this method.
diff --git a/geojson/geojson-tests.ts b/geojson/geojson-tests.ts
index ed953520b..ce38b654b 100644
--- a/geojson/geojson-tests.ts
+++ b/geojson/geojson-tests.ts
@@ -1,6 +1,6 @@
///
-var featureCollection: GeoJSON.FeatureCollection = {
+var featureCollection: GeoJSON.FeatureCollection = {
type: "FeatureCollection",
features: [
{
@@ -54,7 +54,7 @@ var featureCollection: GeoJSON.FeatureCollection = {
}
}
-var feature: GeoJSON.Feature = {
+var feature: GeoJSON.Feature = {
type: "Feature",
bbox: [-180.0, -90.0, 180.0, 90.0],
geometry: {
diff --git a/geojson/geojson.d.ts b/geojson/geojson.d.ts
index f74778315..d77de1fe8 100644
--- a/geojson/geojson.d.ts
+++ b/geojson/geojson.d.ts
@@ -90,9 +90,9 @@ declare namespace GeoJSON {
/***
* http://geojson.org/geojson-spec.html#feature-objects
*/
- export interface Feature extends GeoJsonObject
+ export interface Feature extends GeoJsonObject
{
- geometry: GeometryObject;
+ geometry: T;
properties: any;
id?: string;
}
@@ -100,9 +100,9 @@ declare namespace GeoJSON {
/***
* http://geojson.org/geojson-spec.html#feature-collection-objects
*/
- export interface FeatureCollection extends GeoJsonObject
+ export interface FeatureCollection extends GeoJsonObject
{
- features: Feature[];
+ features: Feature[];
}
/***
diff --git a/gm/gm.d.ts b/gm/gm.d.ts
index d7272397e..964decdee 100644
--- a/gm/gm.d.ts
+++ b/gm/gm.d.ts
@@ -9,6 +9,9 @@ declare module "gm" {
import stream = require('stream');
function m(image: string): m.State;
+ function m(stream:NodeJS.ReadableStream, image?: string): m.State;
+ function m(buffer:Buffer, image?: string): m.State;
+ function m(width:number, height:number, color?:string): m.State;
namespace m {
export interface ClassOptions {
diff --git a/googlemaps/google.maps.d.ts b/googlemaps/google.maps.d.ts
index 14075c446..65776131d 100644
--- a/googlemaps/google.maps.d.ts
+++ b/googlemaps/google.maps.d.ts
@@ -1638,7 +1638,10 @@ declare namespace google.maps {
}
/***** Events *****/
- export interface MapsEventListener { }
+ export interface MapsEventListener {
+ /** Removes the listener. Equivalent to calling google.maps.event.removeListener(listener). */
+ remove(): void;
+ }
export class event {
/**
diff --git a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor-tests.ts b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor-tests.ts
index b2bdf3b8d..36a948d62 100644
--- a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor-tests.ts
+++ b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor-tests.ts
@@ -1,10 +1,23 @@
-///
+///
import * as i18next from "i18next";
-import sprintf from "i18next-sprintf-postprocessor";
+import * as sprintfA from "i18next-sprintf-postprocessor";
+import sprintfB from "i18next-sprintf-postprocessor/dist/commonjs";
function initTest() {
const i18nextOptions = {};
- i18next.use(sprintf).init(i18nextOptions);
- i18next.init({ overloadTranslationOptionHandler: sprintf.overloadTranslationOptionHandler });
+ i18next
+ .use(sprintfA)
+ .use(sprintfB)
+ .init(i18nextOptions);
+ i18next
+ .init({ overloadTranslationOptionHandler: sprintfA.overloadTranslationOptionHandler });
+ i18next
+ .init({ overloadTranslationOptionHandler: sprintfB.overloadTranslationOptionHandler });
+}
+
+function tTest() {
+ i18next.t('interpolationTest1', 'a', 'b', 'c', 'd');
+ i18next.t('interpolationTest3', 'z');
+ i18next.t('interpolationTest4', 0);
}
diff --git a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts
index a069e45ff..1c0cf25ab 100644
--- a/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts
+++ b/i18next-sprintf-postprocessor/i18next-sprintf-postprocessor.d.ts
@@ -3,29 +3,32 @@
// Definitions by: Cyril Schumacher
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
-///
-///
+///
declare namespace I18next {
- interface I18nextOptions extends i18nextSprintfPostProcessor.I18nextOptions {}
-}
-
-declare namespace i18nextSprintfPostProcessor {
- interface I18nextOptions {
- overloadTranslationOptionHandler?(args: Array): void;
- process?(value: any, key: string, options: Object): void;
- }
+ interface I18n {
+ t(key: string, ...args: any[]): string;
+ }
}
declare module "i18next-sprintf-postprocessor" {
import i18next = require("i18next");
- interface i18nextSprintfPostProcessor {
- (): any;
- process(value: any, key: string, options: Object): void;
- overloadTranslationOptionHandler(args: Array): void;
+ interface I18nextSprintfPostProcessor {
+ name: string;
+ type: string;
+ process(value: any, key: string, options: any): any;
+ overloadTranslationOptionHandler(args: string[]): {
+ postProcess: "sprintf",
+ sprintf: string[]
+ };
}
- var sprintf: i18nextSprintfPostProcessor;
+ var sprintf: I18nextSprintfPostProcessor;
+ export = sprintf;
+}
+
+declare module "i18next-sprintf-postprocessor/dist/commonjs" {
+ import sprintf = require("i18next-sprintf-postprocessor");
export default sprintf;
}
diff --git a/i18next/i18next-2.0.17.d.ts b/i18next/i18next-2.0.17.d.ts
index c8f803f05..61cff428a 100644
--- a/i18next/i18next-2.0.17.d.ts
+++ b/i18next/i18next-2.0.17.d.ts
@@ -5,10 +5,7 @@
// Sources: https://github.com/jamuhl/i18next/
-///
///
-///
-///
declare namespace I18next {
export interface I18nextStatic {}
diff --git a/jquery-handsontable/jquery-handsontable.d.ts b/jquery-handsontable/jquery-handsontable.d.ts
index 48f1bf790..14a6ab1b6 100644
--- a/jquery-handsontable/jquery-handsontable.d.ts
+++ b/jquery-handsontable/jquery-handsontable.d.ts
@@ -280,7 +280,7 @@ declare namespace Handsontable {
/**
* Setting to true enables the autoColumnSize plugin, which makes sure each column gets enough space to show its content.
*/
- autoColumnSize?: boolean;
+ autoColumnSize?: boolean | Object;
/**
* Setting to true enables the observeChanges plugin, which automatically renders the table when a change in the data source is observed.
diff --git a/jsen/jsen-tests.ts b/jsen/jsen-tests.ts
new file mode 100644
index 000000000..9957a0120
--- /dev/null
+++ b/jsen/jsen-tests.ts
@@ -0,0 +1,3482 @@
+///
+
+import jsen = require("jsen");
+import JsenSettings = Jsen.JsenSettings;
+
+// any
+{
+ // passes validation on any type
+ {
+ const schema = { type: "any" };
+ const validate = jsen(schema);
+
+ console.assert(validate(null));
+ console.assert(validate(undefined));
+ console.assert(validate(0));
+ console.assert(validate(''));
+ console.assert(validate(Math.PI));
+ console.assert(validate('abc'));
+ console.assert(validate(77));
+ console.assert(validate(false));
+ console.assert(validate(true));
+ console.assert(validate({}));
+ console.assert(validate([]));
+ }
+}
+
+// type: array
+{
+ // required
+ {
+ const schema = { type: 'array' };
+ const validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate([]));
+ }
+ // nullable
+ {
+ const schema = { type: ['array', 'null'] };
+ const validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(null));
+ console.assert(validate([]));
+ }
+
+ // type
+ {
+ const schema = { type: 'array' };
+ const validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate(false));
+ console.assert(!validate({}));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate([]));
+ }
+
+ // minItems
+ {
+ const schema = { type: 'array', minItems: 3 };
+ const validate = jsen(schema);
+
+ console.assert(!validate([]));
+ console.assert(!validate([1, 2]));
+
+ console.assert(validate([1, 2, 3]));
+ console.assert(validate([1, 2, 3, 4]));
+ }
+
+ // maxItems
+ {
+ const schema = { type: 'array', maxItems: 3 };
+ const validate = jsen(schema);
+
+ console.assert(!validate([1, 2, 3, 4]));
+
+ console.assert(validate([]));
+ console.assert(validate([1, 2, 3]));
+ }
+
+ // items: object
+ {
+ let schema: any = { type: 'array', items: { type: 'string' } };
+ let validate = jsen(schema);
+
+ console.assert(!validate(null));
+ console.assert(!validate([1]));
+ console.assert(!validate(['a', false, 'b']));
+ console.assert(!validate(['a', 'b', 1]));
+
+ console.assert(validate([]));
+ console.assert(validate(['a']));
+ console.assert(validate(['a', 'b', 'c']));
+
+ schema = {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ strProp: { type: 'string' },
+ boolProp: { type: 'boolean' }
+ },
+ required: ['strProp']
+ }
+ };
+
+ validate = jsen(schema);
+
+ console.assert(!validate([123]));
+ console.assert(!validate([{}]));
+ console.assert(!validate([{
+ strProp: 'value',
+ boolProp: 123
+ }]));
+
+ console.assert(validate([{
+ strProp: 'value',
+ boolProp: false
+ }]));
+ }
+
+ // items: array
+ {
+ const schema = {
+ type: 'array',
+ items: [
+ { type: 'string' },
+ { type: 'number' }
+ ]
+ };
+
+ const validate = jsen(schema);
+
+ console.assert(!validate([1]));
+ console.assert(!validate([1, 'a']));
+
+ console.assert(validate([]));
+ console.assert(validate(['a']));
+ console.assert(validate(['a', 1]));
+ console.assert(validate(['a', 1, null, 'b', 2]));
+ }
+
+ // additionalItems: boolean
+ {
+ let schema: any = { type: 'array', additionalItems: false };
+ let validate = jsen(schema);
+
+ console.assert(validate([]));
+ console.assert(validate([1]));
+ console.assert(validate([1, 'a', true]));
+
+ schema.items = { type: 'number' };
+ validate = jsen(schema);
+
+ console.assert(!validate(['a']));
+
+ console.assert(validate([]));
+ console.assert(validate([1]));
+ console.assert(validate([1, 2, 3]));
+
+ schema.items = [
+ { type: 'string' },
+ { type: 'number' }
+ ];
+ validate = jsen(schema);
+
+ console.assert(!validate(['a', 1, 2]));
+
+ console.assert(validate([]));
+ console.assert(validate(['a']));
+ console.assert(validate(['a', 1]));
+ }
+
+ // additionalItems: object
+ {
+ // when `items` is an object schema, `additionalItems`
+ // is ignored and must not validate against
+ let schema: any = {
+ type: 'array',
+ items: {
+ type: 'string'
+ },
+ additionalItems: {
+ type: 'number'
+ }
+ };
+
+ let validate = jsen(schema);
+
+ console.assert(!validate(['abc', 'def', 123]));
+
+ // same as above description - only strings are valid
+ console.assert(validate(['abc', 'def']));
+
+ // when `items` is an array, any other positional
+ // data item must validate against `additionalItems`
+ schema.items = [
+ { type: 'string' },
+ { type: 'boolean' }
+ ];
+ validate = jsen(schema);
+
+ console.assert(!validate(['abc', false, 'def']));
+
+ console.assert(validate(['abc', false]));
+ console.assert(validate(['abc', false, 123]));
+ console.assert(validate(['abc', false, 123, Math.PI]));
+
+ // when `additionalItems` is an empty object, anything is valid
+ schema.additionalItems = {};
+ validate = jsen(schema);
+
+ console.assert(validate(['abc', false, 'def', 123, {}, null]));
+ }
+
+ // uniqueItems
+ {
+ let schema = {
+ type: 'array',
+ items: { type: 'number' },
+ uniqueItems: false
+ };
+
+ let validate = jsen(schema);
+
+ console.assert(validate([1, 2, 1]));
+
+ schema.uniqueItems = true;
+ validate = jsen(schema);
+
+ console.assert(!validate([1, 2, 1]));
+
+ console.assert(validate([1, 2, 3]));
+ }
+}
+
+// type: boolean
+{
+ // required
+ {
+ const schema = { type: 'boolean' };
+ const validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate(false));
+ console.assert(validate(true));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['boolean', 'null'] };
+ const validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(true));
+ console.assert(validate(false));
+ console.assert(validate(null));
+ }
+
+ // type
+ {
+ const schema = { type: 'boolean' };
+ const validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(true));
+ console.assert(validate(false));
+ }
+}
+
+// build
+{
+ // validator function has a build property
+ {
+ const validate = jsen({});
+
+ console.assert(typeof validate.build === 'function');
+ console.assert(validate.build.length === 2);
+ }
+
+ // returns default value from schema if initial undefined
+ {
+ const validate = jsen({ type: 'string', default: 'abc' });
+
+ console.assert(validate.build() === 'abc');
+ console.assert(validate.build(undefined) === 'abc');
+ }
+
+ // does not modify initial defined value
+ {
+ const validate = jsen({ type: 'string', default: 'abc' });
+ const initials = [
+ null,
+ '',
+ 'string value',
+ true,
+ false,
+ 123,
+ Math.PI
+ ];
+
+ let obj: any;
+
+ initials.forEach((initial) => {
+ obj = validate.build(initial);
+ console.assert(obj === initial);
+ });
+ }
+
+ // returns a copy of initial defined value
+ {
+ const validate = jsen({ type: 'string', default: 'abc' });
+ const initials = [
+ {},
+ [],
+ new Date()
+ ];
+
+ let obj: any;
+
+ initials.forEach((initial) => {
+ obj = validate.build(initial);
+ console.assert(obj !== initial);
+ console.assert(JSON.stringify(obj) === JSON.stringify(initial));
+ });
+ }
+
+ // returns initial if no default in schema
+ {
+ const validate = jsen({}),
+ initials = [
+ undefined,
+ null,
+ '',
+ 'string value',
+ true,
+ false,
+ 123,
+ Math.PI,
+ {},
+ [],
+ new Date()
+ ];
+
+ let obj: any;
+
+ initials.forEach((initial) => {
+ obj = validate.build(initial);
+ console.assert(JSON.stringify(obj) === JSON.stringify(initial));
+ });
+ }
+
+ // returns the default value specified in schema
+ {
+ const schemas = [
+ { default: null },
+ { default: undefined },
+ { default: '' },
+ { default: 'abc' },
+ { default: true },
+ { default: false },
+ { default: 123 },
+ { default: Math.PI }
+ ];
+
+ schemas.forEach((schema) => {
+ let validate = jsen(schema);
+ console.assert(validate.build() === schema.default);
+ });
+ }
+
+ // returns a copy of a default object or array in schema
+ {
+ const schemas = [
+ { default: { a: { b: 123 } } },
+ { default: [[1, 2, 3], { a: { b: 123 } }] },
+ { default: /\d+/ },
+ { default: new Date('05/14/2015') }
+ ];
+
+ schemas.forEach((schema) => {
+ let validate = jsen(schema);
+ let def = validate.build();
+
+ console.assert(def !== schema.default);
+ console.assert(JSON.stringify(def) === JSON.stringify(schema.default));
+ });
+ }
+
+ // recursively collects default values
+ {
+ const schema: any = {
+ type: 'object',
+ default: {},
+ properties: {
+ a: {
+ type: 'array',
+ default: [],
+ items: {
+ type: 'string'
+ }
+ },
+ b: {
+ type: 'array',
+ default: [],
+ items: {
+ type: 'string',
+ default: 'abc'
+ }
+ },
+ c: {
+ type: 'object',
+ default: {},
+ properties: {
+ d: {
+ type: 'boolean',
+ default: false
+ },
+ e: {
+ type: 'date',
+ default: new Date('05/14/2015')
+ },
+ f: {
+ type: 'array',
+ default: [{}, {}],
+ items: [{
+ type: 'object',
+ properties: {
+ g: {
+ type: 'string',
+ default: 'yes'
+ }
+ }
+ }, {
+ type: 'object',
+ properties: {
+ g: {
+ type: 'integer',
+ default: 0
+ }
+ }
+ }, {
+ type: 'object',
+ properties: {
+ g: {
+ type: 'boolean',
+ default: true
+ }
+ }
+ }]
+ },
+ h: {
+ type: 'array',
+ default: [{}, {}],
+ items: {
+ type: 'object',
+ properties: {
+ i: {
+ type: 'object',
+ default: { foo: 'bar' }
+ }
+ }
+ }
+ },
+ i: {
+ type: 'object',
+ default: null,
+ properties: {
+ j: {
+ type: 'string',
+ default: 'baz'
+ }
+ }
+ }
+ }
+ },
+ j: {
+ type: 'object',
+ properties: {
+ k: {
+ type: 'boolean',
+ default: false
+ }
+ }
+ }
+ }
+ };
+
+ const expected: any = {
+ a: [],
+ b: [],
+ c: {
+ d: false,
+ e: new Date('05/14/2015'),
+ f: [
+ { g: 'yes' },
+ { g: 0 }
+ ],
+ h: [
+ { i: { foo: 'bar' } },
+ { i: { foo: 'bar' } }
+ ],
+ i: null
+ }
+ };
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // merges default values with the initial values
+ {
+ const schemas = [
+ {
+ properties: {
+ foo: { default: 'bar' }
+ }
+ },
+ {
+ properties: {
+ foo: { default: 'bar' }
+ }
+ },
+ {
+ properties: {
+ foo: { default: 'bar' }
+ }
+ },
+ {
+ items: {
+ properties: {
+ foo: { default: 'bar' }
+ }
+ }
+ },
+ {
+ items: {
+ properties: {
+ foo: { default: 'bar' }
+ }
+ }
+ },
+ {
+ items: [
+ { default: 'foo' },
+ { default: 'bar' },
+ { default: 'baz' }
+ ]
+ },
+ {
+ items: [
+ { default: 'foo' },
+ { default: 'bar' },
+ { default: 'baz' }
+ ]
+ }
+ ];
+
+ const defaults = [
+ {},
+ { foo: 'baz' },
+ { x: 'yz' },
+ [],
+ [{}],
+ [],
+ [null, {}, undefined, false]
+ ];
+
+ const expected = [
+ { foo: 'bar' },
+ { foo: 'baz' },
+ { foo: 'bar', x: 'yz' },
+ [],
+ [{ foo: 'bar' }],
+ ['foo', 'bar', 'baz'],
+ [null, {}, 'baz', false]
+ ];
+
+ schemas.forEach((schema, index) => {
+ let validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build(defaults[index])) === JSON.stringify(expected[index]));
+ });
+ }
+
+ // $ref
+ {
+ const schema = {
+ definitions: {
+ positiveInteger: {
+ type: 'integer',
+ minimum: 1,
+ default: 7
+ }
+ },
+ $ref: '#definitions/positiveInteger'
+ };
+
+ const validate = jsen(schema);
+ console.assert(validate.build() === 7);
+ }
+
+ // object
+ {
+ // clones default object and subproperties recursively
+ {
+ const schema = {
+ default: {},
+ properties: {
+ foo: {
+ type: 'string',
+ default: 'bar'
+ }
+ }
+ };
+
+ const expected = { foo: 'bar' };
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // does not recursively assign defaults of children if parent default is not an object
+ {
+ const schema: any = {
+ default: [],
+ properties: {
+ foo: {
+ type: 'string',
+ default: 'bar'
+ }
+ }
+ };
+
+ const expected: any = [];
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+ }
+
+ // array
+ {
+ // does not add new elements to default array: items schema is an object
+ {
+ const schema: any = {
+ default: [],
+ items: {
+ type: 'string',
+ default: 'bar'
+ }
+ };
+
+ const expected: any = [];
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // adds new elements to default array: items schema is an array
+ {
+ const schema: any = {
+ default: [],
+ items: [{
+ type: 'string',
+ default: 'bar'
+ }]
+ };
+
+ const expected = ['bar'];
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // adds default values to already existing child items of compatible type only: items schema is an object
+ {
+ const schema: any = {
+ default: [{}, null, []],
+ items: {
+ properties: {
+ foo: {
+ type: 'string',
+ default: 'bar'
+ }
+ }
+ }
+ };
+
+ const expected: any = [{ foo: 'bar' }, null, []];
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // adds default values to already existing child items of compatible type only: items schema is an array
+ {
+ const schema: any = {
+ default: [{}, null, {}, undefined],
+ items: [
+ {
+ properties: {
+ foo: {
+ type: 'string',
+ default: 'bar'
+ }
+ }
+ },
+ { default: 'abc' },
+ { default: 123 },
+ { default: 123 }
+ ]
+ };
+
+ const expected = [{ foo: 'bar' }, null, {}, 123];
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+
+ // does not assign default child items if parent default is not an array
+ {
+ const schema: any = {
+ default: 'foobar',
+ items: {
+ type: 'string',
+ default: 'bar'
+ }
+ };
+
+ const expected = 'foobar';
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build()) === JSON.stringify(expected));
+ }
+ }
+
+ // option: copy
+ {
+ // returns deep copy of the initial object by default
+ {
+ const schema = {};
+ const initial = {};
+
+ const validate = jsen(schema);
+
+ console.assert(JSON.stringify(validate.build(initial)) === JSON.stringify(initial));
+ console.assert(validate.build(initial) !== initial);
+ }
+
+ // modifies the initial object when copy = false
+ {
+ const schema = {
+ properties: {
+ a: { default: 'foo' },
+ b: {
+ items: {
+ properties: {
+ c: { default: 'bar' },
+ d: { default: 'baz' }
+ }
+ }
+ }
+ }
+ };
+
+ const initial = { b: [{ d: 'xyz' }] };
+ const expected = { a: 'foo', b: [{ c: 'bar', d: 'xyz' }] };
+
+ const validate = jsen(schema);
+ const actual = validate.build(initial, { copy: false });
+
+ console.assert(JSON.stringify(actual) === JSON.stringify(expected));
+ console.assert(actual === initial);
+ }
+ }
+
+ // option: additionalProperties
+ {
+ // includes by default
+ {
+ const schema = {
+ properties: {
+ foo: {}
+ }
+ };
+
+ const initial = { foo: 1, bar: 2 };
+ const expected = { foo: 1, bar: 2 };
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build(initial)) === JSON.stringify(expected));
+ }
+
+ // excludes when schema.additionalProperties = false
+ {
+ const schema = {
+ additionalProperties: false,
+ properties: {
+ foo: {}
+ }
+ };
+
+ const initial = { foo: 1, bar: 2 };
+ const expected = { foo: 1 };
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build(initial)) === JSON.stringify(expected));
+ }
+
+ // removes from the initial object when schema.additionalProperties = false and options.copy = false
+ {
+ const schema = {
+ additionalProperties: false,
+ properties: {
+ foo: {}
+ }
+ };
+
+ const initial = { foo: 1, bar: 2 };
+ const expected = { foo: 1 };
+
+ const validate = jsen(schema);
+ const actual = validate.build(initial, { copy: false });
+
+ console.assert(actual === initial);
+ console.assert(JSON.stringify(actual) === JSON.stringify(expected));
+ }
+
+ // removes from the initial object when options.additionalProperties = false and options.copy = false
+ {
+ const schema = {
+ properties: {
+ foo: {}
+ }
+ };
+
+ const initial = { foo: 1, bar: 2 };
+ const expected = { foo: 1 };
+
+ const validate = jsen(schema);
+ const actual = validate.build(initial, {
+ copy: false,
+ additionalProperties: false
+ });
+
+ console.assert(actual === initial);
+ console.assert(JSON.stringify(actual) === JSON.stringify(expected));
+ }
+
+ // schema.additionalProperties takes precedence
+ {
+ const schema = {
+ additionalProperties: true,
+ properties: {
+ foo: {}
+ }
+ };
+
+ const initial = { foo: 1, bar: 2 };
+ const expected = { foo: 1, bar: 2 };
+
+ const validate = jsen(schema);
+ console.assert(JSON.stringify(validate.build(initial, { additionalProperties: false })) === JSON.stringify(expected));
+ }
+ }
+}
+
+// clone
+{
+ const clone = jsen.clone;
+
+ // string
+ {
+ console.assert(clone('abc') === 'abc');
+ }
+
+ // number
+ {
+ console.assert(clone(123) === 123);
+ }
+
+ // integer
+ {
+ console.assert(clone(Math.PI) === Math.PI);
+ }
+
+ // boolean
+ {
+ console.assert(clone(false) === false);
+ }
+
+ // function
+ {
+ const func = () => {
+ };
+ console.assert(clone(func) === func);
+ }
+
+ // regexp
+ {
+ const regex = /a/gim;
+ console.assert(clone(regex) !== regex);
+ console.assert(clone(regex).toString() === regex.toString());
+ }
+
+ // date
+ {
+ const today = new Date('05/14/2015');
+ console.assert(clone(today) !== today);
+ console.assert(clone(today).toJSON() === today.toJSON());
+ }
+
+ // null
+ {
+ console.assert(clone(null) === null);
+ }
+
+ // undefined
+ {
+ console.assert(clone(undefined) === undefined);
+ }
+
+ // object
+ {
+ const obj = { a: 1, b: 'a', c: false, d: { e: Math.PI, f: [1, 2, 3] } };
+ console.assert(clone(obj) !== obj);
+ console.assert(JSON.stringify(clone(obj)) === JSON.stringify(obj));
+ }
+
+ // array
+ {
+ const arr = [1, 'a', false, { d: [1, 2, 3] }];
+ console.assert(clone(arr) !== arr);
+ console.assert(JSON.stringify(clone(arr)) === JSON.stringify(arr));
+ }
+}
+
+// type: date
+{
+ // required
+ {
+ const schema = { type: 'date' };
+ const validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate(new Date()));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['date', 'null'] };
+ const validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(new Date()));
+ console.assert(validate(null));
+ }
+
+ // type
+ {
+ const schema = { type: 'date' };
+ const validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(new Date()));
+ }
+}
+
+// equal
+{
+ const equal = jsen.equal;
+ // string
+ {
+ console.assert(equal('a', 'a'));
+ console.assert(!equal('a', 'b'));
+ }
+
+ // number
+ {
+ console.assert(equal(123, 123));
+ console.assert(equal(Math.PI, Math.PI));
+ console.assert(!equal(Math.PI, Math.E));
+ }
+
+ // boolean
+ {
+ console.assert(equal(true, true));
+ console.assert(!equal(true, false));
+ }
+
+ // null
+ {
+ console.assert(equal(null, null));
+ console.assert(!equal(null, undefined));
+ }
+
+ // undefined
+ {
+ console.assert(equal(undefined, undefined));
+ console.assert(!equal(null, undefined));
+ }
+
+ // function
+ {
+ const f1 = () => {
+ };
+ const f2 = () => {
+ };
+ const f3 = f1;
+
+ // two functions are only equal if they
+ // reference the same function object
+ console.assert(equal(f1, f3));
+ console.assert(!equal(f1, f2));
+ }
+
+ // array
+ {
+ const f = () => {
+ };
+ const obj1 = { a: 123, b: 'abc', c: f };
+ const obj2 = { a: 123, b: 'abc', c: f };
+ const arr1 = [1, 'a', f, obj1];
+ const arr2 = [1, 'a', f, obj1];
+ const arr3 = [1, 'a', f];
+ const arr4 = [1, 'a', f, obj2];
+
+ console.assert(equal(arr1, arr2));
+ console.assert(equal(arr1, arr4));
+
+ console.assert(!equal(arr1, arr3));
+ }
+
+ // object
+ {
+ const a = { a: 123, b: ['abc'], c: {} };
+ const b = { b: ['abc'], c: {}, a: 123 };
+ const c = a;
+ const d: any = { a: 123, b: ['abc'], c: { d: undefined } };
+
+ console.assert(equal(a, b));
+ console.assert(equal(a, c));
+
+ console.assert(!equal(a, d));
+ }
+
+ // regexp
+ {
+ const a = /a+/gim;
+ const b = new RegExp('a+', 'gim');
+ const c = /a/gim;
+ const d = a;
+
+ console.assert(equal(a, b));
+ console.assert(equal(a, d));
+
+ console.assert(!equal(a, c));
+ }
+}
+
+// error
+{
+ // errors is empty array before validation
+ {
+ const schema = { type: 'number' };
+ const validate = jsen(schema);
+
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 0);
+ }
+
+ // no errors on successful validation
+ {
+ const schema = { type: 'number' };
+ const validate = jsen(schema);
+ const valid = validate(123);
+
+ console.assert(valid);
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 0);
+ }
+
+ // has errors when validation unsuccessful
+ {
+ const schema = { type: 'number' };
+ const validate = jsen(schema);
+ const valid = validate('123');
+
+ console.assert(!valid);
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 1);
+ }
+
+ // clears errors on successive validation calls
+ {
+ const schema = { type: 'number' };
+ const validate = jsen(schema);
+
+ validate('123');
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 1);
+
+ validate(123);
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 0);
+
+ validate('123');
+ console.assert(Array.isArray(validate.errors));
+ console.assert(validate.errors.length === 1);
+ }
+
+ // two successive runs return different arrays
+ {
+ const schema = { type: 'number' };
+ const validate = jsen(schema);
+
+ let previous: any;
+
+ validate('123');
+ console.assert(validate.errors.length === 1);
+ previous = validate.errors;
+
+ validate('123');
+ console.assert(validate.errors.length === 1);
+
+ console.assert(validate.errors !== previous);
+ console.assert(JSON.stringify(validate.errors) === JSON.stringify(previous));
+ }
+
+ // error object
+ {
+ const schemas = [
+ {
+ type: 'number'
+ },
+
+ {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'string'
+ }
+ }
+ },
+
+ {
+ type: 'array',
+ uniqueItems: true
+ },
+
+ {
+ type: 'array',
+ items: {
+ maximum: 10
+ }
+ },
+
+ {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'array',
+ items: [{
+ type: 'object',
+ properties: {
+ b: {
+ multipleOf: 7
+ }
+ }
+ }]
+ }
+ }
+ },
+
+ {
+ allOf: [
+ { minimum: 5 },
+ { maximum: 10 }
+ ]
+ },
+
+ {
+ type: 'object',
+ properties: {
+ a: {
+ anyOf: [
+ { type: 'string' },
+ { type: 'number' }
+ ]
+ }
+ }
+ },
+
+ {
+ type: 'array',
+ items: [{
+ type: 'object',
+ properties: {
+ a: {
+ oneOf: [
+ { type: 'boolean' },
+ { type: 'null' }
+ ]
+ }
+ }
+ }]
+ },
+
+ {
+ type: 'object',
+ properties: {
+ a: {
+ not: {
+ type: 'string'
+ }
+ }
+ }
+ },
+
+ {
+ definitions: {
+ positiveInteger: {
+ type: 'integer',
+ minimum: 0,
+ exclusiveMinimum: true
+ }
+ },
+ type: 'object',
+ properties: {
+ a: {
+ type: 'object',
+ properties: {
+ b: {
+ type: 'object',
+ properties: {
+ c: {
+ $ref: '#/definitions/positiveInteger'
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ {
+ type: 'object',
+ required: ['a', 'b']
+ },
+
+ {
+ type: 'object',
+ dependencies: {
+ a: {
+ required: ['b']
+ }
+ }
+ },
+
+ {
+ type: 'object',
+ dependencies: {
+ a: ['b']
+ }
+ }
+ ];
+
+ const data = [
+ '123',
+ { a: 123 },
+ [7, 11, 7],
+ [10, 11, 9],
+ { a: [{ b: 8 }] },
+ 12,
+ { a: false },
+ [{ a: 123 }],
+ { a: 'abc' },
+ { a: { b: { c: 0 } } },
+ {},
+ { a: 123 },
+ { a: 123 }
+ ];
+
+ // property: path
+ {
+ const expectedPaths = [
+ [''],
+ ['a'],
+ [''],
+ ['1'],
+ ['a.0.b'],
+ [''],
+ ['a', 'a'],
+ ['0.a', '0.a', '0.a'],
+ ['a'],
+ ['a.b.c'],
+ ['a'],
+ ['b'],
+ ['b']
+ ];
+
+ schemas.forEach((schema, index) => {
+ let validate = jsen(schema);
+ let valid = validate(data[index]);
+
+ console.assert(!valid);
+
+ expectedPaths[index].forEach((path, pindex) => {
+ try {
+ console.assert(validate.errors[pindex].path === path);
+ }
+ catch (e) {
+ // console.log(index);
+ // console.log(validate.errors);
+ throw e;
+ }
+ });
+ });
+ }
+
+ // property: keyword
+ {
+ const expectedKeywords = [
+ ['type'],
+ ['type'],
+ ['uniqueItems'],
+ ['maximum'],
+ ['multipleOf'],
+ ['maximum'],
+ ['type', 'type', 'anyOf'],
+ ['type', 'type', 'oneOf'],
+ ['not'],
+ ['exclusiveMinimum'],
+ ['required'],
+ ['required'],
+ ['dependencies']
+ ];
+
+ schemas.forEach((schema, index) => {
+ let validate = jsen(schema);
+ let valid = validate(data[index]);
+
+ console.assert(!valid);
+
+ expectedKeywords[index].forEach((keyword, kindex) => {
+ try {
+ console.assert(validate.errors[kindex].keyword === keyword);
+ }
+ catch (e) {
+ // console.log(index);
+ // console.log(validate.errors);
+ throw e;
+ }
+ });
+ });
+ }
+
+ // adds required property name to path
+ {
+ let schema: any = { type: 'object', required: ['a'] };
+ let validate = jsen(schema);
+ let valid = validate({});
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].path === 'a');
+ console.assert(validate.errors[0].keyword === 'required');
+
+ schema = {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'array',
+ items: {
+ type: 'object',
+ required: ['b']
+ }
+ }
+ }
+ };
+
+ validate = jsen(schema);
+ valid = validate({ a: [{}] });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].path === 'a.0.b');
+ console.assert(validate.errors[0].keyword === 'required');
+ }
+
+ // adds required dependency property to path
+ {
+ let schema: any = {
+ type: 'object',
+ dependencies: {
+ a: ['b']
+ }
+ };
+
+ let validate = jsen(schema);
+ let valid = validate({ a: 123 });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].path === 'b');
+ console.assert(validate.errors[0].keyword === 'dependencies');
+
+ schema = {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'array',
+ items: {
+ type: 'object',
+ dependencies: {
+ a: ['b']
+ }
+ }
+ }
+ }
+ };
+
+ validate = jsen(schema);
+ valid = validate({ a: [{ a: 123 }] });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].path === 'a.0.b');
+ console.assert(validate.errors[0].keyword === 'dependencies');
+ }
+ }
+
+ // multiple errors
+ {
+ const schema = {
+ definitions: {
+ array: {
+ maxItems: 1
+ }
+ },
+ type: 'object',
+ properties: {
+ a: {
+ anyOf: [
+ { items: { type: 'integer' } },
+ { $ref: '#/definitions/array' },
+ { items: [{ maximum: 3 }] }
+ ]
+ }
+ }
+ };
+
+ const data = { a: [Math.PI, Math.E] };
+ const validate = jsen(schema);
+
+ // returns multiple errors
+ {
+ const valid = validate(data);
+
+ // console.log(validate.errors);
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 5);
+ }
+ }
+
+ // custom errors
+ {
+ const schemas = [
+ {
+ type: 'string',
+ invalidMessage: 'string is invalid',
+ requiredMessage: 'string is required'
+ },
+ {
+ type: 'object',
+ required: ['a'],
+ properties: {
+ a: {
+ invalidMessage: 'a is invalid',
+ requiredMessage: 'a is required'
+ }
+ }
+ },
+ {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'object',
+ properties: {
+ b: {
+ invalidMessage: 'b is invalid',
+ requiredMessage: 'b is required'
+ }
+ },
+ required: ['b']
+ }
+ }
+ }
+ },
+ {
+ type: 'object',
+ properties: {
+ a: {
+ type: 'object',
+ properties: {
+ c: {
+ type: 'string',
+ invalidMessage: 'c is invalid',
+ requiredMessage: 'c is required'
+ }
+ }
+ }
+ }
+ }
+ ];
+
+ const data = [
+ undefined,
+ {},
+ [{ a: {} }],
+ { a: { c: 123 } }
+ ];
+
+ const expectedMessages = [
+ 'string is invalid',
+ 'a is required',
+ 'b is required',
+ 'c is invalid'
+ ];
+
+ schemas.forEach((schema, index) => {
+ //it(expectedMessages[index], function () {
+ let validate = jsen(schema);
+ let valid = validate(data[index]);
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === expectedMessages[index]);
+ //});
+ });
+ }
+
+ // custom keyword messages
+ {
+ // uses custom messages on keywords
+ {
+ const schemas: any = [
+ {
+ type: 'string',
+ messages: { type: 'custom message for keyword "type"' }
+ },
+ {
+ enum: [1, 2, 3],
+ messages: { enum: 'custom message for keyword "enum"' }
+ },
+ {
+ minimum: 3,
+ messages: { minimum: 'custom message for keyword "minimum"' }
+ },
+ {
+ minimum: 3,
+ exclusiveMinimum: true,
+ messages: { exclusiveMinimum: 'custom message for keyword "exclusiveMinimum"' }
+ },
+ {
+ maximum: 10,
+ messages: { maximum: 'custom message for keyword "maximum"' }
+ },
+ {
+ maximum: 10,
+ exclusiveMaximum: true,
+ messages: { exclusiveMaximum: 'custom message for keyword "exclusiveMaximum"' }
+ },
+ {
+ multipleOf: 5,
+ messages: { multipleOf: 'custom message for keyword "multipleOf"' }
+ },
+ {
+ minLength: 3,
+ messages: { minLength: 'custom message for keyword "minLength"' }
+ },
+ {
+ maxLength: 5,
+ messages: { maxLength: 'custom message for keyword "maxLength"' }
+ },
+ {
+ pattern: '\\d+',
+ messages: { pattern: 'custom message for keyword "pattern"' }
+ },
+ {
+ format: 'email',
+ messages: { format: 'custom message for keyword "format"' }
+ },
+ {
+ minItems: 1,
+ messages: { minItems: 'custom message for keyword "minItems"' }
+ },
+ {
+ maxItems: 1,
+ messages: { maxItems: 'custom message for keyword "maxItems"' }
+ },
+ {
+ additionalItems: false,
+ items: [{ type: 'string' }],
+ messages: { additionalItems: 'custom message for keyword "additionalItems"' }
+ },
+ {
+ uniqueItems: true,
+ messages: { uniqueItems: 'custom message for keyword "uniqueItems"' }
+ },
+ {
+ minProperties: 1,
+ messages: { minProperties: 'custom message for keyword "minProperties"' }
+ },
+ {
+ maxProperties: 1,
+ messages: { maxProperties: 'custom message for keyword "maxProperties"' }
+ },
+ {
+ required: ['foo'],
+ messages: { required: 'custom message for keyword "required"' }
+ },
+ {
+ required: ['foo'],
+ properties: {
+ foo: {
+ messages: {
+ required: 'custom message for keyword "required"'
+ }
+ }
+ }
+ },
+ {
+ required: ['foo'],
+ properties: {
+ foo: {
+ messages: {
+ required: 'this custom message for keyword "required" is assigned'
+ }
+ }
+ },
+ messages: { required: 'this custom message for keyword "required" is NOT assigned' }
+ },
+ {
+ additionalProperties: false,
+ messages: { additionalProperties: 'custom message for keyword "additionalProperties"' }
+ },
+ {
+ dependencies: {
+ foo: ['bar']
+ },
+ messages: { dependencies: 'custom message for keyword "dependencies"' }
+ },
+ {
+ anyOf: [
+ { type: 'string' },
+ { type: 'integer' }
+ ],
+ messages: { anyOf: 'custom message for keyword "anyOf"' }
+ },
+ {
+ oneOf: [
+ { type: 'string' },
+ { type: 'integer' }
+ ],
+ messages: { oneOf: 'custom message for keyword "oneOf"' }
+ },
+ {
+ not: {
+ type: 'string'
+ },
+ messages: { not: 'custom message for keyword "not"' }
+ }
+ ];
+
+ const data = [
+ 123,
+ 5,
+ 1,
+ 3,
+ 11,
+ 10,
+ 12,
+ 'ab',
+ 'abcdef',
+ 'abc',
+ 'invalid email',
+ [],
+ [1, 2, 3],
+ ['abc', 'def'],
+ [1, 2, 2],
+ {},
+ { foo: 1, bar: 2 },
+ {},
+ {},
+ {},
+ { foo: 'bar' },
+ { foo: 'abc' },
+ null,
+ null,
+ 'abc'
+ ];
+
+ const expectedMessages = [
+ schemas[0].messages.type,
+ schemas[1].messages.enum,
+ schemas[2].messages.minimum,
+ schemas[3].messages.exclusiveMinimum,
+ schemas[4].messages.maximum,
+ schemas[5].messages.exclusiveMaximum,
+ schemas[6].messages.multipleOf,
+ schemas[7].messages.minLength,
+ schemas[8].messages.maxLength,
+ schemas[9].messages.pattern,
+ schemas[10].messages.format,
+ schemas[11].messages.minItems,
+ schemas[12].messages.maxItems,
+ schemas[13].messages.additionalItems,
+ schemas[14].messages.uniqueItems,
+ schemas[15].messages.minProperties,
+ schemas[16].messages.maxProperties,
+ schemas[17].messages.required,
+ schemas[18].properties.foo.messages.required,
+ schemas[19].properties.foo.messages.required,
+ schemas[20].messages.additionalProperties,
+ schemas[21].messages.dependencies,
+ schemas[22].messages.anyOf,
+ schemas[23].messages.oneOf,
+ schemas[24].messages.not
+ ];
+
+ schemas.forEach((schema: any, index: number) => {
+ let validate = jsen(schema);
+ let valid = validate(data[index]);
+
+ console.assert(!valid);
+ console.assert(validate.errors[validate.errors.length - 1].message === expectedMessages[index]);
+ });
+ }
+
+ // does not use custom messages on keyword: items (object)
+ {
+ const schema = {
+ items: {
+ type: 'string',
+ messages: {
+ type: 'will be assigned'
+ }
+ },
+ messages: {
+ items: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate([123]);
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+
+ // does not use custom messages on keyword: items (array)
+ {
+ const schema = {
+ items: [{
+ type: 'string',
+ messages: {
+ type: 'will be assigned'
+ }
+ }],
+ messages: {
+ items: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate([123, 123]);
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+
+ // does not use custom messages on keyword: properties
+ {
+ const schema = {
+ properties: {
+ foo: {
+ type: 'number',
+ messages: {
+ type: 'will be assigned'
+ }
+ }
+ },
+ messages: {
+ properties: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate({ foo: 'bar' });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+
+ // does not use custom messages on keyword: patternProperties
+ {
+ const schema = {
+ patternProperties: {
+ '^foo$': {
+ type: 'number',
+ messages: {
+ type: 'will be assigned'
+ }
+ }
+ },
+ messages: {
+ patternProperties: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate({ foo: 'bar' });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+
+ // does not use custom messages on keyword: dependencies (schema)
+ {
+ const schema = {
+ dependencies: {
+ foo: {
+ minProperties: 2,
+ messages: {
+ minProperties: 'will be assigned'
+ }
+ }
+ },
+ messages: {
+ dependencies: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate({ foo: 'bar' });
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+
+ // does not use custom messages on keyword: allOf
+ {
+ const schema = {
+ dependencies: {
+ foo: {
+ minProperties: 2,
+ messages: {
+ minProperties: 'will be assigned'
+ }
+ }
+ },
+ allOf: [
+ {
+ minimum: 2,
+ messages: {
+ minimum: 'will not be assigned'
+ }
+ },
+ {
+ maximum: 5,
+ messages: {
+ maximum: 'will be assigned'
+ }
+ }
+ ],
+ messages: {
+ allOf: 'will not be assigned'
+ }
+ };
+
+ const validate = jsen(schema);
+ const valid = validate(6);
+
+ console.assert(!valid);
+ console.assert(validate.errors.length === 1);
+ console.assert(validate.errors[0].message === 'will be assigned');
+ }
+ }
+}
+
+const doesThrow = (func: Function) => {
+ try {
+ func();
+ }
+ catch (e) {
+ return true;
+ }
+
+ return false;
+};
+
+const doesNotThrow = (func: Function) => {
+ return !doesThrow(func);
+};
+
+// fixes
+{
+ // Fix broken inlining of regular expressions containing slashes (#15, #25)
+ {
+ const schema = {
+ type: 'string',
+ pattern: '^/dev/[^/]+(/[^/]+)*$'
+ };
+
+ console.assert(doesNotThrow(jsen(schema)));
+ }
+
+ // Fix code generation breaks when object properties in schema are not valid identifiers (#16)
+ {
+ const schema = {
+ type: 'object',
+ properties: {
+ 123: {
+ type: 'boolean'
+ }
+ }
+ };
+
+ console.assert(doesNotThrow(() => {
+ let validate = jsen(schema);
+ console.assert(validate({ 123: true }));
+ })
+ );
+ }
+
+ // Fix cannot dereference schema when ids change resolution scope (#14)
+ {
+ let schema: any = {
+ $ref: '#child',
+ definitions: {
+ child: {
+ id: '#child',
+ type: 'string'
+ }
+ }
+ };
+
+ console.assert(doesNotThrow(() => {
+ let validate = jsen(schema);
+
+ console.assert(validate('abc'));
+ console.assert(!validate(123));
+ })
+ );
+
+
+ schema = {
+ $ref: '#child/definitions/subchild',
+ definitions: {
+ child: {
+ id: '#child',
+ definitions: {
+ subchild: {
+ type: 'number'
+ }
+ }
+ }
+ }
+ };
+
+ console.assert(doesThrow(() => {
+ let validate = jsen(schema);
+ })
+ );
+ }
+
+ // Fix recursive calls to the same cached $ref validator resets the error object
+ {
+ const schema = {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ foo: { $ref: '#' }
+ },
+ required: ['foo']
+ }
+ };
+
+ const validate = jsen(schema);
+
+ console.assert(validate([{ foo: [] }]));
+ console.assert(validate([{ foo: [{ foo: [] }] }]));
+ console.assert(!validate([{ bar: [] }]));
+ console.assert(!validate([{ foo: [{ foo: [] }, { bar: [] }] }])); // Bug! False positive
+ }
+}
+
+// format
+{
+ // date-time
+ {
+ const schema = { format: 'date-time' };
+ const validate = jsen(schema);
+
+ console.assert(validate(new Date().toJSON()));
+
+ console.assert(!validate(''));
+ console.assert(!validate(new Date().toUTCString()));
+ console.assert(!validate(new Date().toLocaleDateString()));
+ console.assert(!validate(new Date().toTimeString()));
+ }
+
+ // uri
+ {
+ const schema = { format: 'uri' };
+ const validate = jsen(schema);
+
+ console.assert(validate('http://google.com'));
+ console.assert(validate('ftp://my-site'));
+ console.assert(validate('custom://my-site/long/$cr@mbl3d/u_r-l?with=query%20string'));
+ console.assert(validate('//no-scheme-here'));
+
+ console.assert(!validate(''));
+ console.assert(!validate('google'));
+ console.assert(!validate('/google'));
+ console.assert(!validate('://google'));
+ console.assert(!validate('http://google.com/no space allowed'));
+ }
+
+ // email
+ {
+ const schema = { format: 'email' };
+ const validate = jsen(schema);
+ const maxLongHostname1 = new Array(5).join('.' + new Array(64).join('a')).substr(1); // 255 chars (4 groups x 63 chars)
+ const maxLongHostname2 = new Array(9).join('.' + new Array(32).join('a')).substr(1); // 255 chars (8 groups x 31 chars)
+
+ console.assert(validate('me@domain'));
+ console.assert(validate('first.last+plus-dash#hash!bang$dollar%percent&\'quote*star/dash=equal?question^pow_under`backtick{brace}|bar~tilde@domain'));
+ console.assert(validate('me@domain.with.multiple.subdomains'));
+ console.assert(validate('me@domain-parts.may.contain-dashes'));
+ console.assert(validate('me@a-single-domain-part-can-be-up-to-sixty-three-characters-long63'));
+ console.assert(validate('me@' + maxLongHostname1));
+ console.assert(validate('me@' + maxLongHostname2));
+
+ console.assert(!validate(''));
+ console.assert(!validate('qu"ote\'s@domain'));
+ console.assert(!validate('me@no_underscores+or?special$chars'));
+ console.assert(!validate('me@ends-with-dash-'));
+ console.assert(!validate('me@-starts-with-dash'));
+ console.assert(!validate('me@asingle-domain-part-cannot-be-longer-than-sixty-three-characters'));
+
+ // These verify that a hostname cannot be longer than 255 chars in total. However,
+ // maximum string length verification cannot be performed in the same regex, so
+ // these test cases fail. Users must additionall use the `maxlength` keyword in this case.
+ // assert(!validate('me@' + maxLongHostname1 + '.a'));
+ // assert(!validate('me@' + maxLongHostname2 + '.a'));
+ }
+
+ // ipv4
+ {
+ const schema = { format: 'ipv4' };
+ const validate = jsen(schema);
+
+ console.assert(validate('0.0.0.0'));
+ console.assert(validate('255.255.255.255'));
+ console.assert(validate('127.0.0.1'));
+
+ console.assert(!validate(''));
+ console.assert(!validate('...'));
+ console.assert(!validate('0.0.0.-1'));
+ console.assert(!validate('0.0.-1.0'));
+ console.assert(!validate('0.-1.0.0'));
+ console.assert(!validate('-1.0.0.0'));
+ console.assert(!validate('256.0.0.0'));
+ console.assert(!validate('0.256.0.0'));
+ console.assert(!validate('0.0.256.0'));
+ console.assert(!validate('0.0.0.256'));
+ }
+
+ // ipv6
+ {
+ const schema = { format: 'ipv6' };
+ const validate = jsen(schema);
+
+ console.assert(validate('1:2:3:4:5:6:7:8'));
+ console.assert(validate('1::'));
+ console.assert(validate('1:2:3:4:5:6:7::'));
+ console.assert(validate('1::8'));
+ console.assert(validate('1:2:3:4:5:6::8'));
+ console.assert(validate('1::7:8'));
+ console.assert(validate('1:2:3:4:5::7:8'));
+ console.assert(validate('1:2:3:4:5::8'));
+ console.assert(validate('1::6:7:8'));
+ console.assert(validate('1:2:3:4::6:7:8'));
+ console.assert(validate('1:2:3:4::8'));
+ console.assert(validate('1::5:6:7:8'));
+ console.assert(validate('1:2:3::5:6:7:8'));
+ console.assert(validate('1:2:3::8'));
+ console.assert(validate('1::4:5:6:7:8'));
+ console.assert(validate('1:2::4:5:6:7:8'));
+ console.assert(validate('1:2::8'));
+ console.assert(validate('1::3:4:5:6:7:8'));
+ console.assert(validate('1::8'));
+ console.assert(validate('::2:3:4:5:6:7:8'));
+ console.assert(validate('::8'));
+ console.assert(validate('::'));
+
+ // link-local IPv6 addresses with zone index
+ console.assert(validate('fe80::7:8%eth0'));
+ console.assert(validate('fe80::7:8%1'));
+
+ // IPv4-mapped IPv6 addresses and IPv4-translated addresses
+ console.assert(validate('::255.255.255.255'));
+ console.assert(validate('::ffff:255.255.255.255'));
+ console.assert(validate('::ffff:0:255.255.255.255'));
+
+ // IPv4-Embedded IPv6 Address
+ console.assert(validate('2001:db8:3:4::192.0.2.33'));
+ console.assert(validate('64:ff9b::192.0.2.33'));
+
+ console.assert(!validate(''));
+ console.assert(!validate('::_'));
+
+ // TODO: we may need more invalid cases here
+ }
+
+ // hostname
+ {
+ const schema = { format: 'hostname' },
+ validate = jsen(schema),
+ maxLong1 = new Array(5).join('.' + new Array(64).join('a')).substr(1), // 255 chars (4 groups x 63 chars)
+ maxLong2 = new Array(9).join('.' + new Array(32).join('a')).substr(1); // 255 chars (8 groups x 31 chars)
+
+ console.assert(validate('my.host'));
+ console.assert(validate('host'));
+ console.assert(validate('domain.with.multiple.subdomains'));
+ console.assert(validate('domain-parts.may.contain-dashes'));
+ console.assert(validate('a-single-domain-part-can-be-up-to-sixty-three-characters-long63'));
+ console.assert(validate(maxLong1));
+ console.assert(validate(maxLong2));
+
+ console.assert(!validate(''));
+ console.assert(!validate('me@domain'));
+ console.assert(!validate('qu"ote\'s'));
+ console.assert(!validate('no_underscores+or?special$chars'));
+ console.assert(!validate('ends-with-dash-'));
+ console.assert(!validate('-starts-with-dash'));
+ console.assert(!validate('asingle-domain-part-cannot-be-longer-than-sixty-three-characters'));
+
+ // These verify that a hostname cannot be longer than 255 chars in total. However,
+ // maximum string length verification cannot be performed in the same regex, so
+ // these test cases fail. Users must additionall use the `maxlength` keyword in this case.
+ // assert(!validate(maxLong1 + '.a'));
+ // assert(!validate(maxLong2 + '.a'));
+ }
+
+ // custom format
+ {
+ // accepts string
+ {
+ const schema = { format: 'custom' },
+ custom = '^\\d+$',
+ validate = jsen(schema, {
+ formats: {
+ custom: custom
+ }
+ });
+
+ console.assert(validate('123'));
+ console.assert(!validate('a123'));
+ }
+
+ // accepts regex
+ {
+ const schema = { format: 'custom' },
+ custom = /^\d+$/,
+ validate = jsen(schema, {
+ formats: {
+ custom: custom
+ }
+ });
+
+ console.assert(validate('123'));
+ console.assert(!validate('a123'));
+ }
+
+ // accepts function
+ {
+ let schema = { format: 'custom' },
+ callCount = 0,
+ custom = (value: any, childSchema: any) => {
+ console.assert(value.indexOf('123') > -1);
+ console.assert(childSchema === schema);
+
+ callCount++;
+
+ return /^\d+$/.test(value);
+ },
+ validate = jsen(schema, {
+ formats: {
+ custom: custom
+ }
+ });
+
+ console.assert(validate('123'));
+ console.assert(!validate('a123'));
+ console.assert(callCount === 2);
+ }
+
+ // is run for all types
+ {
+ let schema = { format: 'custom' },
+ callCount = 0,
+ options = {
+ formats: {
+ custom: () => {
+ callCount++;
+ return true;
+ }
+ }
+ },
+ validate = jsen(schema, options),
+ data = [
+ undefined,
+ null,
+ 'abc',
+ 123,
+ Math.PI,
+ true,
+ false,
+ {},
+ [],
+ new Date()
+ ];
+
+ data.forEach((dataItem) => {
+ validate(dataItem);
+ console.assert(callCount === 1);
+ callCount = 0;
+ });
+ }
+
+ // is not run if a built-in keyword fails
+ {
+ let schema = {
+ format: 'custom',
+ type: 'number',
+ maximum: 10
+ },
+ callCount = 0,
+ options = {
+ formats: {
+ custom: () => {
+ callCount++;
+ return true;
+ }
+ }
+ },
+ validate = jsen(schema, options);
+
+ console.assert(!validate(123));
+ console.assert(callCount === 0);
+
+ console.assert(validate(7));
+ console.assert(callCount === 1);
+ }
+
+ // common scenarios
+ {
+ // verify passwords match
+ {
+ let schema = {
+ description: 'User account creation form',
+ type: 'object',
+ properties: {
+ password: {
+ type: 'string',
+ minLength: 8
+ },
+ password_confirm: {
+ type: 'string',
+ minLength: 8
+ }
+ },
+ format: 'passwordsMatch'
+ },
+ options = {
+ formats: {
+ passwordsMatch: (obj: any) => {
+ callCount++;
+ return obj.password === obj.password_confirm;
+ }
+ }
+ },
+ data = {
+ password: '1234567',
+ password_confirm: '1234567'
+ },
+ validate = jsen(schema, options),
+ callCount = 0;
+
+ console.assert(!validate(data)); // minLength validator failed
+ console.assert(callCount === 0);
+
+ data.password += '8';
+ data.password_confirm += '9';
+
+ console.assert(!validate(data)); // custom validator failed
+ console.assert(callCount === 1);
+
+ data.password_confirm = data.password;
+
+ console.assert(validate(data)); // OK
+ console.assert(callCount === 2);
+ }
+ }
+ }
+}
+
+// option: greedy
+{
+ // validates as many keywords as possible
+ {
+ let schema = {
+ type: 'object',
+ properties: {
+ test1: {
+ type: 'string'
+ },
+ test2: {
+ type: 'object',
+ properties: {
+ test21: {
+ type: 'number'
+ }
+ }
+ },
+ test3: {
+ type: 'number'
+ },
+ test4: { $ref: '#external' }
+ },
+ additionalProperties: false
+ },
+ options = {
+ greedy: true,
+ schemas: {
+ external: {
+ type: 'string'
+ }
+ }
+ },
+ validate = jsen(schema, options),
+ invalidTest = {
+ test1: 1,
+ test2: '2',
+ test3: 'j',
+ test4: 4
+ },
+ ret = validate(invalidTest);
+
+ console.assert(!ret); // false
+ console.assert(JSON.stringify(validate.errors)
+ === JSON.stringify([
+ { path: 'test1', keyword: 'type' },
+ { path: 'test2', keyword: 'type' },
+ { path: 'test3', keyword: 'type' },
+ { path: 'test4', keyword: 'type' }
+ ])
+ );
+
+ delete options.greedy;
+
+ validate = jsen(schema, options);
+
+ ret = validate(invalidTest);
+
+ console.assert(!ret); // false
+ console.assert(JSON.stringify(validate.errors)
+ === JSON.stringify([{ path: 'test1', keyword: 'type' }])
+ );
+ }
+
+ // does not descend into invalid objects
+ {
+ let schema = {
+ type: 'object',
+ properties: {
+ test1: { type: 'object' },
+ test2: {
+ required: ['foo']
+ },
+ test3: {
+ properties: {
+ foo: { type: 'string' }
+ }
+ },
+ test4: {
+ type: 'array',
+ items: {
+ type: 'object',
+ required: ['foo']
+ }
+ }
+ }
+ },
+ options = { greedy: true },
+ data = {
+ test1: 123,
+ test2: {},
+ test3: 123,
+ test4: [{}, { foo: 123 }, null]
+ },
+ validate = jsen(schema, options),
+ ret = validate(data);
+
+ console.assert(!ret);
+ console.assert(JSON.stringify(validate.errors)
+ === JSON.stringify([
+ { path: 'test1', keyword: 'type' },
+ { path: 'test2.foo', keyword: 'required' },
+ { path: 'test4.0.foo', keyword: 'required' },
+ { path: 'test4.2', keyword: 'type' }
+ ])
+ );
+ }
+}
+
+// jsen
+{
+ // is a function
+ {
+ console.assert(typeof jsen === "function");
+ }
+
+ // throws if schema is not an object
+ {
+ console.assert(doesThrow(jsen()));
+ console.assert(doesThrow(jsen(null)));
+ console.assert(doesThrow(jsen(false)));
+ console.assert(doesThrow(jsen(123)));
+ console.assert(doesThrow(jsen("abc")));
+ console.assert(doesThrow(jsen([])));
+ console.assert(doesNotThrow(jsen({})));
+ }
+
+ // produces a function
+ {
+ const validate = jsen({});
+ console.assert(typeof validate === 'function');
+ console.assert(validate() === true);
+ // console.assert(validate.error === null);
+ }
+}
+
+// type: integer
+{
+ // required
+ {
+ const schema = { type: 'integer' },
+ validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+ console.assert(validate(123));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['integer', 'null'] },
+ validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(null));
+ console.assert(validate(123));
+ }
+
+ // type
+ {
+ const schema = { type: 'integer' },
+ validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate(true));
+ console.assert(!validate(false));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(13));
+ }
+
+ // enum
+ {
+ const schema = { type: 'integer', enum: [1, 3, 5, 7] },
+ validate = jsen(schema);
+
+ console.assert(!validate(4));
+ console.assert(validate(5));
+ }
+
+ // minimum
+ {
+ const schema = { type: 'integer', minimum: 7 },
+ validate = jsen(schema);
+
+ console.assert(!validate(6));
+
+ console.assert(validate(7));
+ console.assert(validate(999));
+ }
+
+ // exclusiveMinimum
+ {
+ const schema = {
+ type: 'integer',
+ minimum: 7,
+ exclusiveMinimum: true
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(6));
+ console.assert(!validate(7));
+
+ console.assert(validate(8));
+ console.assert(validate(999));
+ }
+
+ // maximum
+ {
+ const schema = { type: 'integer', maximum: 77 },
+ validate = jsen(schema);
+
+ console.assert(!validate(78));
+
+ console.assert(validate(-12));
+ console.assert(validate(76));
+ console.assert(validate(77));
+ }
+
+ // exclusiveMaximum
+ {
+ const schema = {
+ type: 'integer',
+ maximum: 77,
+ exclusiveMaximum: true
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(77));
+ console.assert(!validate(78));
+
+ console.assert(validate(-12));
+ console.assert(validate(75));
+ console.assert(validate(76));
+ }
+
+ // multipleOf
+ {
+ const schema = { type: 'integer', multipleOf: 7 },
+ validate = jsen(schema);
+
+ console.assert(!validate(8));
+
+ console.assert(validate(14));
+ console.assert(validate(-49));
+ console.assert(validate(77));
+ }
+}
+
+// missing $ref
+{
+ // passes validation with ignore missing $ref
+ {
+ let schema = {
+ type: 'object',
+ properties: {
+ test1: { $ref: '#external1' },
+ test2: {
+ type: 'number'
+ },
+ test3: { $ref: '#external3' } //missing
+ },
+ additionalProperties: false
+ },
+ external1 = {
+ type: 'object',
+ properties: {
+ test11: { $ref: '#external11' }, //missing
+ test12: {
+ type: 'number'
+ },
+ test13: { $ref: '#external11' } //duplicate
+ }
+ },
+ validate = jsen(schema, {
+ schemas: {
+ external1: external1
+ },
+ missing$Ref: true
+ }),
+ missingTest = {
+ test1: {
+ test11: 'missing',
+ test12: 5,
+ test13: 'missing too'
+ },
+ test2: 2,
+ test3: 3
+ },
+ invalidTest = {
+ test1: {
+ test11: 'missing',
+ test12: 5,
+ test13: 'missing too'
+ },
+ test2: 'fail',
+ test3: 3
+ },
+ ret: boolean;
+
+ ret = validate(missingTest);
+ console.assert(ret); // true
+
+ ret = validate(invalidTest);
+ console.assert(!ret); // !false
+ }
+}
+
+// multi schema
+{
+ // allOf
+ {
+ const schema = {
+ allOf: [
+ { type: 'number' },
+ { type: 'integer' }
+ ]
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(null));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(0));
+ console.assert(validate(777));
+ console.assert(validate(-9));
+ }
+
+ // anyOf
+ {
+ const schema = {
+ anyOf: [
+ { type: 'string' },
+ { type: 'number' }
+ ]
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(null));
+ console.assert(!validate(true));
+ console.assert(!validate({}));
+ console.assert(!validate([]));
+
+ console.assert(validate('abc'));
+ console.assert(validate(123));
+ console.assert(validate(''));
+ console.assert(validate(0));
+ }
+
+ // oneOf
+ {
+ const schema = {
+ oneOf: [
+ { type: 'number', maximum: 5 },
+ { type: 'number', minimum: 3 }
+ ]
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(null));
+ console.assert(!validate(true));
+ console.assert(!validate({}));
+ console.assert(!validate([]));
+ // matches both validators
+ console.assert(!validate(3));
+
+ console.assert(validate(0));
+ console.assert(validate(1));
+ console.assert(validate(2));
+ console.assert(validate(6));
+ console.assert(validate(17));
+ }
+
+ // not
+ {
+ const schema = {
+ not: {
+ type: 'array'
+ }
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate([]));
+
+ console.assert(validate(0));
+ console.assert(validate(false));
+ console.assert(validate('abc'));
+ console.assert(validate({}));
+ console.assert(validate(null));
+ console.assert(validate());
+ }
+}
+
+// type: null
+{
+ // required
+ {
+ const schema = { type: 'null' },
+ validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+ console.assert(validate(null));
+ }
+
+ // type
+ {
+ const schema = { type: 'null' },
+ validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(null));
+ }
+}
+
+// type: number
+{
+ // required
+ {
+ const schema = { type: 'number' },
+ validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate(Math.PI));
+ console.assert(validate(123));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['number', 'null'] },
+ validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(null));
+ console.assert(validate(Math.PI));
+ }
+
+ // type
+ {
+ const schema = { type: 'number' },
+ validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate(true));
+ console.assert(!validate(false));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+
+ console.assert(validate(13));
+ console.assert(validate(17.8));
+ console.assert(validate(Math.PI));
+ }
+
+ // enum
+ {
+ const schema = {
+ type: 'number',
+ enum: [1, Math.E, 3, 5, 7]
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(4));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(5));
+ console.assert(validate(Math.E));
+ }
+
+ // minimum
+ {
+ const schema = { type: 'number', minimum: 7 },
+ validate = jsen(schema);
+
+ console.assert(!validate(6));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(7));
+ console.assert(validate(999));
+ }
+
+ // exclusiveMinimum
+ {
+ const schema = {
+ type: 'number',
+ minimum: 7,
+ exclusiveMinimum: true
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(6));
+ console.assert(!validate(7));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate(8));
+ console.assert(validate(999));
+ }
+
+ // maximum
+ {
+ const schema = { type: 'number', maximum: 77 },
+ validate = jsen(schema);
+
+ console.assert(!validate(77.000001));
+ console.assert(!validate(78));
+
+ console.assert(validate(-12));
+ console.assert(validate(76));
+ console.assert(validate(77));
+ console.assert(validate(Math.PI));
+ }
+
+ // exclusiveMaximum
+ {
+ const schema = {
+ type: 'number',
+ maximum: 77,
+ exclusiveMaximum: true
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate(77));
+ console.assert(!validate(78));
+
+ console.assert(validate(-12));
+ console.assert(validate(75));
+ console.assert(validate(76));
+ console.assert(validate(76.99999));
+ }
+
+ // multipleOf
+ {
+ let schema = { type: 'number', multipleOf: 7 },
+ validate = jsen(schema);
+
+ console.assert(!validate(8));
+
+ console.assert(validate(14));
+ console.assert(validate(-49));
+ console.assert(validate(77));
+
+ schema = {
+ type: 'number',
+ multipleOf: 3.14 // Math.PI
+ };
+
+ validate = jsen(schema);
+
+ console.assert(!validate(2.5));
+
+ console.assert(validate(9.42)); // 3 * Math.PI
+ }
+
+ // fix multipleOf doesn't validate data for decimal point (#1)
+ {
+ const schema = { type: 'number', multipleOf: 0.01 },
+ validate = jsen(schema);
+
+ console.assert(validate(18.15));
+ }
+}
+
+// type: object
+{
+ // required
+ {
+ const schema = { type: 'object' },
+ validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate({}));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['object', 'null'] },
+ validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(null));
+ console.assert(validate({}));
+ }
+
+ // type
+ {
+ const schema = { type: 'object' },
+ validate = jsen(schema);
+
+ console.assert(!validate('123'));
+ console.assert(!validate(false));
+ console.assert(!validate([]));
+ console.assert(!validate(Math.PI));
+
+ console.assert(validate({}));
+ console.assert(jsen({ type: 'object', properties: {} }, {})());
+ }
+
+ // maxProperties
+ {
+ const schema = { type: 'object', maxProperties: 3 },
+ validate = jsen(schema);
+
+ console.assert(!validate({ a: 1, b: 2, c: 3, d: 4 }));
+
+ console.assert(validate({}));
+ console.assert(validate({ a: 1 }));
+ console.assert(validate({ a: 1, b: 2 }));
+ console.assert(validate({ a: 1, b: 2, c: 3 }));
+ }
+
+ // minProperties
+ {
+ const schema = { type: 'object', minProperties: 2 },
+ validate = jsen(schema);
+
+ console.assert(!validate({}));
+ console.assert(!validate({ a: 1 }));
+
+ console.assert(validate({ a: 1, b: 2 }));
+ console.assert(validate({ a: 1, b: 2, c: 3 }));
+ }
+
+ // required properties
+ {
+ const schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' },
+ c: { type: 'boolean' }
+ },
+ required: ['a', 'b']
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate({}));
+ console.assert(!validate({ c: true }));
+ console.assert(!validate({ a: 'abc', c: true }));
+ console.assert(!validate({ b: 123, c: true }));
+ console.assert(!validate({ a: 'abc', b: undefined }));
+
+ console.assert(validate({ a: 'abc', b: 123 }));
+ console.assert(validate({ a: 'abc', b: 123, c: true }));
+ }
+
+ // additionalProperties
+ {
+ let schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' }
+ },
+ additionalProperties: true
+ },
+ validate = jsen(schema);
+
+ console.assert(validate({ a: 'abc' }));
+ console.assert(validate({ b: 123 }));
+ console.assert(validate({ a: 'abc', b: 123 }));
+ console.assert(validate({ a: 'abc', b: 123, c: true }));
+
+ schema.additionalProperties = false;
+ validate = jsen(schema);
+
+ console.assert(!validate({ c: true }));
+ console.assert(!validate({ a: 'abc', b: 123, c: true }));
+
+ console.assert(validate({ a: 'abc', b: 123 }));
+ console.assert(jsen({ type: 'object', additionalProperties: false })({}));
+ }
+
+ // additionalProperties as schema
+ {
+ const schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' }
+ },
+ additionalProperties: {
+ type: 'boolean'
+ }
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate({ a: 'abc', b: 123, c: 123 }));
+
+ console.assert(validate({ a: 'abc', b: 123, c: false }));
+ }
+
+ // additionalProperties with patternProperties
+ {
+ let schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' }
+ },
+ patternProperties: {
+ '^b': { type: 'number' }
+ },
+ additionalProperties: true
+ },
+ validate = jsen(schema);
+
+ console.assert(validate({ a: 'abc' }));
+ console.assert(validate({ b: 123 }));
+ console.assert(validate({ a: 'abc', b: 123, bar: Math.E, baz: Math.PI }));
+ console.assert(validate({ a: 'abc', baz: 123, c: true }));
+
+ schema.additionalProperties = false;
+ validate = jsen(schema);
+
+ console.assert(!validate({ c: true }));
+ console.assert(!validate({ a: 'abc', bar: 123, c: true }));
+
+ console.assert(validate({ a: 'abc', baz: 123 }));
+ console.assert(jsen({ type: 'object', additionalProperties: false })({}));
+ }
+
+ // patternProperties
+ {
+ const schema = {
+ type: 'object',
+ patternProperties: {
+ '^a': { type: 'string' },
+ '^b': { type: 'number' }
+ }
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate({ a: 123 }));
+ console.assert(!validate({ b: 'abc' }));
+
+ console.assert(validate({}));
+ console.assert(validate({ a: 'abc' }));
+ console.assert(validate({ b: 123 }));
+ console.assert(validate({ a: 'abc', b: 123 }));
+ }
+
+ // dependencies: schema
+ {
+ const schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' }
+ },
+ dependencies: {
+ a: {
+ type: 'object',
+ required: ['c'],
+ properties: {
+ c: { type: 'boolean' }
+ }
+ },
+ b: {
+ type: 'object',
+ required: ['f'],
+ properties: {
+ f: { type: 'null' }
+ }
+ },
+ g: {
+ type: 'object',
+ required: ['b'],
+ properties: {
+ b: {
+ type: 'integer'
+ }
+ }
+ }
+ }
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate({ a: 'abc' }));
+ console.assert(!validate({ a: 'abc', c: 123 }));
+ console.assert(!validate({ b: Math.PI, f: false }));
+ console.assert(!validate({ b: Math.PI, g: null }));
+
+ console.assert(validate({}));
+ console.assert(validate({ a: 'abc', c: false }));
+ console.assert(validate({ b: Math.PI, f: null }));
+ console.assert(validate({ b: 123, g: 'any value', f: null }));
+ }
+
+ // dependencies: property
+ {
+ const schema = {
+ type: 'object',
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' },
+ c: { type: 'boolean' }
+ },
+ dependencies: {
+ a: ['b', 'c']
+ }
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate({ a: 'abc' }));
+ console.assert(!validate({ a: 'abc', b: 123 }));
+
+ console.assert(validate({}));
+ console.assert(validate({ a: 'abc', b: 123, c: false }));
+ }
+
+ // nested graph
+ {
+ const schema = {
+ type: ['object', 'null'],
+ properties: {
+ a: { type: 'string' },
+ b: { type: 'number' },
+ c: {
+ type: 'array',
+ items: { type: 'boolean' }
+ }
+ },
+ required: ['a']
+ },
+ validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate({}));
+ console.assert(!validate({ a: 123 }));
+ console.assert(!validate({ a: 'abc', b: false }));
+ console.assert(!validate({ a: 'abc', c: [null] }));
+
+ console.assert(validate(null));
+ console.assert(validate({ a: 'abc', b: 123.4, c: [true, false] }));
+ console.assert(validate({ a: 'abc', b: 0 }));
+ console.assert(validate({ a: 'abc', c: [true, false] }));
+ console.assert(validate({ a: 'abc', c: [] }));
+ }
+}
+
+// $ref
+{
+ // throws if string is not in correct format
+ {
+ console.assert(doesThrow(
+ jsen({ $ref: '' })
+ ));
+
+ console.assert(doesThrow(
+ jsen({ $ref: '#double//slash' })
+ ));
+
+ console.assert(doesThrow(
+ jsen({ $ref: '#ends/with/slash/' })
+ ));
+
+ console.assert(doesThrow(
+ // invalid reference, non-existent schema properties
+ jsen({ $ref: '#a/b/c' })
+ ));
+
+ console.assert(doesNotThrow(
+ // schema resolves to itself
+ jsen({ $ref: '#' })
+ ));
+
+ console.assert(doesNotThrow(
+ jsen({
+ a: {
+ b: {
+ c: {
+ type: 'any'
+ }
+ }
+ },
+ $ref: '#/a/b/c'
+ })
+ ));
+
+ console.assert(doesNotThrow(
+ jsen({
+ arr: [
+ { value: { type: 'string' } },
+ { value: { type: 'number' } },
+ { value: { type: 'boolean' } }
+ ],
+ type: 'object',
+ properties: {
+ a: { $ref: '#arr/2/value' }
+ }
+ })
+ ));
+ }
+
+ // external schema
+ {
+ // finds external schema with a hash
+ {
+ const external = { type: 'string' },
+ schema = { $ref: '#external' },
+ validate = jsen(schema, {
+ schemas: {
+ external: external
+ }
+ });
+
+ console.assert(validate('abc'));
+ console.assert(!validate(123));
+ }
+
+ // finds external schema without a hash
+ {
+ const external = { type: 'string' },
+ schema = { $ref: 'external' },
+ validate = jsen(schema, {
+ schemas: {
+ external: external
+ }
+ });
+
+ console.assert(validate('abc'));
+ console.assert(!validate(123));
+ }
+
+ // throws when no external schema found
+ {
+ const schema = { $ref: '#external' };
+
+ console.assert(doesNotThrow(
+ jsen(schema)
+ ));
+ }
+
+ // own property takes precendence over external schema
+ {
+ const external = { type: 'string' },
+ schema = {
+ external: { type: 'number' },
+ $ref: '#external'
+ },
+ validate = jsen(schema, {
+ schemas: {
+ external: external
+ }
+ });
+
+ console.assert(!validate('abc'));
+ console.assert(validate(123));
+ }
+
+ // external schemas have their own dereferencing scope
+ {
+ const external = {
+ inner: { type: 'string' },
+ $ref: '#inner'
+ },
+ schema = {
+ inner: { type: 'number' },
+ $ref: '#external'
+ },
+ validate = jsen(schema, {
+ schemas: {
+ external: external
+ }
+ });
+
+ console.assert(validate('abc'));
+ console.assert(!validate(123));
+ }
+ }
+}
+
+// type: string
+{
+ // required
+ {
+ const schema = { type: 'string' },
+ validate = jsen(schema);
+
+ console.assert(!validate());
+ console.assert(!validate(null));
+
+ console.assert(validate('abc'));
+ }
+
+ // nullable
+ {
+ const schema = { type: ['string', 'null'] },
+ validate = jsen(schema);
+
+ console.assert(!validate(undefined));
+
+ console.assert(validate(null));
+ console.assert(validate(''));
+ }
+
+ // type
+ {
+ const schema = { type: 'string' },
+ validate = jsen(schema);
+
+ console.assert(!validate(123));
+ console.assert(!validate(true));
+ console.assert(!validate(false));
+ console.assert(!validate(0));
+ console.assert(!validate([]));
+ console.assert(!validate({}));
+
+ console.assert(validate('abc'));
+ }
+
+ // enum
+ {
+ const schema = { type: 'string', enum: ['a', 'b', 'c'] },
+ validate = jsen(schema);
+
+ console.assert(!validate('not in enum'));
+ console.assert(validate('b'));
+ }
+
+ // minLength
+ {
+ const schema = { type: 'string', minLength: 10 },
+ validate = jsen(schema);
+
+ console.assert(!validate('too short'));
+ console.assert(validate('just long enough'));
+ }
+
+ // maxLength
+ {
+ const schema = { type: 'string', maxLength: 12 },
+ validate = jsen(schema);
+
+ console.assert(!validate('this string is too long'));
+ console.assert(validate('short enough'));
+ }
+
+ // pattern
+ {
+ let schema: any = { type: 'string', pattern: '\\d' },
+ validate = jsen(schema);
+
+ console.assert(!validate('a'));
+ console.assert(validate('1'));
+
+ schema = { type: 'string', pattern: /\d/ };
+ validate = jsen(schema);
+
+ console.assert(!validate('a'));
+ console.assert(validate('1'));
+ }
+}
+
+// unique
+{
+ // filters unique values
+ {
+ const inputs = [
+ [1, 'a', 3, false, null, undefined],
+ ['abc', 123, true, 123, false, Math.PI, 'abc', true, null, null]
+ ],
+ expected = [
+ [1, 'a', 3, false, null, undefined],
+ ['abc', 123, true, false, Math.PI, null]
+ ];
+
+ for (let i = 0; i < inputs.length; i++) {
+ console.assert(JSON.stringify(jsen.unique(inputs[i])) === JSON.stringify(expected[i]));
+ }
+ }
+
+ // performs deep equality checks
+ {
+ const input: any = [
+ {},
+ { a: 1 },
+ { b: { c: { d: 123, f: null }, e: 'abc' } },
+ [1, 2, 3],
+ [{ a: 213 }],
+ { b: 1 },
+ { a: 1, b: undefined },
+ { b: { e: 'abc', c: { f: null, d: 123 } } },
+ [1, 2, 3],
+ [{ a: 213 }]
+ ],
+ expected: any = [
+ {},
+ { a: 1 },
+ { b: { c: { d: 123, f: null }, e: 'abc' } },
+ [1, 2, 3],
+ [{ a: 213 }],
+ { b: 1 },
+ { a: 1, b: undefined }
+ ];
+
+ console.assert(JSON.stringify(jsen.unique(input)) === JSON.stringify(expected));
+ }
+
+ // unique.findIndex
+ {
+ // finds an item index with comparator
+ {
+ const arr = [{}, { a: 1 }, { a: 1, b: 2 }],
+ expected = 2,
+ comparator = (obj1: any, obj2: any) => {
+ return obj1.a === obj2.a && obj1.b === obj2.b;
+ };
+
+ console.assert(jsen.unique.findIndex(arr, { a: 1, b: 2 }, comparator) === expected);
+ }
+
+ // returns -1 when item cannot be found
+ {
+ const arr = [{}, { a: 1 }, { a: 1, b: 2 }],
+ expected = -1,
+ comparator = (obj1: any, obj2: any) => {
+ return obj1.a === obj2.a && obj1.b === obj2.b;
+ };
+
+ console.assert(jsen.unique.findIndex(arr, { a: 1, b: null }, comparator) === expected);
+ }
+ }
+}
diff --git a/jsen/jsen.d.ts b/jsen/jsen.d.ts
new file mode 100644
index 000000000..19407c849
--- /dev/null
+++ b/jsen/jsen.d.ts
@@ -0,0 +1,52 @@
+// Type definitions for jsen (JSON Sentinel)
+// Project: https://github.com/bugventure/jsen
+// Definitions by: Vladimir Đokić
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module Jsen {
+
+ export interface JsenFormats {
+ [key: string]: string | RegExp | Function;
+ }
+
+ export interface JsenSettings {
+ missing$Ref?: boolean;
+ greedy?: boolean;
+ formats?: JsenFormats;
+ schemas?: any;
+ }
+
+ export interface JsenBuildSettings {
+ copy?: boolean;
+ additionalProperties?: boolean;
+ }
+
+ export interface JsenValidator {
+ (data?: any): boolean;
+ build(initial?: any, options?: JsenBuildSettings): any;
+ errors: JsenValidateError[];
+ }
+
+ export interface JsenValidateError {
+ path: string;
+ keyword: string;
+ message?: string;
+ }
+
+ export interface JsenUnique {
+ (array: any[]): boolean;
+ findIndex(array: any[], value: any, comparator: (obj1: any, obj2: any) => boolean): number;
+ }
+
+ export interface JsenMain {
+ (schema?: any, options?: JsenSettings): JsenValidator;
+ clone(data: any): any;
+ equal(a: any, b: any): boolean;
+ unique: JsenUnique;
+ }
+}
+
+declare module "jsen" {
+ var _jsen: Jsen.JsenMain;
+ export = _jsen;
+}
diff --git a/leaflet/leaflet.d.ts b/leaflet/leaflet.d.ts
index 4732e7f3d..6c487c3eb 100644
--- a/leaflet/leaflet.d.ts
+++ b/leaflet/leaflet.d.ts
@@ -2000,11 +2000,11 @@ declare namespace L {
export function closestPointOnSegment(p: Point, p1: Point, p2: Point): Point;
/**
- * Clips the segment a to b by rectangular bounds (modifying the segment points
- * directly!). Used by Leaflet to only show polyline points that are on the screen
- * or near, increasing performance.
+ * Clips the segment a to b by rectangular bounds. Used by Leaflet to only show
+ * polyline points that are on the screen or near, increasing performance. Returns
+ * either false or a length-2 array of clipped points.
*/
- export function clipSegment(a: Point, b: Point, bounds: Bounds): void;
+ export function clipSegment(a: Point, b: Point, bounds: Bounds): Point[] | boolean;
}
}
diff --git a/lodash/lodash-3.10-tests.ts b/lodash/lodash-3.10-tests.ts
index 8d19f394a..0a2debfa0 100644
--- a/lodash/lodash-3.10-tests.ts
+++ b/lodash/lodash-3.10-tests.ts
@@ -5003,13 +5003,6 @@ namespace TestReject {
}
}
-result = _.sample([1, 2, 3, 4]);
-result = _.sample([1, 2, 3, 4], 2);
-result = <_.LoDashImplicitWrapper>_([1, 2, 3, 4]).sample();
-result = <_.LoDashImplicitArrayWrapper>_([1, 2, 3, 4]).sample(2);
-result = _([1, 2, 3, 4]).sample().value();
-result = _([1, 2, 3, 4]).sample(2).value();
-
// _.select
namespace TestSelect {
let array: TResult[];
@@ -5108,6 +5101,78 @@ namespace TestSelect {
}
}
+// _.sample
+namespace TestSample {
+ let array: string[];
+ let list: _.List;
+ let dictionary: _.Dictionary;
+ let numericDictionary: _.NumericDictionary;
+
+ {
+ let result: string;
+
+ result = _.sample('abc');
+ result = _.sample(array);
+ result = _.sample(list);
+ result = _.sample(dictionary);
+ result = _.sample(numericDictionary);
+ result = _.sample<{a: string}, string>({a: 'foo'});
+ result = _.sample({a: 'foo'});
+
+ result = _('abc').sample();
+ result = _(array).sample();
+ result = _(list).sample();
+ result = _(dictionary).sample();
+ result = _(numericDictionary).sample();
+ result = _({a: 'foo'}).sample();
+ }
+
+ {
+ let result: string[];
+
+ result = _.sample('abc', 42);
+ result = _.sample(array, 42);
+ result = _.sample(list, 42);
+ result = _.sample(dictionary, 42);
+ result = _.sample(numericDictionary, 42);
+ result = _.sample<{a: string}, string>({a: 'foo'}, 42);
+ result = _.sample({a: 'foo'}, 42);
+ }
+
+ {
+ let result: _.LoDashImplicitArrayWrapper;
+
+ result = _('abc').sample(42);
+ result = _(array).sample(42);
+ result = _(list).sample(42);
+ result = _(dictionary).sample(42);
+ result = _(numericDictionary).sample(42);
+ result = _({a: 'foo'}).sample(42);
+ }
+
+ {
+ let result: _.LoDashExplicitWrapper;
+
+ result = _('abc').chain().sample();
+ result = _(array).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(list).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(dictionary).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(numericDictionary).chain().sample<_.LoDashExplicitWrapper>();
+ result = _({a: 'foo'}).chain().sample<_.LoDashExplicitWrapper>();
+ }
+
+ {
+ let result: _.LoDashExplicitArrayWrapper;
+
+ result = _('abc').chain().sample(42);
+ result = _(array).chain().sample(42);
+ result = _(list).chain().sample(42);
+ result = _(dictionary).chain().sample(42);
+ result = _(numericDictionary).chain().sample(42);
+ result = _({a: 'foo'}).chain().sample(42);
+ }
+}
+
// _.shuffle
namespace TestShuffle {
let array: TResult[];
@@ -6097,20 +6162,42 @@ namespace TestFlowRight {
// _.memoize
namespace TestMemoize {
- var testMemoizedFunction: _.MemoizedFunction;
- var cache = <_.MapCache>testMemoizedFunction.cache;
- interface TestMemoizedResultFn extends _.MemoizedFunction {
+ {
+ let memoizedFunction: _.MemoizedFunction;
+ let cache: _.MapCache = memoizedFunction.cache;
+ }
+
+ interface MemoizedResultFn extends _.MemoizedFunction {
(a1: string, a2: number): boolean;
}
- var testMemoizeFn = (a1: string, a2: number) => a1.length > a2;
- var testMemoizeResolverFn = (a1: string, a2: number) => a1 + a2;
- var result: TestMemoizedResultFn;
- result = _.memoize(testMemoizeFn);
- result = _.memoize(testMemoizeFn, testMemoizeResolverFn);
- result = _(testMemoizeFn).memoize().value();
- result = _(testMemoizeFn).memoize(testMemoizeResolverFn).value();
- result('foo', 1);
- result.cache.get('foo1');
+
+ let memoizeFn: (a1: string, a2: number) => boolean;
+ let memoizeResolverFn: (a1: string, a2: number) => string;
+
+ {
+ let result: MemoizedResultFn;
+
+ result = _.memoize(memoizeFn);
+ result = _.memoize(memoizeFn, memoizeResolverFn);
+
+ result('foo', 1);
+ result.cache.get('foo1');
+ }
+
+ {
+ let result: _.LoDashImplicitObjectWrapper;
+
+ result = _(memoizeFn).memoize();
+ result = _(memoizeFn).memoize(memoizeResolverFn);
+ }
+
+ {
+ let result: _.LoDashExplicitObjectWrapper;
+
+ result = _(memoizeFn).chain().memoize();
+ result = _(memoizeFn).chain().memoize(memoizeResolverFn);
+ }
+
_.memoize.Cache = {
delete: key => false,
get: key => undefined,
@@ -10270,12 +10357,23 @@ namespace TestMixin {
}
// _.noConflict
-{
- let result: typeof _;
- result = _.noConflict();
- result = _(42).noConflict();
- result = _([]).noConflict();
- result = _({}).noConflict();
+namespace TestNoConflict {
+ {
+ let result: typeof _;
+
+ result = _.noConflict();
+ result = _(42).noConflict();
+ result = _([]).noConflict();
+ result = _({}).noConflict();
+ }
+
+ {
+ let result: _.LoDashExplicitObjectWrapper;
+
+ result = _(42).chain().noConflict();
+ result = _([]).chain().noConflict();
+ result = _({}).chain().noConflict();
+ }
}
// _.noop
diff --git a/lodash/lodash-3.10.d.ts b/lodash/lodash-3.10.d.ts
index c2fb9f726..b92de15c8 100644
--- a/lodash/lodash-3.10.d.ts
+++ b/lodash/lodash-3.10.d.ts
@@ -8008,56 +8008,6 @@ declare module _ {
reject(predicate: W): LoDashExplicitArrayWrapper;
}
- //_.sample
- interface LoDashStatic {
- /**
- * Retrieves a random element or n random elements from a collection.
- * @param collection The collection to sample.
- * @return Returns the random sample(s) of collection.
- **/
- sample(collection: Array): T;
-
- /**
- * @see _.sample
- **/
- sample(collection: List): T;
-
- /**
- * @see _.sample
- **/
- sample(collection: Dictionary): T;
-
- /**
- * @see _.sample
- * @param n The number of elements to sample.
- **/
- sample(collection: Array, n: number): T[];
-
- /**
- * @see _.sample
- * @param n The number of elements to sample.
- **/
- sample(collection: List, n: number): T[];
-
- /**
- * @see _.sample
- * @param n The number of elements to sample.
- **/
- sample(collection: Dictionary, n: number): T[];
- }
-
- interface LoDashImplicitArrayWrapper {
- /**
- * @see _.sample
- **/
- sample(n: number): LoDashImplicitArrayWrapper;
-
- /**
- * @see _.sample
- **/
- sample(): LoDashImplicitWrapper;
- }
-
//_.select
interface LoDashStatic {
/**
@@ -8217,6 +8167,141 @@ declare module _ {
select(predicate: W): LoDashExplicitArrayWrapper;
}
+ //_.sample
+ interface LoDashStatic {
+ /**
+ * Gets a random element or n random elements from a collection.
+ *
+ * @param collection The collection to sample.
+ * @return Returns the random sample(s) of collection.
+ */
+ sample(
+ collection: List|Dictionary|NumericDictionary,
+ n: number
+ ): T[];
+
+ /**
+ * @see _.sample
+ */
+ sample(
+ collection: O,
+ n: number
+ ): T[];
+
+ /**
+ * @see _.sample
+ */
+ sample(
+ collection: Object,
+ n: number
+ ): T[];
+
+ /**
+ * @see _.sample
+ */
+ sample(
+ collection: List|Dictionary|NumericDictionary
+ ): T;
+
+ /**
+ * @see _.sample
+ */
+ sample(
+ collection: O
+ ): T;
+
+ /**
+ * @see _.sample
+ */
+ sample(
+ collection: Object
+ ): T;
+ }
+
+ interface LoDashImplicitWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashImplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): string;
+ }
+
+ interface LoDashImplicitArrayWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashImplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): T;
+ }
+
+ interface LoDashImplicitObjectWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashImplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): T;
+ }
+
+ interface LoDashExplicitWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashExplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): LoDashExplicitWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashExplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): TWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(
+ n: number
+ ): LoDashExplicitArrayWrapper;
+
+ /**
+ * @see _.sample
+ */
+ sample(): TWrapper;
+ }
+
//_.shuffle
interface LoDashStatic {
/**
@@ -9735,6 +9820,7 @@ declare module _ {
* storing the result based on the arguments provided to the memoized function. By default, the first argument
* provided to the memoized function is coerced to a string and used as the cache key. The func is invoked with
* the this binding of the memoized function.
+ *
* @param func The function to have its output memoized.
* @param resolver The function to resolve the cache key.
* @return Returns the new memoizing function.
@@ -9752,6 +9838,13 @@ declare module _ {
memoize(resolver?: Function): LoDashImplicitObjectWrapper;
}
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.memoize
+ */
+ memoize(resolver?: Function): LoDashExplicitObjectWrapper;
+ }
+
//_.modArgs
interface LoDashStatic {
/**
@@ -15430,6 +15523,13 @@ declare module _ {
noConflict(): typeof _;
}
+ interface LoDashExplicitWrapperBase {
+ /**
+ * @see _.noConflict
+ */
+ noConflict(): LoDashExplicitObjectWrapper;
+ }
+
//_.noop
interface LoDashStatic {
/**
diff --git a/lodash/lodash-tests.ts b/lodash/lodash-tests.ts
index c8c824bd7..7931acb2b 100644
--- a/lodash/lodash-tests.ts
+++ b/lodash/lodash-tests.ts
@@ -5042,14 +5042,103 @@ namespace TestReject {
}
// _.sample
-result = _.sample([1, 2, 3, 4]);
-result = <_.LoDashImplicitWrapper>_([1, 2, 3, 4]).sample();
-result = _([1, 2, 3, 4]).sample().value();
+namespace TestSample {
+ let array: string[];
+ let list: _.List;
+ let dictionary: _.Dictionary;
+ let numericDictionary: _.NumericDictionary;
+
+ {
+ let result: string;
+
+ result = _.sample('abc');
+ result = _.sample(array);
+ result = _.sample(list);
+ result = _.sample(dictionary);
+ result = _.sample(numericDictionary);
+ result = _.sample<{a: string}, string>({a: 'foo'});
+ result = _.sample({a: 'foo'});
+
+ result = _('abc').sample();
+ result = _(array).sample();
+ result = _(list).sample();
+ result = _(dictionary).sample();
+ result = _(numericDictionary).sample();
+ result = _({a: 'foo'}).sample();
+ }
+
+ {
+ let result: _.LoDashExplicitWrapper;
+
+ result = _('abc').chain().sample();
+ result = _(array).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(list).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(dictionary).chain().sample<_.LoDashExplicitWrapper>();
+ result = _(numericDictionary).chain().sample<_.LoDashExplicitWrapper>();
+ result = _({a: 'foo'}).chain().sample<_.LoDashExplicitWrapper>();
+ }
+}
// _.sampleSize
-result = _.sampleSize([1, 2, 3, 4], 2);
-result = <_.LoDashImplicitArrayWrapper>_([1, 2, 3, 4]).sampleSize(2);
-result = _([1, 2, 3, 4]).sampleSize(2).value();
+namespace TestSampleSize {
+ let array: string[];
+ let list: _.List;
+ let dictionary: _.Dictionary;
+ let numericDictionary: _.NumericDictionary;
+
+ {
+ let result: string[];
+
+ result = _.sampleSize('abc');
+ result = _.sampleSize('abc', 42);
+ result = _.sampleSize(array);
+ result = _.sampleSize(array, 42);
+ result = _.sampleSize(list);
+ result = _.sampleSize(list, 42);
+ result = _.sampleSize(dictionary);
+ result = _.sampleSize(dictionary, 42);
+ result = _.sampleSize(numericDictionary);
+ result = _.sampleSize(numericDictionary, 42);
+ result = _.sampleSize<{a: string}, string>({a: 'foo'});
+ result = _.sampleSize<{a: string}, string>({a: 'foo'}, 42);
+ result = _.sampleSize({a: 'foo'});
+ result = _.sampleSize({a: 'foo'}, 42);
+ }
+
+ {
+ let result: _.LoDashImplicitArrayWrapper;
+
+ result = _('abc').sampleSize();
+ result = _('abc').sampleSize(42);
+ result = _(array).sampleSize();
+ result = _(array).sampleSize(42);
+ result = _(list).sampleSize();
+ result = _(list).sampleSize(42);
+ result = _(dictionary).sampleSize();
+ result = _(dictionary).sampleSize(42);
+ result = _(numericDictionary).sampleSize();
+ result = _(numericDictionary).sampleSize(42);
+ result = _({a: 'foo'}).sampleSize();
+ result = _({a: 'foo'}).sampleSize(42);
+ }
+
+ {
+ let result: _.LoDashExplicitArrayWrapper;
+
+ result = _('abc').chain().sampleSize();
+ result = _('abc').chain().sampleSize(42);
+ result = _(array).chain().sampleSize();
+ result = _(array).chain().sampleSize(42);
+ result = _(list).chain().sampleSize();
+ result = _(list).chain().sampleSize(42);
+ result = _(dictionary).chain().sampleSize();
+ result = _(dictionary).chain().sampleSize(42);
+ result = _(numericDictionary).chain().sampleSize();
+ result = _(numericDictionary).chain().sampleSize(42);
+ result = _({a: 'foo'}).chain().sampleSize();
+ result = _({a: 'foo'}).chain().sampleSize(42);
+ }
+}
// _.shuffle
namespace TestShuffle {
@@ -5977,20 +6066,42 @@ namespace TestFlowRight {
// _.memoize
namespace TestMemoize {
- var testMemoizedFunction: _.MemoizedFunction;
- var cache = <_.MapCache>testMemoizedFunction.cache;
- interface TestMemoizedResultFn extends _.MemoizedFunction {
+ {
+ let memoizedFunction: _.MemoizedFunction;
+ let cache: _.MapCache = memoizedFunction.cache;
+ }
+
+ interface MemoizedResultFn extends _.MemoizedFunction {
(a1: string, a2: number): boolean;
}
- var testMemoizeFn = (a1: string, a2: number) => a1.length > a2;
- var testMemoizeResolverFn = (a1: string, a2: number) => a1 + a2;
- var result: TestMemoizedResultFn;
- result = _.memoize(testMemoizeFn);
- result = _.memoize(testMemoizeFn, testMemoizeResolverFn);
- result = _(testMemoizeFn).memoize().value();
- result = _(testMemoizeFn).memoize(testMemoizeResolverFn).value();
- result('foo', 1);
- result.cache.get('foo1');
+
+ let memoizeFn: (a1: string, a2: number) => boolean;
+ let memoizeResolverFn: (a1: string, a2: number) => string;
+
+ {
+ let result: MemoizedResultFn;
+
+ result = _.memoize(memoizeFn);
+ result = _.memoize(memoizeFn, memoizeResolverFn);
+
+ result('foo', 1);
+ result.cache.get('foo1');
+ }
+
+ {
+ let result: _.LoDashImplicitObjectWrapper;
+
+ result = _(memoizeFn).memoize();
+ result = _(memoizeFn).memoize(memoizeResolverFn);
+ }
+
+ {
+ let result: _.LoDashExplicitObjectWrapper;
+
+ result = _(memoizeFn).chain().memoize();
+ result = _(memoizeFn).chain().memoize(memoizeResolverFn);
+ }
+
_.memoize.Cache = {
delete: key => false,
get: key => undefined,
@@ -11506,12 +11617,23 @@ namespace TestMixin {
}
// _.noConflict
-{
- let result: typeof _;
- result = _.noConflict();
- result = _(42).noConflict();
- result = _([]).noConflict();
- result = _({}).noConflict();
+namespace TestNoConflict {
+ {
+ let result: typeof _;
+
+ result = _.noConflict();
+ result = _(42).noConflict();
+ result = _([]).noConflict();
+ result = _({}).noConflict();
+ }
+
+ {
+ let result: _.LoDashExplicitObjectWrapper;
+
+ result = _(42).chain().noConflict();
+ result = _([]).chain().noConflict();
+ result = _({}).chain().noConflict();
+ }
}
// _.noop
diff --git a/lodash/lodash.d.ts b/lodash/lodash.d.ts
index 790107369..bd996b963 100644
--- a/lodash/lodash.d.ts
+++ b/lodash/lodash.d.ts
@@ -8981,77 +8981,155 @@ declare module _ {
//_.sample
interface LoDashStatic {
/**
- * Gets a random element from `collection`.
+ * Gets a random element from collection.
*
- * @static
- * @memberOf _
- * @category Collection
- * @param {Array|Object} collection The collection to sample.
- * @returns {*} Returns the random element.
- * @example
- *
- * _.sample([1, 2, 3, 4]);
- * // => 2
+ * @param collection The collection to sample.
+ * @return Returns the random element.
*/
- sample(collection: Array): T;
+ sample(
+ collection: List|Dictionary|NumericDictionary
+ ): T;
/**
- * @see _.sample
- **/
- sample(collection: List): T;
+ * @see _.sample
+ */
+ sample(
+ collection: O
+ ): T;
/**
- * @see _.sample
- **/
- sample(collection: Dictionary): T;
+ * @see _.sample
+ */
+ sample(
+ collection: Object
+ ): T;
+ }
+
+ interface LoDashImplicitWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(): string;
}
interface LoDashImplicitArrayWrapper {
/**
* @see _.sample
- **/
- sample(): LoDashImplicitWrapper;
+ */
+ sample(): T;
+ }
+
+ interface LoDashImplicitObjectWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(): T;
+ }
+
+ interface LoDashExplicitWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(): LoDashExplicitWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(): TWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.sample
+ */
+ sample(): TWrapper;
}
//_.sampleSize
interface LoDashStatic {
/**
- * Gets `n` random elements from `collection`.
+ * Gets n random elements at unique keys from collection up to the size of collection.
*
- * @static
- * @memberOf _
- * @category Collection
- * @param {Array|Object} collection The collection to sample.
- * @param {number} [n=0] The number of elements to sample.
- * @returns {Array} Returns the random elements.
- * @example
- *
- * _.sampleSize([1, 2, 3, 4], 2);
- * // => [3, 1]
+ * @param collection The collection to sample.
+ * @param n The number of elements to sample.
+ * @return Returns the random elements.
*/
- sampleSize(collection: Array, n: number): T[];
+ sampleSize(
+ collection: List|Dictionary|NumericDictionary,
+ n?: number
+ ): T[];
/**
- * @see _.sampleSize
- **/
- sampleSize(collection: List, n: number): T[];
+ * @see _.sampleSize
+ */
+ sampleSize(
+ collection: O,
+ n?: number
+ ): T[];
/**
- * @see _.sampleSize
- **/
- sampleSize(collection: Dictionary, n: number): T[];
+ * @see _.sampleSize
+ */
+ sampleSize(
+ collection: Object,
+ n?: number
+ ): T[];
+ }
+
+ interface LoDashImplicitWrapper {
+ /**
+ * @see _.sampleSize
+ */
+ sampleSize(
+ n?: number
+ ): LoDashImplicitArrayWrapper;
}
interface LoDashImplicitArrayWrapper {
/**
* @see _.sampleSize
- **/
- sampleSize(n: number): LoDashImplicitArrayWrapper;
+ */
+ sampleSize(
+ n?: number
+ ): LoDashImplicitArrayWrapper;
+ }
+ interface LoDashImplicitObjectWrapper {
/**
* @see _.sampleSize
- **/
- sampleSize(): LoDashImplicitWrapper;
+ */
+ sampleSize(
+ n?: number
+ ): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitWrapper {
+ /**
+ * @see _.sampleSize
+ */
+ sampleSize(
+ n?: number
+ ): LoDashExplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.sampleSize
+ */
+ sampleSize(
+ n?: number
+ ): LoDashExplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.sampleSize
+ */
+ sampleSize(
+ n?: number
+ ): LoDashExplicitArrayWrapper | |