Merge pull request #10303 from Microsoft/not_needed_types

Allow `"typings": null`
This commit is contained in:
Andy 2016-08-12 08:55:32 -07:00 committed by GitHub
commit b988bc98a1
8 changed files with 86 additions and 53 deletions

View file

@ -119,49 +119,31 @@ namespace ts {
}
function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
let jsonContent: { typings?: string, types?: string, main?: string };
try {
const jsonText = state.host.readFile(packageJsonPath);
jsonContent = jsonText ? <{ typings?: string, types?: string, main?: string }>JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
jsonContent = {};
const jsonContent = readJson(packageJsonPath, state.host);
function tryReadFromField(fieldName: string) {
if (hasProperty(jsonContent, fieldName)) {
const typesFile = (<any>jsonContent)[fieldName];
if (typeof typesFile === "string") {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
return typesFilePath;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof typesFile);
}
}
}
}
let typesFile: string;
let fieldName: string;
// first try to read content of 'typings' section (backward compatibility)
if (jsonContent.typings) {
if (typeof jsonContent.typings === "string") {
fieldName = "typings";
typesFile = jsonContent.typings;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "typings", typeof jsonContent.typings);
}
}
}
// then read 'types'
if (!typesFile && jsonContent.types) {
if (typeof jsonContent.types === "string") {
fieldName = "types";
typesFile = jsonContent.types;
}
else {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, "types", typeof jsonContent.types);
}
}
}
if (typesFile) {
const typesFilePath = normalizePath(combinePaths(baseDirectory, typesFile));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, typesFile, typesFilePath);
}
const typesFilePath = tryReadFromField("typings") || tryReadFromField("types");
if (typesFilePath) {
return typesFilePath;
}
// Use the main module for inferring types if no types package specified and the allowJs is set
if (state.compilerOptions.allowJs && jsonContent.main && typeof jsonContent.main === "string") {
if (state.traceEnabled) {
@ -173,6 +155,17 @@ namespace ts {
return undefined;
}
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
try {
const jsonText = host.readFile(path);
return jsonText ? JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
return {};
}
}
const typeReferenceExtensions = [".d.ts"];
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
@ -717,7 +710,7 @@ namespace ts {
}
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, state: ModuleResolutionState): string {
const packageJsonPath = combinePaths(candidate, "package.json");
const packageJsonPath = pathToPackageJson(candidate);
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
if (directoryExists && state.host.fileExists(packageJsonPath)) {
if (state.traceEnabled) {
@ -747,6 +740,10 @@ namespace ts {
return loadModuleFromFile(combinePaths(candidate, "index"), extensions, failedLookupLocation, !directoryExists, state);
}
function pathToPackageJson(directory: string): string {
return combinePaths(directory, "package.json");
}
function loadModuleFromNodeModulesFolder(moduleName: string, directory: string, failedLookupLocations: string[], state: ModuleResolutionState): string {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
@ -1070,15 +1067,21 @@ namespace ts {
}
// Walk the primary type lookup locations
let result: string[] = [];
const result: string[] = [];
if (host.directoryExists && host.getDirectories) {
const typeRoots = getEffectiveTypeRoots(options, host);
if (typeRoots) {
for (const root of typeRoots) {
if (host.directoryExists(root)) {
for (const typeDirectivePath of host.getDirectories(root)) {
// Return just the type directive names
result = result.concat(getBaseFileName(normalizePath(typeDirectivePath)));
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && readJson(packageJsonPath, host).typings === null;
if (!isNotNeededPackage) {
// Return just the type directive names
result.push(getBaseFileName(normalized));
}
}
}
}

View file

@ -52,7 +52,7 @@ class CompilerBaselineRunner extends RunnerBase {
private makeUnitName(name: string, root: string) {
const path = ts.toPath(name, root, (fileName) => Harness.Compiler.getCanonicalFileName(fileName));
const pathStart = ts.toPath(Harness.IO.getCurrentDirectory(), "", (fileName) => Harness.Compiler.getCanonicalFileName(fileName));
return path.replace(pathStart, "/");
return pathStart ? path.replace(pathStart, "/") : path;
};
public checkTestCodeOutput(fileName: string) {

View file

@ -2395,13 +2395,14 @@ ${code}
// Comment line, check for global/file @options and record them
const match = optionRegex.exec(line.substr(2));
if (match) {
const fileMetadataNamesIndex = fileMetadataNames.indexOf(match[1]);
const [key, value] = match.slice(1);
const fileMetadataNamesIndex = fileMetadataNames.indexOf(key);
if (fileMetadataNamesIndex === -1) {
// Check if the match is already existed in the global options
if (globalOptions[match[1]] !== undefined) {
throw new Error("Global Option : '" + match[1] + "' is already existed");
if (globalOptions[key] !== undefined) {
throw new Error(`Global option '${key}' already exists`);
}
globalOptions[match[1]] = match[2];
globalOptions[key] = value;
}
else {
if (fileMetadataNamesIndex === fileMetadataNames.indexOf(metadataOptionNames.fileName)) {
@ -2416,12 +2417,12 @@ ${code}
resetLocalData();
}
currentFileName = basePath + "/" + match[2];
currentFileOptions[match[1]] = match[2];
currentFileName = basePath + "/" + value;
currentFileOptions[key] = value;
}
else {
// Add other fileMetadata flag
currentFileOptions[match[1]] = match[2];
currentFileOptions[key] = value;
}
}
}
@ -2509,7 +2510,7 @@ ${code}
}
const marker: Marker = {
fileName: fileName,
fileName,
position: location.position,
data: markerValue
};
@ -2526,7 +2527,7 @@ ${code}
function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: MarkerMap, markers: Marker[]): Marker {
const marker: Marker = {
fileName: fileName,
fileName,
position: location.position
};

View file

@ -0,0 +1,9 @@
//// [tests/cases/conformance/typings/typingsLookup2.ts] ////
//// [package.json]
{ "typings": null }
//// [a.ts]
//// [a.js]

View file

@ -0,0 +1,3 @@
=== /a.ts ===
No type information for this code.

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,3 @@
=== /a.ts ===
No type information for this code.

View file

@ -0,0 +1,13 @@
// @traceResolution: true
// @noImplicitReferences: true
// @currentDirectory: /
// This tests that an @types package with `"typings": null` is not automatically included.
// (If it were, this test would break because there are no typings to be found.)
// @filename: /tsconfig.json
{}
// @filename: /node_modules/@types/angular2/package.json
{ "typings": null }
// @filename: /a.ts