mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Remove shims project (#50049)
This commit is contained in:
parent
7f1dc78f54
commit
b56483feb8
10
Gulpfile.js
10
Gulpfile.js
@ -92,18 +92,12 @@ const localize = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const buildShims = () => buildProject("src/shims");
|
||||
const cleanShims = () => cleanProject("src/shims");
|
||||
cleanTasks.push(cleanShims);
|
||||
|
||||
const buildDebugTools = () => buildProject("src/debug");
|
||||
const cleanDebugTools = () => cleanProject("src/debug");
|
||||
cleanTasks.push(cleanDebugTools);
|
||||
|
||||
const buildShimsAndTools = parallel(buildShims, buildDebugTools);
|
||||
|
||||
// Pre-build steps when targeting the LKG compiler
|
||||
const lkgPreBuild = parallel(generateLibs, series(buildScripts, generateDiagnostics, buildShimsAndTools));
|
||||
const lkgPreBuild = parallel(generateLibs, series(buildScripts, generateDiagnostics, buildDebugTools));
|
||||
|
||||
const buildTsc = () => buildProject("src/tsc");
|
||||
task("tsc", series(lkgPreBuild, buildTsc));
|
||||
@ -119,7 +113,7 @@ task("watch-tsc", series(lkgPreBuild, parallel(watchLib, watchDiagnostics, watch
|
||||
task("watch-tsc").description = "Watch for changes and rebuild the command-line compiler only.";
|
||||
|
||||
// Pre-build steps when targeting the built/local compiler.
|
||||
const localPreBuild = parallel(generateLibs, series(buildScripts, generateDiagnostics, buildShimsAndTools, buildTsc));
|
||||
const localPreBuild = parallel(generateLibs, series(buildScripts, generateDiagnostics, buildDebugTools, buildTsc));
|
||||
|
||||
// Pre-build steps to use based on supplied options.
|
||||
const preBuild = cmdLineOptions.lkg ? lkgPreBuild : localPreBuild;
|
||||
|
||||
@ -124,45 +124,34 @@ namespace ts {
|
||||
/**
|
||||
* Returns the native Map implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeMap(): MapConstructor | undefined {
|
||||
export function tryGetNativeMap(): MapConstructor {
|
||||
// Internet Explorer's Map doesn't support iteration, so don't use it.
|
||||
const gMap = globals?.Map;
|
||||
// eslint-disable-next-line no-in-operator
|
||||
return typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap : undefined;
|
||||
const constructor = typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Map implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native Set implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeSet(): SetConstructor | undefined {
|
||||
export function tryGetNativeSet(): SetConstructor {
|
||||
// Internet Explorer's Set doesn't support iteration, so don't use it.
|
||||
const gSet = globals?.Set;
|
||||
// eslint-disable-next-line no-in-operator
|
||||
return typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 ? gSet : undefined;
|
||||
const constructor = typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 ? gSet : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Set implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const Map = getCollectionImplementation("Map", "tryGetNativeMap", "createMapShim");
|
||||
export const Map = NativeCollections.tryGetNativeMap();
|
||||
/* @internal */
|
||||
export const Set = getCollectionImplementation("Set", "tryGetNativeSet", "createSetShim");
|
||||
|
||||
/* @internal */
|
||||
type GetIteratorCallback = <I extends readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined>(iterable: I) => Iterator<
|
||||
I extends ReadonlyESMap<infer K, infer V> ? [K, V] :
|
||||
I extends ReadonlySet<infer T> ? T :
|
||||
I extends readonly (infer T)[] ? T :
|
||||
I extends undefined ? undefined :
|
||||
never>;
|
||||
|
||||
/* @internal */
|
||||
function getCollectionImplementation<
|
||||
K1 extends MatchingKeys<typeof NativeCollections, () => any>,
|
||||
K2 extends MatchingKeys<typeof ShimCollections, (getIterator?: GetIteratorCallback) => ReturnType<(typeof NativeCollections)[K1]>>
|
||||
>(name: string, nativeFactory: K1, shimFactory: K2): NonNullable<ReturnType<(typeof NativeCollections)[K1]>> {
|
||||
// NOTE: ts.ShimCollections will be defined for typescriptServices.js but not for tsc.js, so we must test for it.
|
||||
const constructor = NativeCollections[nativeFactory]() ?? ShimCollections?.[shimFactory](getIterator);
|
||||
if (constructor) return constructor as NonNullable<ReturnType<(typeof NativeCollections)[K1]>>;
|
||||
throw new Error(`TypeScript requires an environment that provides a compatible native ${name} implementation.`);
|
||||
}
|
||||
export const Set = NativeCollections.tryGetNativeSet();
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
},
|
||||
|
||||
"references": [
|
||||
{ "path": "../shims" }
|
||||
],
|
||||
|
||||
"files": [
|
||||
|
||||
@ -6,6 +6,5 @@
|
||||
"preserveConstEnums": false
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../shims" }
|
||||
]
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
"outFile": "../../built/local/services.js"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../shims" },
|
||||
{ "path": "../compiler" },
|
||||
{ "path": "../jsTyping" }
|
||||
],
|
||||
|
||||
@ -1,267 +0,0 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
type GetIteratorCallback = <I extends readonly any[] | ReadonlySetShim<any> | ReadonlyMapShim<any, any> | undefined>(iterable: I) => IteratorShim<
|
||||
I extends ReadonlyMapShim<infer K, infer V> ? [K, V] :
|
||||
I extends ReadonlySetShim<infer T> ? T :
|
||||
I extends readonly (infer T)[] ? T :
|
||||
I extends undefined ? undefined :
|
||||
never>;
|
||||
|
||||
type IteratorResultShim<T> =
|
||||
| { value: T, done?: false }
|
||||
| { value: void, done: true };
|
||||
|
||||
interface IteratorShim<T> {
|
||||
next(): IteratorResultShim<T>;
|
||||
}
|
||||
|
||||
interface ReadonlyMapShim<K, V> {
|
||||
readonly size: number;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
keys(): IteratorShim<K>;
|
||||
values(): IteratorShim<V>;
|
||||
entries(): IteratorShim<[K, V]>;
|
||||
forEach(action: (value: V, key: K) => void): void;
|
||||
}
|
||||
|
||||
interface MapShim<K, V> extends ReadonlyMapShim<K, V> {
|
||||
set(key: K, value: V): this;
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
type MapShimConstructor = new <K, V>(iterable?: readonly (readonly [K, V])[] | ReadonlyMapShim<K, V>) => MapShim<K, V>;
|
||||
|
||||
interface ReadonlySetShim<T> {
|
||||
readonly size: number;
|
||||
has(value: T): boolean;
|
||||
keys(): IteratorShim<T>;
|
||||
values(): IteratorShim<T>;
|
||||
entries(): IteratorShim<[T, T]>;
|
||||
forEach(action: (value: T, key: T) => void): void;
|
||||
}
|
||||
|
||||
interface SetShim<T> extends ReadonlySetShim<T> {
|
||||
add(value: T): this;
|
||||
delete(value: T): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
type SetShimConstructor = new <T>(iterable?: readonly T[] | ReadonlySetShim<T>) => SetShim<T>;
|
||||
|
||||
interface MapData<K, V> {
|
||||
size: number;
|
||||
readonly head: MapEntry<K, V>;
|
||||
tail: MapEntry<K, V>;
|
||||
}
|
||||
|
||||
interface MapEntry<K, V> {
|
||||
readonly key?: K;
|
||||
value?: V;
|
||||
/**
|
||||
* Specifies the next entry in the linked list.
|
||||
*/
|
||||
next?: MapEntry<K, V>;
|
||||
/**
|
||||
* Specifies the previous entry in the linked list.
|
||||
* Must be set when the entry is part of a Map/Set.
|
||||
* When 'undefined', iterators should skip the next entry.
|
||||
* This will be set to 'undefined' when an entry is deleted.
|
||||
* See https://github.com/Microsoft/TypeScript/pull/27292 for more information.
|
||||
*/
|
||||
prev?: MapEntry<K, V>;
|
||||
}
|
||||
|
||||
interface IteratorData<K, V, U extends (K | V | [K, V])> {
|
||||
current?: MapEntry<K, V>;
|
||||
selector: (key: K, value: V) => U;
|
||||
}
|
||||
|
||||
function createMapData<K, V>(): MapData<K, V> {
|
||||
const sentinel: MapEntry<K, V> = {};
|
||||
sentinel.prev = sentinel;
|
||||
return { head: sentinel, tail: sentinel, size: 0 };
|
||||
}
|
||||
|
||||
function createMapEntry<K, V>(key: K, value: V): MapEntry<K, V> {
|
||||
return { key, value, next: undefined, prev: undefined };
|
||||
}
|
||||
|
||||
function sameValueZero(x: unknown, y: unknown) {
|
||||
// Treats -0 === 0 and NaN === NaN
|
||||
return x === y || x !== x && y !== y;
|
||||
}
|
||||
|
||||
function getPrev<K, V>(entry: MapEntry<K, V>) {
|
||||
const prev = entry.prev;
|
||||
// Entries without a 'prev' have been removed from the map.
|
||||
// An entry whose 'prev' points to itself is the head of the list and is invalid here.
|
||||
if (!prev || prev === entry) throw new Error("Illegal state");
|
||||
return prev;
|
||||
}
|
||||
|
||||
function getNext<K, V>(entry: MapEntry<K, V> | undefined) {
|
||||
while (entry) {
|
||||
// Entries without a 'prev' have been removed from the map. Their 'next'
|
||||
// pointer should point to the previous entry prior to deletion and
|
||||
// that entry should be skipped to resume iteration.
|
||||
const skipNext = !entry.prev;
|
||||
entry = entry.next;
|
||||
if (skipNext) {
|
||||
continue;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
function getEntry<K, V>(data: MapData<K, V>, key: K): MapEntry<K, V> | undefined {
|
||||
// We walk backwards from 'tail' to prioritize recently added entries.
|
||||
// We skip 'head' because it is an empty entry used to track iteration start.
|
||||
for (let entry = data.tail; entry !== data.head; entry = getPrev(entry)) {
|
||||
if (sameValueZero(entry.key, key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addOrUpdateEntry<K, V>(data: MapData<K, V>, key: K, value: V): MapEntry<K, V> | undefined {
|
||||
const existing = getEntry(data, key);
|
||||
if (existing) {
|
||||
existing.value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = createMapEntry(key, value);
|
||||
entry.prev = data.tail;
|
||||
data.tail.next = entry;
|
||||
data.tail = entry;
|
||||
data.size++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
function deleteEntry<K, V>(data: MapData<K, V>, key: K): MapEntry<K, V> | undefined {
|
||||
// We walk backwards from 'tail' to prioritize recently added entries.
|
||||
// We skip 'head' because it is an empty entry used to track iteration start.
|
||||
for (let entry = data.tail; entry !== data.head; entry = getPrev(entry)) {
|
||||
// all entries in the map should have a 'prev' pointer.
|
||||
if (entry.prev === undefined) throw new Error("Illegal state");
|
||||
if (sameValueZero(entry.key, key)) {
|
||||
if (entry.next) {
|
||||
entry.next.prev = entry.prev;
|
||||
}
|
||||
else {
|
||||
// an entry in the map without a 'next' pointer must be the 'tail'.
|
||||
if (data.tail !== entry) throw new Error("Illegal state");
|
||||
data.tail = entry.prev;
|
||||
}
|
||||
|
||||
entry.prev.next = entry.next;
|
||||
entry.next = entry.prev;
|
||||
entry.prev = undefined;
|
||||
data.size--;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearEntries<K, V>(data: MapData<K, V>) {
|
||||
let node = data.tail;
|
||||
while (node !== data.head) {
|
||||
const prev = getPrev(node);
|
||||
node.next = data.head;
|
||||
node.prev = undefined;
|
||||
node = prev;
|
||||
}
|
||||
data.head.next = undefined;
|
||||
data.tail = data.head;
|
||||
data.size = 0;
|
||||
}
|
||||
|
||||
function forEachEntry<K, V>(data: MapData<K, V>, action: (value: V, key: K) => void) {
|
||||
let entry: MapEntry<K, V> | undefined = data.head;
|
||||
while (entry) {
|
||||
entry = getNext(entry);
|
||||
if (entry) {
|
||||
action(entry.value!, entry.key!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function forEachIteration<T>(iterator: IteratorShim<T> | undefined, action: (value: any) => void) {
|
||||
if (iterator) {
|
||||
for (let step = iterator.next(); !step.done; step = iterator.next()) {
|
||||
action(step.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createIteratorData<K, V, U extends (K | V | [K, V])>(data: MapData<K, V>, selector: (key: K, value: V) => U): IteratorData<K, V, U> {
|
||||
return { current: data.head, selector };
|
||||
}
|
||||
|
||||
function iteratorNext<K, V, U extends (K | V | [K, V])>(data: IteratorData<K, V, U>): IteratorResultShim<U> {
|
||||
// Navigate to the next entry.
|
||||
data.current = getNext(data.current);
|
||||
if (data.current) {
|
||||
return { value: data.selector(data.current.key!, data.current.value!), done: false };
|
||||
}
|
||||
else {
|
||||
return { value: undefined as never, done: true };
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export namespace ShimCollections {
|
||||
export function createMapShim(getIterator: GetIteratorCallback): MapShimConstructor {
|
||||
class MapIterator<K, V, U extends (K | V | [K, V])> {
|
||||
private _data: IteratorData<K, V, U>;
|
||||
constructor(data: MapData<K, V>, selector: (key: K, value: V) => U) {
|
||||
this._data = createIteratorData(data, selector);
|
||||
}
|
||||
next() { return iteratorNext(this._data); }
|
||||
}
|
||||
return class Map<K, V> implements MapShim<K, V> {
|
||||
private _mapData = createMapData<K, V>();
|
||||
constructor(iterable?: readonly (readonly [K, V])[] | ReadonlyMapShim<K, V>) {
|
||||
forEachIteration(getIterator(iterable), ([key, value]) => this.set(key, value));
|
||||
}
|
||||
get size() { return this._mapData.size; }
|
||||
get(key: K): V | undefined { return getEntry(this._mapData, key)?.value; }
|
||||
set(key: K, value: V): this { return addOrUpdateEntry(this._mapData, key, value), this; }
|
||||
has(key: K): boolean { return !!getEntry(this._mapData, key); }
|
||||
delete(key: K): boolean { return !!deleteEntry(this._mapData, key); }
|
||||
clear(): void { clearEntries(this._mapData); }
|
||||
keys(): IteratorShim<K> { return new MapIterator(this._mapData, (key, _value) => key); }
|
||||
values(): IteratorShim<V> { return new MapIterator(this._mapData, (_key, value) => value); }
|
||||
entries(): IteratorShim<[K, V]> { return new MapIterator(this._mapData, (key, value) => [key, value]); }
|
||||
forEach(action: (value: V, key: K) => void): void { forEachEntry(this._mapData, action); }
|
||||
};
|
||||
}
|
||||
|
||||
export function createSetShim(getIterator: GetIteratorCallback): SetShimConstructor {
|
||||
class SetIterator<K, V, U extends (K | V | [K, V])> {
|
||||
private _data: IteratorData<K, V, U>;
|
||||
constructor(data: MapData<K, V>, selector: (key: K, value: V) => U) {
|
||||
this._data = createIteratorData(data, selector);
|
||||
}
|
||||
next() { return iteratorNext(this._data); }
|
||||
}
|
||||
return class Set<T> implements SetShim<T> {
|
||||
private _mapData = createMapData<T, T>();
|
||||
constructor(iterable?: readonly T[] | ReadonlySetShim<T>) {
|
||||
forEachIteration(getIterator(iterable), value => this.add(value));
|
||||
}
|
||||
get size() { return this._mapData.size; }
|
||||
add(value: T): this { return addOrUpdateEntry(this._mapData, value, value), this; }
|
||||
has(value: T): boolean { return !!getEntry(this._mapData, value); }
|
||||
delete(value: T): boolean { return !!deleteEntry(this._mapData, value); }
|
||||
clear(): void { clearEntries(this._mapData); }
|
||||
keys(): IteratorShim<T> { return new SetIterator(this._mapData, (key, _value) => key); }
|
||||
values(): IteratorShim<T> { return new SetIterator(this._mapData, (_key, value) => value); }
|
||||
entries(): IteratorShim<[T, T]> { return new SetIterator(this._mapData, (key, value) => [key, value]); }
|
||||
forEach(action: (value: T, key: T) => void): void { forEachEntry(this._mapData, action); }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"outFile": "../../built/local/shims.js"
|
||||
},
|
||||
"files": [
|
||||
"collectionShims.ts",
|
||||
]
|
||||
}
|
||||
@ -14,7 +14,6 @@
|
||||
]
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../shims", "prepend": true },
|
||||
{ "path": "../compiler", "prepend": true },
|
||||
{ "path": "../executeCommandLine", "prepend": true },
|
||||
{ "path": "../services", "prepend": true },
|
||||
@ -76,8 +75,6 @@
|
||||
"unittests/publicApi.ts",
|
||||
"unittests/reuseProgramStructure.ts",
|
||||
"unittests/semver.ts",
|
||||
"unittests/createMapShim.ts",
|
||||
"unittests/createSetShim.ts",
|
||||
"unittests/transform.ts",
|
||||
"unittests/config/commandLineParsing.ts",
|
||||
"unittests/config/configurationExtension.ts",
|
||||
|
||||
@ -1,326 +0,0 @@
|
||||
namespace ts {
|
||||
describe("unittests:: createMapShim", () => {
|
||||
|
||||
const stringKeys = [
|
||||
"1",
|
||||
"3",
|
||||
"2",
|
||||
"4",
|
||||
"0",
|
||||
"999",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"Z",
|
||||
"X",
|
||||
"X1",
|
||||
"X2",
|
||||
"Y"
|
||||
];
|
||||
|
||||
const mixedKeys = [
|
||||
true,
|
||||
3,
|
||||
{ toString() { return "2"; } },
|
||||
"4",
|
||||
false,
|
||||
null, // eslint-disable-line no-null/no-null
|
||||
undefined,
|
||||
"B",
|
||||
{ toString() { return "C"; } },
|
||||
"Z",
|
||||
"X",
|
||||
{ toString() { return "X1"; } },
|
||||
"X2",
|
||||
"Y"
|
||||
];
|
||||
|
||||
function testMapIterationAddedValues<K>(keys: K[], map: ESMap<K, string>, useForEach: boolean): string {
|
||||
let resultString = "";
|
||||
|
||||
map.set(keys[0], "1");
|
||||
map.set(keys[1], "3");
|
||||
map.set(keys[2], "2");
|
||||
map.set(keys[3], "4");
|
||||
|
||||
let addedThree = false;
|
||||
const doForEach = (value: string, key: K) => {
|
||||
resultString += `${key}:${value};`;
|
||||
|
||||
// Add a new key ("0") - the map should provide this
|
||||
// one in the next iteration.
|
||||
if (key === keys[0]) {
|
||||
map.set(keys[0], "X1");
|
||||
map.set(keys[4], "X0");
|
||||
map.set(keys[3], "X4");
|
||||
}
|
||||
else if (key === keys[1]) {
|
||||
if (!addedThree) {
|
||||
addedThree = true;
|
||||
|
||||
// Remove and re-add key "3"; the map should
|
||||
// visit it after "0".
|
||||
map.delete(keys[1]);
|
||||
map.set(keys[1], "Y3");
|
||||
|
||||
// Change the value of "2"; the map should provide
|
||||
// it when visiting the key.
|
||||
map.set(keys[2], "Y2");
|
||||
}
|
||||
else {
|
||||
// Check that an entry added when we visit the
|
||||
// currently last entry will still be visited.
|
||||
map.set(keys[5], "999");
|
||||
}
|
||||
}
|
||||
else if (key === keys[5]) {
|
||||
// Ensure that clear() behaves correctly same as removing all keys.
|
||||
map.set(keys[6], "A");
|
||||
map.set(keys[7], "B");
|
||||
map.set(keys[8], "C");
|
||||
}
|
||||
else if (key === keys[6]) {
|
||||
map.clear();
|
||||
map.set(keys[9], "Z");
|
||||
}
|
||||
else if (key === keys[9]) {
|
||||
// Check that the map behaves correctly when two items are
|
||||
// added and removed immediately.
|
||||
map.set(keys[10], "X");
|
||||
map.set(keys[11], "X1");
|
||||
map.set(keys[12], "X2");
|
||||
map.delete(keys[11]);
|
||||
map.delete(keys[12]);
|
||||
map.set(keys[13], "Y");
|
||||
}
|
||||
};
|
||||
|
||||
if (useForEach) {
|
||||
map.forEach(doForEach);
|
||||
}
|
||||
else {
|
||||
// Use an iterator.
|
||||
const iterator = map.entries();
|
||||
while (true) {
|
||||
const iterResult = iterator.next();
|
||||
if (iterResult.done) {
|
||||
break;
|
||||
}
|
||||
|
||||
const [key, value] = iterResult.value;
|
||||
doForEach(value, key);
|
||||
}
|
||||
}
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
let MapShim!: MapConstructor;
|
||||
beforeEach(() => {
|
||||
function getIterator<I extends readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined>(iterable: I): Iterator<
|
||||
I extends ReadonlyESMap<infer K, infer V> ? [K, V] :
|
||||
I extends ReadonlySet<infer T> ? T :
|
||||
I extends readonly (infer T)[] ? T :
|
||||
I extends undefined ? undefined :
|
||||
never>;
|
||||
function getIterator(iterable: readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined): Iterator<any> | undefined {
|
||||
// override `ts.getIterator` with a version that allows us to iterate over a `MapShim` in an environment with a native `Map`.
|
||||
if (iterable instanceof MapShim) return iterable.entries();
|
||||
return ts.getIterator(iterable);
|
||||
}
|
||||
|
||||
MapShim = ShimCollections.createMapShim(getIterator);
|
||||
});
|
||||
afterEach(() => {
|
||||
MapShim = undefined!;
|
||||
});
|
||||
|
||||
it("iterates values in insertion order and handles changes with string keys", () => {
|
||||
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 = new Map<string, string>();
|
||||
const nativeMapForEachResult = testMapIterationAddedValues(stringKeys, nativeMap, /* useForEach */ true);
|
||||
assert.equal(nativeMapForEachResult, expectedResult, "nativeMap-forEach");
|
||||
|
||||
nativeMap = new Map<string, string>();
|
||||
const nativeMapIteratorResult = testMapIterationAddedValues(stringKeys, nativeMap, /* useForEach */ false);
|
||||
assert.equal(nativeMapIteratorResult, expectedResult, "nativeMap-iterator");
|
||||
|
||||
// Then, test the map shim.
|
||||
let localShimMap = new MapShim<string, string>();
|
||||
const shimMapForEachResult = testMapIterationAddedValues(stringKeys, localShimMap, /* useForEach */ true);
|
||||
assert.equal(shimMapForEachResult, expectedResult, "shimMap-forEach");
|
||||
|
||||
localShimMap = new MapShim<string, string>();
|
||||
const shimMapIteratorResult = testMapIterationAddedValues(stringKeys, localShimMap, /* useForEach */ false);
|
||||
assert.equal(shimMapIteratorResult, expectedResult, "shimMap-iterator");
|
||||
});
|
||||
|
||||
it("iterates values in insertion order and handles changes with mixed-type keys", () => {
|
||||
const expectedResult = "true:1;3:3;2:Y2;4:X4;false:X0;3:Y3;null:999;undefined:A;Z:Z;X:X;Y:Y;";
|
||||
|
||||
// First, ensure the test actually has the same behavior as a native Map.
|
||||
let nativeMap = new Map<any, string>();
|
||||
const nativeMapForEachResult = testMapIterationAddedValues(mixedKeys, nativeMap, /* useForEach */ true);
|
||||
assert.equal(nativeMapForEachResult, expectedResult, "nativeMap-forEach");
|
||||
|
||||
nativeMap = new Map<any, string>();
|
||||
const nativeMapIteratorResult = testMapIterationAddedValues(mixedKeys, nativeMap, /* useForEach */ false);
|
||||
assert.equal(nativeMapIteratorResult, expectedResult, "nativeMap-iterator");
|
||||
|
||||
// Then, test the map shim.
|
||||
let localShimMap = new MapShim<any, string>();
|
||||
const shimMapForEachResult = testMapIterationAddedValues(mixedKeys, localShimMap, /* useForEach */ true);
|
||||
assert.equal(shimMapForEachResult, expectedResult, "shimMap-forEach");
|
||||
|
||||
localShimMap = new MapShim<any, string>();
|
||||
const shimMapIteratorResult = testMapIterationAddedValues(mixedKeys, localShimMap, /* useForEach */ false);
|
||||
assert.equal(shimMapIteratorResult, expectedResult, "shimMap-iterator");
|
||||
});
|
||||
|
||||
it("create from Array", () => {
|
||||
const map = new MapShim([["a", "b"]]);
|
||||
assert.equal(map.size, 1);
|
||||
assert.isTrue(map.has("a"));
|
||||
assert.equal(map.get("a"), "b");
|
||||
});
|
||||
|
||||
it("create from Map", () => {
|
||||
const map1 = new MapShim([["a", "b"]]);
|
||||
const map2 = new MapShim(map1);
|
||||
assert.equal(map1.size, 1);
|
||||
assert.equal(map2.size, 1);
|
||||
assert.isTrue(map2.has("a"));
|
||||
assert.equal(map2.get("a"), "b");
|
||||
});
|
||||
|
||||
it("set when not present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
const result = map.set("a", "b");
|
||||
assert.equal(map.size, 1);
|
||||
assert.strictEqual(result, map);
|
||||
assert.isTrue(map.has("a"));
|
||||
assert.equal(map.get("a"), "b");
|
||||
});
|
||||
|
||||
it("set when present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "z");
|
||||
const result = map.set("a", "b");
|
||||
assert.equal(map.size, 1);
|
||||
assert.strictEqual(result, map);
|
||||
assert.isTrue(map.has("a"));
|
||||
assert.equal(map.get("a"), "b");
|
||||
});
|
||||
|
||||
it("has when not present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
assert.isFalse(map.has("a"));
|
||||
});
|
||||
|
||||
it("has when present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
assert.isTrue(map.has("a"));
|
||||
});
|
||||
|
||||
it("get when not present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
assert.isUndefined(map.get("a"));
|
||||
});
|
||||
|
||||
it("get when present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
assert.equal(map.get("a"), "b");
|
||||
});
|
||||
|
||||
it("delete when not present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
assert.isFalse(map.delete("a"));
|
||||
});
|
||||
|
||||
it("delete when present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
assert.isTrue(map.delete("a"));
|
||||
});
|
||||
|
||||
it("delete twice when present", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
assert.isTrue(map.delete("a"));
|
||||
assert.isFalse(map.delete("a"));
|
||||
});
|
||||
|
||||
it("remove only item and iterate", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
map.delete("a");
|
||||
const actual = arrayFrom(map.keys());
|
||||
assert.deepEqual(actual, []);
|
||||
});
|
||||
|
||||
it("remove first item and iterate", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
map.set("c", "d");
|
||||
map.delete("a");
|
||||
assert.deepEqual(arrayFrom(map.keys()), ["c"]);
|
||||
assert.deepEqual(arrayFrom(map.values()), ["d"]);
|
||||
assert.deepEqual(arrayFrom(map.entries()), [["c", "d"]]);
|
||||
});
|
||||
|
||||
it("remove last item and iterate", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
map.set("c", "d");
|
||||
map.delete("c");
|
||||
assert.deepEqual(arrayFrom(map.keys()), ["a"]);
|
||||
assert.deepEqual(arrayFrom(map.values()), ["b"]);
|
||||
assert.deepEqual(arrayFrom(map.entries()), [["a", "b"]]);
|
||||
});
|
||||
|
||||
it("remove middle item and iterate", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("a", "b");
|
||||
map.set("c", "d");
|
||||
map.set("e", "f");
|
||||
map.delete("c");
|
||||
assert.deepEqual(arrayFrom(map.keys()), ["a", "e"]);
|
||||
assert.deepEqual(arrayFrom(map.values()), ["b", "f"]);
|
||||
assert.deepEqual(arrayFrom(map.entries()), [["a", "b"], ["e", "f"]]);
|
||||
});
|
||||
|
||||
it("keys", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("c", "d");
|
||||
map.set("a", "b");
|
||||
assert.deepEqual(arrayFrom(map.keys()), ["c", "a"]);
|
||||
});
|
||||
|
||||
it("values", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("c", "d");
|
||||
map.set("a", "b");
|
||||
assert.deepEqual(arrayFrom(map.values()), ["d", "b"]);
|
||||
});
|
||||
|
||||
it("entries", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("c", "d");
|
||||
map.set("a", "b");
|
||||
assert.deepEqual(arrayFrom(map.entries()), [["c", "d"], ["a", "b"]]);
|
||||
});
|
||||
|
||||
it("forEach", () => {
|
||||
const map = new MapShim<string, string>();
|
||||
map.set("c", "d");
|
||||
map.set("a", "b");
|
||||
const actual: [string, string][] = [];
|
||||
map.forEach((value, key) => actual.push([key, value]));
|
||||
assert.deepEqual(actual, [["c", "d"], ["a", "b"]]);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1,309 +0,0 @@
|
||||
namespace ts {
|
||||
describe("unittests:: createSetShim", () => {
|
||||
const stringKeys = [
|
||||
"1",
|
||||
"3",
|
||||
"2",
|
||||
"4",
|
||||
"0",
|
||||
"999",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"Z",
|
||||
"X",
|
||||
"X1",
|
||||
"X2",
|
||||
"Y"
|
||||
];
|
||||
|
||||
const mixedKeys = [
|
||||
true,
|
||||
3,
|
||||
{ toString() { return "2"; } },
|
||||
"4",
|
||||
false,
|
||||
null, // eslint-disable-line no-null/no-null
|
||||
undefined,
|
||||
"B",
|
||||
{ toString() { return "C"; } },
|
||||
"Z",
|
||||
"X",
|
||||
{ toString() { return "X1"; } },
|
||||
"X2",
|
||||
"Y"
|
||||
];
|
||||
|
||||
function testSetIterationAddedValues<K>(keys: K[], set: Set<K>, useForEach: boolean): string {
|
||||
let resultString = "";
|
||||
|
||||
set.add(keys[0]);
|
||||
set.add(keys[1]);
|
||||
set.add(keys[2]);
|
||||
set.add(keys[3]);
|
||||
|
||||
let addedThree = false;
|
||||
const doForEach = (key: K) => {
|
||||
resultString += `${key};`;
|
||||
|
||||
// Add a new key ("0") - the set should provide this
|
||||
// one in the next iteration.
|
||||
if (key === keys[0]) {
|
||||
set.add(keys[0]);
|
||||
set.add(keys[4]);
|
||||
set.add(keys[3]);
|
||||
}
|
||||
else if (key === keys[1]) {
|
||||
if (!addedThree) {
|
||||
addedThree = true;
|
||||
|
||||
// Remove and re-add key "3"; the set should
|
||||
// visit it after "0".
|
||||
set.delete(keys[1]);
|
||||
set.add(keys[1]);
|
||||
|
||||
// Change the value of "2"; the set should provide
|
||||
// it when visiting the key.
|
||||
set.add(keys[2]);
|
||||
}
|
||||
else {
|
||||
// Check that an entry added when we visit the
|
||||
// currently last entry will still be visited.
|
||||
set.add(keys[5]);
|
||||
}
|
||||
}
|
||||
else if (key === keys[5]) {
|
||||
// Ensure that clear() behaves correctly same as removing all keys.
|
||||
set.add(keys[6]);
|
||||
set.add(keys[7]);
|
||||
set.add(keys[8]);
|
||||
}
|
||||
else if (key === keys[6]) {
|
||||
set.clear();
|
||||
set.add(keys[9]);
|
||||
}
|
||||
else if (key === keys[9]) {
|
||||
// Check that the set behaves correctly when two items are
|
||||
// added and removed immediately.
|
||||
set.add(keys[10]);
|
||||
set.add(keys[11]);
|
||||
set.add(keys[12]);
|
||||
set.delete(keys[11]);
|
||||
set.delete(keys[12]);
|
||||
set.add(keys[13]);
|
||||
}
|
||||
};
|
||||
|
||||
if (useForEach) {
|
||||
set.forEach(doForEach);
|
||||
}
|
||||
else {
|
||||
// Use an iterator.
|
||||
const iterator = set.values();
|
||||
while (true) {
|
||||
const iterResult = iterator.next();
|
||||
if (iterResult.done) {
|
||||
break;
|
||||
}
|
||||
|
||||
doForEach(iterResult.value);
|
||||
}
|
||||
}
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
let SetShim!: SetConstructor;
|
||||
beforeEach(() => {
|
||||
function getIterator<I extends readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined>(iterable: I): Iterator<
|
||||
I extends ReadonlyESMap<infer K, infer V> ? [K, V] :
|
||||
I extends ReadonlySet<infer T> ? T :
|
||||
I extends readonly (infer T)[] ? T :
|
||||
I extends undefined ? undefined :
|
||||
never>;
|
||||
function getIterator(iterable: readonly any[] | ReadonlySet<any> | ReadonlyESMap<any, any> | undefined): Iterator<any> | undefined {
|
||||
// override `ts.getIterator` with a version that allows us to iterate over a `SetShim` in an environment with a native `Set`.
|
||||
if (iterable instanceof SetShim) return iterable.values();
|
||||
return ts.getIterator(iterable);
|
||||
}
|
||||
|
||||
SetShim = ShimCollections.createSetShim(getIterator);
|
||||
});
|
||||
afterEach(() => {
|
||||
SetShim = undefined!;
|
||||
});
|
||||
|
||||
it("iterates values in insertion order and handles changes with string keys", () => {
|
||||
const expectedResult = "1;3;2;4;0;3;999;A;Z;X;Y;";
|
||||
|
||||
// First, ensure the test actually has the same behavior as a native Set.
|
||||
let nativeSet = new Set<string>();
|
||||
const nativeSetForEachResult = testSetIterationAddedValues(stringKeys, nativeSet, /* useForEach */ true);
|
||||
assert.equal(nativeSetForEachResult, expectedResult, "nativeSet-forEach");
|
||||
|
||||
nativeSet = new Set<string>();
|
||||
const nativeSetIteratorResult = testSetIterationAddedValues(stringKeys, nativeSet, /* useForEach */ false);
|
||||
assert.equal(nativeSetIteratorResult, expectedResult, "nativeSet-iterator");
|
||||
|
||||
// Then, test the set shim.
|
||||
let localShimSet = new SetShim<string>();
|
||||
const shimSetForEachResult = testSetIterationAddedValues(stringKeys, localShimSet, /* useForEach */ true);
|
||||
assert.equal(shimSetForEachResult, expectedResult, "shimSet-forEach");
|
||||
|
||||
localShimSet = new SetShim<string>();
|
||||
const shimSetIteratorResult = testSetIterationAddedValues(stringKeys, localShimSet, /* useForEach */ false);
|
||||
assert.equal(shimSetIteratorResult, expectedResult, "shimSet-iterator");
|
||||
});
|
||||
|
||||
it("iterates values in insertion order and handles changes with mixed-type keys", () => {
|
||||
const expectedResult = "true;3;2;4;false;3;null;undefined;Z;X;Y;";
|
||||
|
||||
// First, ensure the test actually has the same behavior as a native Set.
|
||||
let nativeSet = new Set<any>();
|
||||
const nativeSetForEachResult = testSetIterationAddedValues(mixedKeys, nativeSet, /* useForEach */ true);
|
||||
assert.equal(nativeSetForEachResult, expectedResult, "nativeSet-forEach");
|
||||
|
||||
nativeSet = new Set<any>();
|
||||
const nativeSetIteratorResult = testSetIterationAddedValues(mixedKeys, nativeSet, /* useForEach */ false);
|
||||
assert.equal(nativeSetIteratorResult, expectedResult, "nativeSet-iterator");
|
||||
|
||||
// Then, test the set shim.
|
||||
let localshimSet = new SetShim<any>();
|
||||
const shimSetForEachResult = testSetIterationAddedValues(mixedKeys, localshimSet, /* useForEach */ true);
|
||||
assert.equal(shimSetForEachResult, expectedResult, "shimSet-forEach");
|
||||
|
||||
localshimSet = new SetShim<any>();
|
||||
const shimSetIteratorResult = testSetIterationAddedValues(mixedKeys, localshimSet, /* useForEach */ false);
|
||||
assert.equal(shimSetIteratorResult, expectedResult, "shimSet-iterator");
|
||||
});
|
||||
|
||||
it("create from Array", () => {
|
||||
const set = new SetShim(["a"]);
|
||||
assert.equal(set.size, 1);
|
||||
assert.isTrue(set.has("a"));
|
||||
});
|
||||
|
||||
it("create from set", () => {
|
||||
const set1 = new SetShim(["a"]);
|
||||
const set2 = new SetShim(set1);
|
||||
assert.equal(set1.size, 1);
|
||||
assert.equal(set2.size, 1);
|
||||
assert.isTrue(set2.has("a"));
|
||||
});
|
||||
|
||||
it("add when not present", () => {
|
||||
const set = new SetShim<string>();
|
||||
const result = set.add("a");
|
||||
assert.equal(set.size, 1);
|
||||
assert.strictEqual(result, set);
|
||||
assert.isTrue(set.has("a"));
|
||||
});
|
||||
|
||||
it("add when present", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
const result = set.add("a");
|
||||
assert.equal(set.size, 1);
|
||||
assert.strictEqual(result, set);
|
||||
assert.isTrue(set.has("a"));
|
||||
});
|
||||
|
||||
it("has when not present", () => {
|
||||
const set = new SetShim<string>();
|
||||
assert.isFalse(set.has("a"));
|
||||
});
|
||||
|
||||
it("has when present", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
assert.isTrue(set.has("a"));
|
||||
});
|
||||
|
||||
it("delete when not present", () => {
|
||||
const set = new SetShim<string>();
|
||||
assert.isFalse(set.delete("a"));
|
||||
});
|
||||
|
||||
it("delete when present", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
assert.isTrue(set.delete("a"));
|
||||
});
|
||||
|
||||
it("delete twice when present", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
assert.isTrue(set.delete("a"));
|
||||
assert.isFalse(set.delete("a"));
|
||||
});
|
||||
|
||||
it("remove only item and iterate", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
set.delete("a");
|
||||
const actual = arrayFrom(set.keys());
|
||||
assert.deepEqual(actual, []);
|
||||
});
|
||||
|
||||
it("remove first item and iterate", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
set.add("c");
|
||||
set.delete("a");
|
||||
assert.deepEqual(arrayFrom(set.keys()), ["c"]);
|
||||
assert.deepEqual(arrayFrom(set.values()), ["c"]);
|
||||
assert.deepEqual(arrayFrom(set.entries()), [["c", "c"]]);
|
||||
});
|
||||
|
||||
it("remove last item and iterate", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
set.add("c");
|
||||
set.delete("c");
|
||||
assert.deepEqual(arrayFrom(set.keys()), ["a"]);
|
||||
assert.deepEqual(arrayFrom(set.values()), ["a"]);
|
||||
assert.deepEqual(arrayFrom(set.entries()), [["a", "a"]]);
|
||||
});
|
||||
|
||||
it("remove middle item and iterate", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("a");
|
||||
set.add("c");
|
||||
set.add("e");
|
||||
set.delete("c");
|
||||
assert.deepEqual(arrayFrom(set.keys()), ["a", "e"]);
|
||||
assert.deepEqual(arrayFrom(set.values()), ["a", "e"]);
|
||||
assert.deepEqual(arrayFrom(set.entries()), [["a", "a"], ["e", "e"]]);
|
||||
});
|
||||
|
||||
it("keys", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("c");
|
||||
set.add("a");
|
||||
assert.deepEqual(arrayFrom(set.keys()), ["c", "a"]);
|
||||
});
|
||||
|
||||
it("values", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("c");
|
||||
set.add("a");
|
||||
assert.deepEqual(arrayFrom(set.values()), ["c", "a"]);
|
||||
});
|
||||
|
||||
it("entries", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("c");
|
||||
set.add("a");
|
||||
assert.deepEqual(arrayFrom(set.entries()), [["c", "c"], ["a", "a"]]);
|
||||
});
|
||||
|
||||
it("forEach", () => {
|
||||
const set = new SetShim<string>();
|
||||
set.add("c");
|
||||
set.add("a");
|
||||
const actual: [string, string][] = [];
|
||||
set.forEach((value, key) => actual.push([key, value]));
|
||||
assert.deepEqual(actual, [["c", "c"], ["a", "a"]]);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -2,7 +2,6 @@
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{ "path": "./shims" },
|
||||
{ "path": "./tsc" },
|
||||
{ "path": "./tsserver" },
|
||||
{ "path": "./typingsInstaller" },
|
||||
@ -12,4 +11,4 @@
|
||||
{ "path": "./dynamicImportCompat" },
|
||||
{ "path": "./testRunner" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
"tsserverlibrary.ts"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../shims", "prepend": true },
|
||||
{ "path": "../compiler", "prepend": true },
|
||||
{ "path": "../jsTyping", "prepend": true },
|
||||
{ "path": "../services", "prepend": true },
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
"typescriptServices.ts"
|
||||
],
|
||||
"references": [
|
||||
{ "path": "../shims", "prepend": true },
|
||||
{ "path": "../compiler", "prepend": true },
|
||||
{ "path": "../jsTyping", "prepend": true },
|
||||
{ "path": "../services", "prepend": true },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user