treat ambient non-aliased 'require' as commonjs 'require'

This commit is contained in:
Vladimir Matveev 2016-10-24 11:19:41 -07:00
parent cef9d85979
commit b7ea3e5bdd
10 changed files with 197 additions and 9 deletions

View file

@ -12819,16 +12819,41 @@ namespace ts {
}
// In JavaScript files, calls to any identifier 'require' are treated as external module imports
if (isInJavaScriptFile(node) &&
isRequireCall(node, /*checkArgumentIsStringLiteral*/true) &&
// Make sure require is not a local function
!resolveName(node.expression, (<Identifier>node.expression).text, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined)) {
if (isInJavaScriptFile(node) && isCommonJsRequire(node)) {
return resolveExternalModuleTypeByLiteral(<StringLiteral>node.arguments[0]);
}
return getReturnTypeOfSignature(signature);
}
function isCommonJsRequire(node: Node) {
if (!isRequireCall(node, /*checkArgumentIsStringLiteral*/true)) {
return false;
}
// Make sure require is not a local function
const resolvedRequire = resolveName(node.expression, (<Identifier>node.expression).text, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
if (!resolvedRequire) {
// project does not contain symbol named 'require' - assume commonjs require
return true;
}
// project includes symbol named 'require' - make sure that it it ambient and local non-alias
if (resolvedRequire.flags & SymbolFlags.Alias) {
return false;
}
const targetDeclarationKind = resolvedRequire.flags & SymbolFlags.Function
? SyntaxKind.FunctionDeclaration
: resolvedRequire.flags & SymbolFlags.Variable
? SyntaxKind.VariableDeclaration
: SyntaxKind.Unknown;
if (targetDeclarationKind !== SyntaxKind.Unknown) {
const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind);
// function/variable declaration should be ambient
return isInAmbientContext(decl);
}
return false;
}
function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type {
return getReturnTypeOfSignature(getResolvedSignature(node));
}

View file

@ -0,0 +1,21 @@
//// [tests/cases/compiler/ambientRequireFunction.ts] ////
//// [node.d.ts]
declare function require(moduleName: string): any;
declare module "fs" {
export function readFileSync(s: string): string;
}
//// [app.js]
/// <reference path="node.d.ts"/>
const fs = require("fs");
const text = fs.readFileSync("/a/b/c");
//// [app.js]
/// <reference path="node.d.ts"/>
var fs = require("fs");
var text = fs.readFileSync("/a/b/c");

View file

@ -0,0 +1,27 @@
=== tests/cases/compiler/app.js ===
/// <reference path="node.d.ts"/>
const fs = require("fs");
>fs : Symbol(fs, Decl(app.js, 2, 5))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"fs" : Symbol("fs", Decl(node.d.ts, 2, 50))
const text = fs.readFileSync("/a/b/c");
>text : Symbol(text, Decl(app.js, 3, 5))
>fs.readFileSync : Symbol(readFileSync, Decl(node.d.ts, 4, 21))
>fs : Symbol(fs, Decl(app.js, 2, 5))
>readFileSync : Symbol(readFileSync, Decl(node.d.ts, 4, 21))
=== tests/cases/compiler/node.d.ts ===
declare function require(moduleName: string): any;
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>moduleName : Symbol(moduleName, Decl(node.d.ts, 2, 25))
declare module "fs" {
export function readFileSync(s: string): string;
>readFileSync : Symbol(readFileSync, Decl(node.d.ts, 4, 21))
>s : Symbol(s, Decl(node.d.ts, 5, 33))
}

View file

@ -0,0 +1,30 @@
=== tests/cases/compiler/app.js ===
/// <reference path="node.d.ts"/>
const fs = require("fs");
>fs : typeof "fs"
>require("fs") : typeof "fs"
>require : (moduleName: string) => any
>"fs" : "fs"
const text = fs.readFileSync("/a/b/c");
>text : string
>fs.readFileSync("/a/b/c") : string
>fs.readFileSync : (s: string) => string
>fs : typeof "fs"
>readFileSync : (s: string) => string
>"/a/b/c" : "/a/b/c"
=== tests/cases/compiler/node.d.ts ===
declare function require(moduleName: string): any;
>require : (moduleName: string) => any
>moduleName : string
declare module "fs" {
export function readFileSync(s: string): string;
>readFileSync : (s: string) => string
>s : string
}

