fix: parser fails with older scoped packages. (#208)

* fix: parser fails with older scoped packages.

Given a path mapping as

```
"paths": {
	"@ckeditor/ckeditor5-utils": [
		"ckeditor__ckeditor5-utils/v10"
	]
}
```

definitions-parser failed to understand that `/v10` is not part of the
package name, and that the key of the mapping must be a scoped name.

* Resolve PR comments

- add test coverage
- simplify implementation

* Add test in definition-parser

* Use scopedPackageName in Error for missing mapping

Co-authored-by: Piotr Błażejewicz <peterblazejewicz@users.noreply.github.com>
This commit is contained in:
Federico Panico
2021-03-05 15:59:19 -03:00
committed by GitHub
parent b6ffdea10c
commit fd4be462c3
5 changed files with 102 additions and 8 deletions

View File

@@ -23,7 +23,8 @@ import {
join,
flatMap,
unique,
unmangleScopedPackage
unmangleScopedPackage,
removeVersionFromPackageName
} from "@definitelytyped/utils";
import { TypeScriptVersion } from "@definitelytyped/typescript-versions";
@@ -467,7 +468,7 @@ function calculateDependencies(
const pathMapping = pathMappingList[0];
// Path mapping may be for "@foo/*" -> "foo__*".
const scopedPackageName = unmangleScopedPackage(pathMapping);
const scopedPackageName = removeVersionFromPackageName(unmangleScopedPackage(pathMapping));
if (scopedPackageName !== undefined) {
if (dependencyName !== scopedPackageName) {
throw new Error(`Expected directory ${pathMapping} to be the path mapping for ${dependencyName}`);
@@ -504,12 +505,13 @@ function calculateDependencies(
pathMappings[dependencyName] = pathMappingVersion;
}
if (directoryVersion !== undefined && !(paths && packageName in paths)) {
const scopedPackageName = unmangleScopedPackage(packageName) ?? packageName;
if (directoryVersion !== undefined && !(paths && scopedPackageName in paths)) {
const mapping = JSON.stringify([`${packageName}/v${formatTypingVersion(directoryVersion)}`]);
throw new Error(
`${packageName}: Older version ${formatTypingVersion(
`${scopedPackageName}: Older version ${formatTypingVersion(
directoryVersion
)} must have a "paths" entry of "${packageName}": ${mapping}`
)} must have a "paths" entry of "${scopedPackageName}": ${mapping}`
);
}

View File

@@ -1,5 +1,5 @@
import { parseHeaderOrFail } from "@definitelytyped/header-parser";
import { Dir, FS, InMemoryFS, Semver } from "@definitelytyped/utils";
import { Dir, FS, InMemoryFS, mangleScopedPackage, Semver } from "@definitelytyped/utils";
class DTMock {
public readonly fs: FS;
@@ -40,7 +40,7 @@ class DTMock {
* @param olderVersion The older version that's to be added.
*/
public addOldVersionOfPackage(packageName: string, olderVersion: string) {
const latestDir = this.pkgDir(packageName);
const latestDir = this.pkgDir(mangleScopedPackage(packageName));
const index = latestDir.get("index.d.ts") as string;
const latestHeader = parseHeaderOrFail(index);
const latestVersion = `${latestHeader.libraryMajorVersion}.${latestHeader.libraryMinorVersion}`;
@@ -57,7 +57,7 @@ class DTMock {
compilerOptions: {
...tsconfig.compilerOptions,
paths: {
[packageName]: [`${packageName}/v${olderVersion}`]
[packageName]: [`${mangleScopedPackage(packageName)}/v${olderVersion}`]
}
}
})

View File

@@ -17,6 +17,57 @@ describe(getTypingInfo, () => {
expect(info).toBeDefined();
});
it("works for a scoped package with scoped older dependencies", async () => {
const dt = createMockDT();
const scopedWithOlderScopedDependency = dt.pkgDir("ckeditor__ckeditor5-engine");
scopedWithOlderScopedDependency.set(
"index.d.ts",
`// Type definitions for @ckeditor/ckeditor-engine 25.0
// Project: https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-engine
// Definitions by: Federico <https://github.com/fedemp>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
import * as utils from '@ckeditor/ckeditor5-utils';`
);
scopedWithOlderScopedDependency.set(
"tsconfig.json",
JSON.stringify({
files: ["index.d.ts"],
compilerOptions: {
paths: {
"@ckeditor/ckeditor5-utils": ["ckeditor__ckeditor5-utils/v10"]
}
}
})
);
const olderScopedPackage = dt.pkgDir("ckeditor__ckeditor5-utils");
olderScopedPackage.set(
"index.d.ts",
`// Type definitions for @ckeditor/ckeditor5-utils 25.0
// Project: https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-utils
// Definitions by: Federico <https://github.com/fedemp>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
export function myFunction(arg:string): string;
`
);
olderScopedPackage.set(
"tsconfig.json",
JSON.stringify({
files: ["index.d.ts"],
compilerOptions: {
paths: {}
}
})
);
dt.addOldVersionOfPackage("@ckeditor/ckeditor5-utils", "10");
const info = await getTypingInfo("@ckeditor/ckeditor5-engine", dt.pkgFS("ckeditor__ckeditor5-engine"));
expect(info).toBeDefined();
});
describe("concerning multiple versions", () => {
it("records what the version directory looks like on disk", async () => {
const dt = createMockDT();

View File

@@ -24,12 +24,25 @@ export function computeHash(content: string): string {
return h.digest("hex");
}
export function isScopedPackage(packageName: string): boolean {
return packageName.startsWith("@");
}
// Based on `getPackageNameFromAtTypesDirectory` in TypeScript.
export function unmangleScopedPackage(packageName: string): string | undefined {
const separator = "__";
return packageName.includes(separator) ? `@${packageName.replace(separator, "/")}` : undefined;
}
// Reverts unmangleScopedPackage.
export function mangleScopedPackage(packageName: string): string {
return isScopedPackage(packageName) ? packageName.replace(/\//, "__").replace("@", "") : packageName;
}
export function removeVersionFromPackageName(packageName: string | undefined): string | undefined {
return packageName?.replace(/\/v(\d){1,}$/i, "");
}
export async function sleep(seconds: number): Promise<void> {
return new Promise<void>(resolve => setTimeout(resolve, seconds * 1000));
}

View File

@@ -0,0 +1,28 @@
import { removeVersionFromPackageName, unmangleScopedPackage } from "../src/miscellany";
describe("miscellany", () => {
describe(unmangleScopedPackage, () => {
it("for unscoped package returns undefined", () => {
expect(unmangleScopedPackage("foobar")).toBeUndefined();
expect(unmangleScopedPackage("utils")).toBeUndefined();
});
it("for scoped package returns unmangled name", () => {
expect(unmangleScopedPackage("foo__bar")).toBe("@foo/bar");
expect(unmangleScopedPackage("definitelytyped__utils")).toBe("@definitelytyped/utils");
});
});
describe(removeVersionFromPackageName, () => {
it("for non versioned package returns package", () => {
expect(removeVersionFromPackageName("@ckeditor/ckeditor5-utils")).toBe("@ckeditor/ckeditor5-utils");
expect(removeVersionFromPackageName("@foo/bar")).toBe("@foo/bar");
});
it("for versioned package returns package name only", () => {
expect(removeVersionFromPackageName("@ckeditor/ckeditor5-utils/v10")).toBe("@ckeditor/ckeditor5-utils");
expect(removeVersionFromPackageName("@foo/bar/v0")).toBe("@foo/bar");
expect(removeVersionFromPackageName("@foo/bar/V999")).toBe("@foo/bar");
});
});
});