Merge remote-tracking branch 'upstream/master' into es2019

This commit is contained in:
Kagami Sascha Rosylight
2019-02-08 06:55:56 +09:00
99 changed files with 1046 additions and 156 deletions
+2 -1
View File
@@ -39,6 +39,7 @@ namespace ts {
["es2017.string", "lib.es2017.string.d.ts"],
["es2017.intl", "lib.es2017.intl.d.ts"],
["es2017.typedarrays", "lib.es2017.typedarrays.d.ts"],
["es2018.asynciterable", "lib.es2018.asynciterable.d.ts"],
["es2018.intl", "lib.es2018.intl.d.ts"],
["es2018.promise", "lib.es2018.promise.d.ts"],
["es2018.regexp", "lib.es2018.regexp.d.ts"],
@@ -47,7 +48,7 @@ namespace ts {
["es2019.symbol", "lib.es2019.symbol.d.ts"],
["esnext.array", "lib.es2019.array.d.ts"],
["esnext.symbol", "lib.es2019.symbol.d.ts"],
["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"],
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
["esnext.intl", "lib.esnext.intl.d.ts"],
["esnext.bigint", "lib.esnext.bigint.d.ts"]
];
+134 -22
View File
@@ -118,42 +118,105 @@ namespace ts {
export const MapCtr = typeof Map !== "undefined" && "entries" in Map.prototype ? Map : shimMap();
// Keep the class inside a function so it doesn't get compiled if it's not used.
function shimMap(): new <T>() => Map<T> {
export function shimMap(): new <T>() => Map<T> {
interface MapEntry<T> {
readonly key?: string;
value?: T;
// Linked list references for iterators.
nextEntry?: MapEntry<T>;
previousEntry?: MapEntry<T>;
/**
* Specifies if iterators should skip the next entry.
* This will be set when an entry is deleted.
* See https://github.com/Microsoft/TypeScript/pull/27292 for more information.
*/
skipNext?: boolean;
}
class MapIterator<T, U extends (string | T | [string, T])> {
private data: MapLike<T>;
private keys: ReadonlyArray<string>;
private index = 0;
private selector: (data: MapLike<T>, key: string) => U;
constructor(data: MapLike<T>, selector: (data: MapLike<T>, key: string) => U) {
this.data = data;
private currentEntry?: MapEntry<T>;
private selector: (key: string, value: T) => U;
constructor(currentEntry: MapEntry<T>, selector: (key: string, value: T) => U) {
this.currentEntry = currentEntry;
this.selector = selector;
this.keys = Object.keys(data);
}
public next(): { value: U, done: false } | { value: never, done: true } {
const index = this.index;
if (index < this.keys.length) {
this.index++;
return { value: this.selector(this.data, this.keys[index]), done: false };
// Navigate to the next entry.
while (this.currentEntry) {
const skipNext = !!this.currentEntry.skipNext;
this.currentEntry = this.currentEntry.nextEntry;
if (!skipNext) {
break;
}
}
if (this.currentEntry) {
return { value: this.selector(this.currentEntry.key!, this.currentEntry.value!), done: false };
}
else {
return { value: undefined as never, done: true };
}
return { value: undefined as never, done: true };
}
}
return class <T> implements Map<T> {
private data = createDictionaryObject<T>();
private data = createDictionaryObject<MapEntry<T>>();
public size = 0;
// Linked list references for iterators.
// See https://github.com/Microsoft/TypeScript/pull/27292
// for more information.
/**
* The first entry in the linked list.
* Note that this is only a stub that serves as starting point
* for iterators and doesn't contain a key and a value.
*/
private readonly firstEntry: MapEntry<T>;
private lastEntry: MapEntry<T>;
constructor() {
// Create a first (stub) map entry that will not contain a key
// and value but serves as starting point for iterators.
this.firstEntry = {};
// When the map is empty, the last entry is the same as the
// first one.
this.lastEntry = this.firstEntry;
}
get(key: string): T | undefined {
return this.data[key];
const entry = this.data[key] as MapEntry<T> | undefined;
return entry && entry.value!;
}
set(key: string, value: T): this {
if (!this.has(key)) {
this.size++;
// Create a new entry that will be appended at the
// end of the linked list.
const newEntry: MapEntry<T> = {
key,
value
};
this.data[key] = newEntry;
// Adjust the references.
const previousLastEntry = this.lastEntry;
previousLastEntry.nextEntry = newEntry;
newEntry.previousEntry = previousLastEntry;
this.lastEntry = newEntry;
}
this.data[key] = value;
else {
this.data[key].value = value;
}
return this;
}
@@ -165,32 +228,81 @@ namespace ts {
delete(key: string): boolean {
if (this.has(key)) {
this.size--;
const entry = this.data[key];
delete this.data[key];
// Adjust the linked list references of the neighbor entries.
const previousEntry = entry.previousEntry!;
previousEntry.nextEntry = entry.nextEntry;
if (entry.nextEntry) {
entry.nextEntry.previousEntry = previousEntry;
}
// When the deleted entry was the last one, we need to
// adust the lastEntry reference.
if (this.lastEntry === entry) {
this.lastEntry = previousEntry;
}
// Adjust the forward reference of the deleted entry
// in case an iterator still references it. This allows us
// to throw away the entry, but when an active iterator
// (which points to the current entry) continues, it will
// navigate to the entry that originally came before the
// current one and skip it.
entry.previousEntry = undefined;
entry.nextEntry = previousEntry;
entry.skipNext = true;
return true;
}
return false;
}
clear(): void {
this.data = createDictionaryObject<T>();
this.data = createDictionaryObject<MapEntry<T>>();
this.size = 0;
// Reset the linked list. Note that we must adjust the forward
// references of the deleted entries to ensure iterators stuck
// in the middle of the list don't continue with deleted entries,
// but can continue with new entries added after the clear()
// operation.
const firstEntry = this.firstEntry;
let currentEntry = firstEntry.nextEntry;
while (currentEntry) {
const nextEntry = currentEntry.nextEntry;
currentEntry.previousEntry = undefined;
currentEntry.nextEntry = firstEntry;
currentEntry.skipNext = true;
currentEntry = nextEntry;
}
firstEntry.nextEntry = undefined;
this.lastEntry = firstEntry;
}
keys(): Iterator<string> {
return new MapIterator(this.data, (_data, key) => key);
return new MapIterator(this.firstEntry, key => key);
}
values(): Iterator<T> {
return new MapIterator(this.data, (data, key) => data[key]);
return new MapIterator(this.firstEntry, (_key, value) => value);
}
entries(): Iterator<[string, T]> {
return new MapIterator(this.data, (data, key) => [key, data[key]] as [string, T]);
return new MapIterator(this.firstEntry, (key, value) => [key, value] as [string, T]);
}
forEach(action: (value: T, key: string) => void): void {
for (const key in this.data) {
action(this.data[key], key);
const iterator = this.entries();
while (true) {
const { value: entry, done } = iterator.next();
if (done) {
break;
}
action(entry[1], entry[0]);
}
}
};
+1 -1
View File
@@ -609,7 +609,7 @@ namespace ts {
export interface Node extends TextRange {
kind: SyntaxKind;
flags: NodeFlags;
/* @internal */ modifierFlagsCache?: ModifierFlags;
/* @internal */ modifierFlagsCache: ModifierFlags;
/* @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined
decorators?: NodeArray<Decorator>; // Array of decorators (in document order)
modifiers?: ModifiersArray; // Array of modifiers
+2 -2
View File
@@ -3792,8 +3792,8 @@ namespace ts {
}
export function getModifierFlags(node: Node): ModifierFlags {
if (node.modifierFlagsCache! & ModifierFlags.HasComputedFlags) {
return node.modifierFlagsCache! & ~ModifierFlags.HasComputedFlags;
if (node.modifierFlagsCache & ModifierFlags.HasComputedFlags) {
return node.modifierFlagsCache & ~ModifierFlags.HasComputedFlags;
}
const flags = getModifierFlagsNoCache(node);
+1
View File
@@ -1,4 +1,5 @@
/// <reference lib="es2017" />
/// <reference lib="es2018.asynciterable" />
/// <reference lib="es2018.promise" />
/// <reference lib="es2018.regexp" />
/// <reference lib="es2018.intl" />
-2
View File
@@ -1,5 +1,3 @@
/// <reference lib="es2019" />
/// <reference lib="esnext.asynciterable" />
/// <reference lib="esnext.array" />
/// <reference lib="esnext.bigint" />
/// <reference lib="esnext.intl" />
+1 -1
View File
@@ -30,13 +30,13 @@
"es2017.string",
"es2017.intl",
"es2017.typedarrays",
"es2018.asynciterable",
"es2018.regexp",
"es2018.promise",
"es2018.intl",
"es2019.array",
"es2019.string",
"es2019.symbol",
"esnext.asynciterable",
"esnext.bigint",
"esnext.intl",
// Default libraries
+8 -3
View File
@@ -16,18 +16,20 @@ namespace ts {
public pos: number;
public end: number;
public flags: NodeFlags;
public modifierFlagsCache: ModifierFlags;
public transformFlags: TransformFlags;
public parent: Node;
public symbol!: Symbol; // Actually optional, but it was too annoying to access `node.symbol!` everywhere since in many cases we know it must be defined
public jsDoc?: JSDoc[];
public original?: Node;
public transformFlags: TransformFlags;
private _children: Node[] | undefined;
constructor(kind: SyntaxKind, pos: number, end: number) {
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.transformFlags = undefined!; // TODO: GH#18217
this.modifierFlagsCache = ModifierFlags.None;
this.transformFlags = TransformFlags.None;
this.parent = undefined!;
this.kind = kind;
}
@@ -200,16 +202,19 @@ namespace ts {
public pos: number;
public end: number;
public flags: NodeFlags;
public modifierFlagsCache: ModifierFlags;
public transformFlags: TransformFlags;
public parent: Node;
public symbol!: Symbol;
public jsDocComments?: JSDoc[];
public transformFlags!: TransformFlags;
constructor(pos: number, end: number) {
// Set properties in same order as NodeObject
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.modifierFlagsCache = ModifierFlags.None;
this.transformFlags = TransformFlags.None;
this.parent = undefined!;
}
+1
View File
@@ -58,6 +58,7 @@
"unittests/publicApi.ts",
"unittests/reuseProgramStructure.ts",
"unittests/semver.ts",
"unittests/shimMap.ts",
"unittests/transform.ts",
"unittests/tsbuild.ts",
"unittests/tsbuildWatchMode.ts",
@@ -57,7 +57,7 @@ namespace ts {
assertParseResult(["--lib", "es5,invalidOption", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
@@ -259,7 +259,7 @@ namespace ts {
assertParseResult(["--lib", "es5,", "es7", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
@@ -278,7 +278,7 @@ namespace ts {
assertParseResult(["--lib", "es5, ", "es7", "0.ts"],
{
errors: [{
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.string', 'es2019.symbol', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
file: undefined,
@@ -295,7 +295,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint'.",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
@@ -326,7 +326,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint'.",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
@@ -357,7 +357,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint'.",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
@@ -388,7 +388,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint'.",
messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint'.",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]
+106
View File
@@ -0,0 +1,106 @@
namespace ts {
describe("unittests:: shimMap", () => {
function testMapIterationAddedValues(map: Map<string>, useForEach: boolean): string {
let resultString = "";
map.set("1", "1");
map.set("3", "3");
map.set("2", "2");
map.set("4", "4");
let addedThree = false;
const doForEach = (value: string, key: string) => {
resultString += `${key}:${value};`;
// Add a new key ("0") - the map should provide this
// one in the next iteration.
if (key === "1") {
map.set("1", "X1");
map.set("0", "X0");
map.set("4", "X4");
}
else if (key === "3") {
if (!addedThree) {
addedThree = true;
// Remove and re-add key "3"; the map should
// visit it after "0".
map.delete("3");
map.set("3", "Y3");
// Change the value of "2"; the map should provide
// it when visiting the key.
map.set("2", "Y2");
}
else {
// Check that an entry added when we visit the
// currently last entry will still be visited.
map.set("999", "999");
}
}
else if (key === "999") {
// Ensure that clear() behaves correctly same as removing all keys.
map.set("A", "A");
map.set("B", "B");
map.set("C", "C");
}
else if (key === "A") {
map.clear();
map.set("Z", "Z");
}
else if (key === "Z") {
// Check that the map behaves correctly when two items are
// added and removed immediately.
map.set("X", "X");
map.set("X1", "X1");
map.set("X2", "X2");
map.delete("X1");
map.delete("X2");
map.set("Y", "Y");
}
};
if (useForEach) {
map.forEach(doForEach);
}
else {
// Use an iterator.
const iterator = map.entries();
while (true) {
const { value: tuple, done } = iterator.next();
if (done) {
break;
}
doForEach(tuple[1], tuple[0]);
}
}
return resultString;
}
it("iterates values in insertion order and handles changes", () => {
const expectedResult = "1:1;3:3;2:Y2;4:X4;0:X0;3:Y3;999:999;A:A;Z:Z;X:X;Y:Y;";
// First, ensure the test actually has the same behavior as a native Map.
let nativeMap = createMap<string>();
const nativeMapForEachResult = testMapIterationAddedValues(nativeMap, /* useForEach */ true);
assert.equal(nativeMapForEachResult, expectedResult, "nativeMap-forEach");
nativeMap = createMap<string>();
const nativeMapIteratorResult = testMapIterationAddedValues(nativeMap, /* useForEach */ false);
assert.equal(nativeMapIteratorResult, expectedResult, "nativeMap-iterator");
// Then, test the shimMap.
let localShimMap = new (shimMap())<string>();
const shimMapForEachResult = testMapIterationAddedValues(localShimMap, /* useForEach */ true);
assert.equal(shimMapForEachResult, expectedResult, "shimMap-forEach");
localShimMap = new (shimMap())<string>();
const shimMapIteratorResult = testMapIterationAddedValues(localShimMap, /* useForEach */ false);
assert.equal(shimMapIteratorResult, expectedResult, "shimMap-iterator");
});
});
}