View file

@ -0,0 +1,15 @@
//// [app.js]
function require(a) {
return a;
}
const fs = require("fs");
const text = fs.readFileSync("/a/b/c");
//// [app.js]
function require(a) {
return a;
}
var fs = require("fs");
var text = fs.readFileSync("/a/b/c");

View file

@ -0,0 +1,18 @@
=== tests/cases/compiler/app.js ===
function require(a) {
>require : Symbol(require, Decl(app.js, 0, 0))
>a : Symbol(a, Decl(app.js, 1, 17))
return a;
>a : Symbol(a, Decl(app.js, 1, 17))
}
const fs = require("fs");
>fs : Symbol(fs, Decl(app.js, 5, 5))
>require : Symbol(require, Decl(app.js, 0, 0))
const text = fs.readFileSync("/a/b/c");
>text : Symbol(text, Decl(app.js, 6, 5))
>fs : Symbol(fs, Decl(app.js, 5, 5))

View file

@ -0,0 +1,24 @@
=== tests/cases/compiler/app.js ===
function require(a) {
>require : (a: any) => any
>a : any
return a;
>a : any
}
const fs = require("fs");
>fs : any
>require("fs") : any
>require : (a: any) => any
>"fs" : "fs"
const text = fs.readFileSync("/a/b/c");
>text : any
>fs.readFileSync("/a/b/c") : any
>fs.readFileSync : any
>fs : any
>readFileSync : any
>"/a/b/c" : "/a/b/c"

View file

@ -0,0 +1,17 @@
// @module: commonjs
// @allowJs: true
// @outDir: ./out/
// @filename: node.d.ts
declare function require(moduleName: string): any;
declare module "fs" {
export function readFileSync(s: string): string;
}
// @filename: app.js
/// <reference path="node.d.ts"/>
const fs = require("fs");
const text = fs.readFileSync("/a/b/c");

View file

@ -0,0 +1,11 @@
// @module: commonjs
// @allowJs: true
// @outDir: ./out/
// @filename: app.js
function require(a) {
return a;
}
const fs = require("fs");
const text = fs.readFileSync("/a/b/c");

View file

@ -128,7 +128,7 @@ function dir(dirPath: string, spec?: string, options?: any) {
// fs.rmdirSync won't delete directories with files in it
function deleteFolderRecursive(dirPath: string) {
if (fs.existsSync(dirPath)) {
fs.readdirSync(dirPath).forEach((file, index) => {
fs.readdirSync(dirPath).forEach((file) => {
const curPath = path.join(path, file);
if (fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
@ -141,7 +141,7 @@ function deleteFolderRecursive(dirPath: string) {
}
};
function writeFile(path: string, data: any, opts: { recursive: boolean }) {
function writeFile(path: string, data: any) {
ensureDirectoriesExist(getDirectoryPath(path));
fs.writeFileSync(path, data);
}
@ -208,7 +208,7 @@ enum RequestType {
Unknown
}
function getRequestOperation(req: http.ServerRequest, filename: string) {
function getRequestOperation(req: http.ServerRequest) {
if (req.method === "GET" && req.url.indexOf("?") === -1) {
if (req.url.indexOf(".") !== -1) return RequestType.GetFile;
else return RequestType.GetDir;
@ -258,7 +258,7 @@ function handleRequestOperation(req: http.ServerRequest, res: http.ServerRespons
break;
case RequestType.WriteFile:
processPost(req, res, (data) => {
writeFile(reqPath, data, { recursive: true });
writeFile(reqPath, data);
});
send(ResponseCode.Success, res, undefined);
break;
@ -306,7 +306,7 @@ http.createServer((req: http.ServerRequest, res: http.ServerResponse) => {
log(`${req.method} ${req.url}`);
const uri = url.parse(req.url).pathname;
const reqPath = path.join(process.cwd(), uri);
const operation = getRequestOperation(req, reqPath);
const operation = getRequestOperation(req);
handleRequestOperation(req, res, operation, reqPath);
}).listen(port);