Skip to content

Instantly share code, notes, and snippets.

@mwheeler
Created January 7, 2014 03:54
Show Gist options
  • Save mwheeler/8294415 to your computer and use it in GitHub Desktop.
Save mwheeler/8294415 to your computer and use it in GitHub Desktop.
Example of parsing require()'s in typescript 0.9.5
var fs = require('fs');
var path = require('path');
// dodgy arg parsing
var input = process.argv[2];
// import typescript
var TypeScript = (function(){
var sandbox = {
__filename: __filename,
__dirname: __dirname,
global: global,
process: process,
require: require,
console: console,
exports: null,
setInterval: setInterval,
setTimeout: setTimeout
};
var vm = require('vm');
var typescript_filename = require.resolve('typescript');
var source = fs.readFileSync(typescript_filename, 'utf8');
var script = vm.createScript(source.concat('\n\nexports = TypeScript;'), typescript_filename);
script.runInNewContext(sandbox);
return sandbox.exports;
})();
// Compiler settings
var compiler_settings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings({
noImplicitAny: true,
useCaseSensitiveFileResolution: true,
moduleGenTarget: TypeScript.ModuleGenTarget.Synchronous,
codeGenTarget: TypeScript.LanguageVersion.EcmaScript5
});
// Host path helper
var host = {
getScriptSnapshot: function(filename)
{
var contents = fs.readFileSync(filename).toString();
return TypeScript.ScriptSnapshot.fromString(contents);
},
resolveRelativePath: function(pathname, dirname)
{
return host.resolvePath(pathname, dirname);
//return path.relative(dirname, pathname);
},
writeFile: function(fileName, contents, writeByteOrderMark)
{
fs.writeFileSync(fileName, contents);
},
getParentDirectory: function(filepath)
{
return path.dirname(filepath);
},
fileExists: function(path)
{
return fs.existsSync(path);
},
directoryExists: function(path)
{
return fs.existsSync(path);
},
resolvePath: function(filepath, search_paths)
{
var search = [];
if(filepath[0] !== '/' && filepath[0] !== '\\')
{
search = search.concat(search_paths).map(function(x)
{
if(x[0] !== '/' && x[0] !== '\\')
{
return path.join(process.cwd(), x);
}
return x;
});
// TODO: 'built in' & task-driven search paths
}
var exts = ['', '.ts', '.js'];
for(var ext in exts)
{
var args = search.concat(filepath + exts[ext]);
var result = path.resolve.apply(path, args);
if(result && fs.existsSync(result)) return result;
}
return filepath;
}
};
// TypeScript compiler
var compiler = new TypeScript.TypeScriptCompiler(new TypeScript.NullLogger(), compiler_settings);
// Base input path
if(input[0] != '/') input = path.relative(process.cwd(), input);
// Add file to compiler
compiler.addFile(input, host.getScriptSnapshot(input), TypeScript.ByteOrderMark.Utf8, 0, false, []);
// Get top level decls
var decl = compiler.topLevelDeclaration(input);
// Parse ast
function parse_ast(ast)
{
var result = {};
switch (ast.kind()/*nodeType()*/)
{
case TypeScript.SyntaxKind.List:
for(var i = 0; i < ast.childCount(); ++i)
{
var child = parse_ast(ast.childAt(i));
if(!child) continue;
result[child.name] = child;
}
return result;
case TypeScript.SyntaxKind.Script:
ast = ast.topLevelMod;
case TypeScript.SyntaxKind.ModuleDeclaration:
var module_name = path.basename(ast.name.text());
result.name = module_name;
case TypeScript.SyntaxKind.SourceUnit:
result.type = 'module';
result.value = parse_ast(ast.moduleElements);
return result;
case TypeScript.SyntaxKind.ExternalModuleReference:
var id = ast.stringLiteral.text().replace(/^'|^"|'$|"$/gm, '');
result.type = 'require';
result.value = id;
return result;
// import LocalName = require("ModuleName")
case TypeScript.SyntaxKind.ImportDeclaration:
result.type = 'import';
result.name = ast.identifier.text();
result.value = parse_ast(ast.moduleReference);
return result;
}
return undefined;
}
console.log(parse_ast(decl.ast()));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment