diff --git a/src/components/ASTOutline/ASTOutline.css b/src/components/ASTOutline/ASTOutline.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/ASTOutline/ASTOutline.tsx b/src/components/ASTOutline/ASTOutline.tsx
new file mode 100644
index 0000000..07524fd
--- /dev/null
+++ b/src/components/ASTOutline/ASTOutline.tsx
@@ -0,0 +1,64 @@
+import React from "react";
+import { connect } from "react-redux";
+import * as ts from "typescript";
+
+import { AppState } from "../../store";
+import { forEachChild, syntaxKindNameMapping, ObjectHash } from "../../utils";
+
+interface ASTOutlineProps {
+ node?: ts.Node;
+ sourceFile?: ts.SourceFile;
+}
+
+function ASTOutline(props: ASTOutlineProps) {
+ const { node, sourceFile } = props;
+ if (node === undefined || sourceFile === undefined) {
+ return null;
+ }
+
+ const output = (
+ <>
+
{syntaxKindNameMapping[node.kind]}
+
+ {forEachChild(node).map(childNode => (
+
+ ))}
+
+ >
+ );
+
+ if (ts.isSourceFile(node)) {
+ return ;
+ } else {
+ return output;
+ }
+}
+
+type ASTOutlineStateProps = ASTOutlineProps;
+
+const mapStateToProps = (state: AppState) => ({
+ node: state.sourceFiles.currentSourceFile,
+ sourceFile: state.sourceFiles.currentSourceFile
+});
+// currentSourceFile from ownProps should take preceedence
+const mergeProps = (
+ stateProps: ASTOutlineStateProps,
+ _dispatchProps: never,
+ ownProps: ASTOutlineProps
+) => {
+ return {
+ ...stateProps,
+ ...ownProps
+ };
+};
+
+export { ASTOutline as ASTOutlineUnconnected, ASTOutlineProps };
+const ASTOutlineConnected = connect(
+ mapStateToProps,
+ null,
+ mergeProps
+)(ASTOutline);
+export default ASTOutlineConnected;
diff --git a/src/components/ASTOutline/index.tsx b/src/components/ASTOutline/index.tsx
new file mode 100644
index 0000000..807a9a5
--- /dev/null
+++ b/src/components/ASTOutline/index.tsx
@@ -0,0 +1,7 @@
+import ASTOutline, {
+ ASTOutlineUnconnected,
+ ASTOutlineProps
+} from "./ASTOutline";
+
+export { ASTOutlineUnconnected, ASTOutlineProps };
+export default ASTOutline;