Skip to content

Commit

Permalink
Add Flow typing
Browse files Browse the repository at this point in the history
 - Includes workaround for `config-chain` including intentionally broken test files in its repo: facebook/flow#869
 - Includes Hack for externals with Parcel: parcel-bundler/parcel#144
  • Loading branch information
Daniel15 committed Sep 5, 2018
1 parent 4f7a323 commit 1d226a3
Show file tree
Hide file tree
Showing 15 changed files with 282 additions and 20 deletions.
15 changes: 15 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[ignore]
# https://github.com/facebook/flow/issues/869
.*/node_modules/config-chain/test/broken.json

[include]

[declarations]

[libs]

[lints]

[options]

[strict]
12 changes: 12 additions & 0 deletions flow-typed/source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
declare module "source-map" {
declare class SourceMapConsumer {
sources: $ReadOnlyArray<string>,

destroy(): void;
sourceContentFor(url: string): ?string;
}

declare module.exports: {
SourceMapConsumer: (file: string | ArrayBuffer) => Promise<SourceMapConsumer>,
}
}
20 changes: 17 additions & 3 deletions js/buildTree.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
export default function buildTree(files) {
const tree = {
// @flow

export type TreeNode = $ReadOnly<{|
name: string,
path: string,
type: 'dir' | 'file',
children: Map<string, TreeNode>,
|}>;

export default function buildTree(files: Array<string>): TreeNode {
const tree: TreeNode = {
name: '/',
path: '',
type: 'dir',
Expand All @@ -16,6 +25,7 @@ export default function buildTree(files) {
if (!next) {
next = {
name: piece,
path: `${curr.path}/${piece}`,
type: 'dir',
children: new Map(),
};
Expand All @@ -35,7 +45,11 @@ export default function buildTree(files) {
let root = tree;
while (root && root.children.size === 1) {
const firstKey = root.children.keys().next().value;
root = root.children.get(firstKey);
const node = firstKey && root.children.get(firstKey);
if (!node) {
break;
}
root = node;
}

return root;
Expand Down
16 changes: 14 additions & 2 deletions js/components/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
// @flow

import React from 'react';

import classNames from './App.css';
import Files from './Files';

import getFilesFromSourceMap from '../getFilesFromSourceMap';

export default class App extends React.Component {
type Props = {||};
type State = {|
error: ?Error,
files: ?Map<string, ?string>,
id: number,
loading: boolean,
|};

export default class App extends React.Component<Props, State> {
state = {
error: null,
files: null,
Expand Down Expand Up @@ -41,7 +53,7 @@ export default class App extends React.Component {
);
}

_onSelectFile = (evt) => {
_onSelectFile = (evt: {target: {files: Array<File>}}) => {
this.setState(state => ({id: state.id + 1, loading: true}));
const file = evt.target.files[0];
getFilesFromSourceMap(file).then(
Expand Down
14 changes: 12 additions & 2 deletions js/components/Code.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// @flow

// TODO: Flow type this
import Prism from 'prismjs';
import React from 'react';

import classNames from './Files.css';

function runPrism(code) {
function runPrism(code: string): {|__html: string|} {
return {__html: Prism.highlight(code, Prism.languages.javascript)};
}

export default class Code extends React.PureComponent {
type Props = {|
code: ?string,
|};

export default class Code extends React.PureComponent<Props> {
render() {
const code = this.props.code || '// File is empty';
return (
Expand Down
38 changes: 34 additions & 4 deletions js/components/FileTree.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
// @flow

import React from 'react';
import nullthrows from 'nullthrows';

import type {TreeNode} from '../buildTree';
import classNames from './Files.css';

export default class FileTree extends React.Component {
type Props = {|
selectedDir: $ReadOnlyArray<string>,
selectedFile: ?string,
tree: TreeNode,

onSelectDir: (path: $ReadOnlyArray<string>) => void,
onSelectFile: (path: string) => void,
|};

export default class FileTree extends React.PureComponent<Props> {
render() {
const selectedPath = this.props.selectedDir;

let selectedNode = this.props.tree;
selectedPath.forEach(piece => {
selectedNode = selectedNode.children.get(piece);
selectedNode = nullthrows(selectedNode.children.get(piece));
});

const nodes = [];
Expand Down Expand Up @@ -50,7 +65,14 @@ export default class FileTree extends React.Component {
}
}

class DirNode extends React.Component {
type DirNodeProps = {|
name: string,
path: $ReadOnlyArray<string>,

onSelect: (path: $ReadOnlyArray<string>) => void,
|}

class DirNode extends React.Component<DirNodeProps> {
render() {
return (
<li><a href="#" onClick={this._onSelect}>{this.props.name}/</a></li>
Expand All @@ -63,7 +85,15 @@ class DirNode extends React.Component {
}
}

class FileNode extends React.Component {
type FileNodeProps = {|
name: string,
node: TreeNode,
selectedFile: ?string,

onSelect: (path: string) => void,
|};

class FileNode extends React.Component<FileNodeProps> {
render() {
let name = this.props.name;
if (this.props.selectedFile === this.props.node.path) {
Expand Down
19 changes: 16 additions & 3 deletions js/components/Files.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
// @flow

import React from 'react';

import classNames from './Files.css';
import Code from './Code';
import FileTree from './FileTree';

import buildTree from '../buildTree';

export default class Files extends React.Component {
type Props = {|
files: Map<string, ?string>,
|};

type State = {|
selectedFile: ?string,
selectedDir: $ReadOnlyArray<string>,
|};

export default class Files extends React.Component<Props, State> {
state = {
selectedDir: [],
selectedFile: null,
Expand Down Expand Up @@ -38,11 +51,11 @@ export default class Files extends React.Component {
: '/' + this.state.selectedDir.join('/') + '/';
}

_onSelectDir = (path) => {
_onSelectDir = (path: $ReadOnlyArray<string>) => {
this.setState({selectedDir: path});
}

_onSelectFile = (path) => {
_onSelectFile = (path: string) => {
this.setState({selectedFile: path});
}
}
2 changes: 2 additions & 0 deletions js/externals/prism.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Loaded from CDN
module.exports = Prism;
2 changes: 2 additions & 0 deletions js/externals/react-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Loaded from CDN
module.exports = ReactDOM;
2 changes: 2 additions & 0 deletions js/externals/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Loaded from CDN
module.exports = React;
2 changes: 2 additions & 0 deletions js/externals/source-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Loaded from CDN
module.exports = sourceMap;
8 changes: 7 additions & 1 deletion js/getFilesFromSourceMap.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
export default function getFilesFromSourceMap(file) {
// @flow

import sourceMap from 'source-map';

export default function getFilesFromSourceMap(
file: File
): Promise<Map<string, ?string>> {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = () => {
Expand Down
9 changes: 8 additions & 1 deletion js/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
// @flow

import React from 'react';
import ReactDOM from 'react-dom';
import sourceMap from 'source-map';
import nullthrows from 'nullthrows';

import App from './components/App';

sourceMap.SourceMapConsumer.initialize({
'lib/mappings.wasm': 'https://unpkg.com/source-map@0.7.3/lib/mappings.wasm',
});
ReactDOM.render(<App />, document.getElementById('app'));
ReactDOM.render(<App />, nullthrows(document.getElementById('app')));
12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@
"build": "parcel build ./index.html",
"watch": "parcel ./index.html"
},
"alias": {
"prismjs": "./js/externals/prism",
"react": "./js/externals/react",
"react-dom": "./js/externals/react-dom",
"source-map": "./js/externals/source-map"
},
"devDependencies": {
"autoprefixer": "^9.1.3",
"babel-preset-flow": "^6.23.0",
"babel-preset-react-app": "^3.1.2",
"flow-bin": "^0.80.0",
"nullthrows": "^1.0.2",
"parcel-bundler": "^1.9.7",
"postcss-modules": "^1.3.2",
"prismjs": "^1.15.0",
"react": "^16.0.0",
"react-dom": "^16.4.2",
"sanitize.css": "^7.0.1",
"source-map": "^0.7.3"
}
Expand Down
Loading

0 comments on commit 1d226a3

Please sign in to comment.