...
 
Commits (2)
/** /**
* @flow * @flow strict
*/ */
opaque type Token = number; opaque type Token = number;
...@@ -13,7 +13,7 @@ let pendingClaim: ?Token = null; ...@@ -13,7 +13,7 @@ let pendingClaim: ?Token = null;
* listener to be notified. * listener to be notified.
*/ */
export function getRefetchToken(): Token { export function getRefetchToken(): Token {
if (pendingClaim) { if (pendingClaim != null) {
throw new Error('Only one refetch token may be outstanding at any time'); throw new Error('Only one refetch token may be outstanding at any time');
} }
pendingClaim = tokenCounter++; pendingClaim = tokenCounter++;
......
/**
* @flow
*/
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import * as React from 'react';
import Footer from './Footer'; import Footer from './Footer';
import Nav from './Nav'; import Nav from './Nav';
import Progress from './Progress'; import Progress from './Progress';
...@@ -11,12 +15,13 @@ if (inBrowser) { ...@@ -11,12 +15,13 @@ if (inBrowser) {
require('highlight.js/styles/default.css'); require('highlight.js/styles/default.css');
} }
export default class App extends React.Component { type Props = {
static propTypes = { children: React.Node,
router: PropTypes.object, router: $FlowFixMe,
showProgress: PropTypes.bool, showProgress?: boolean,
}; };
export default class App extends React.Component<Props> {
static childContextTypes = { static childContextTypes = {
router: PropTypes.object, router: PropTypes.object,
}; };
...@@ -35,11 +40,14 @@ export default class App extends React.Component { ...@@ -35,11 +40,14 @@ export default class App extends React.Component {
* relative one that should be handled by the router, and if so, we hand it * relative one that should be handled by the router, and if so, we hand it
* off to the router; otherwise, the browser handles it. * off to the router; otherwise, the browser handles it.
*/ */
_handleClick = event => { _handleClick = (event: SyntheticMouseEvent<HTMLDivElement>) => {
let href = null; let href = null;
let element = event.target; let element = event.target;
if (!(element instanceof HTMLElement)) {
return;
}
while (element) { while (element) {
if (element.tagName === 'A') { if (element instanceof HTMLAnchorElement) {
href = element.getAttribute('href'); href = element.getAttribute('href');
} }
if (element.className === 'prerendered') { if (element.className === 'prerendered') {
...@@ -62,14 +70,17 @@ export default class App extends React.Component { ...@@ -62,14 +70,17 @@ export default class App extends React.Component {
// browser. // browser.
return; return;
} }
element = element.parentNode; element = element.parentElement;
} }
}; };
_handleMouseOver = event => { _handleMouseOver = (event: SyntheticMouseEvent<HTMLDivElement>) => {
let element = event.target; let element = event.target;
if (!(element instanceof HTMLElement)) {
return;
}
while (element) { while (element) {
if (element.tagName === 'A') { if (element instanceof HTMLAnchorElement) {
const href = element.getAttribute('href'); const href = element.getAttribute('href');
if (!href || !href.match(/^\//)) { if (!href || !href.match(/^\//)) {
// Not a relatve URL; let the browser handle it. // Not a relatve URL; let the browser handle it.
......
...@@ -13,7 +13,7 @@ const StatusCodesToMessages = { ...@@ -13,7 +13,7 @@ const StatusCodesToMessages = {
}; };
type Props = { type Props = {
children: $ReadOnlyArray<ChildrenArray<ReactNode>>, children?: $ReadOnlyArray<ChildrenArray<ReactNode>>,
code: 404 | 500, code: 404 | 500,
}; };
......
/** /**
* @flow * @flow strict
*/ */
import React from 'react'; import React from 'react';
......
/** /**
* @flow * @flow strict
*/ */
import React from 'react'; import React from 'react';
......
/** /**
* @flow * @flow strict
*/ */
import React from 'react'; import React from 'react';
......
/** /**
* @flow * @flow strict
*/ */
export type TimeInfo = { export type TimeInfo = {
......
/** /**
* @flow strict-local * @flow strict
*/ */
import * as React from 'react'; import * as React from 'react';
......
/** /**
* @flow * @flow strict
*/ */
export default function extractTypeAndId(typeAndId: string): [string, string] { export default function extractTypeAndId(typeAndId: string): [string, string] {
......
/** /**
* @flow * @flow strict
*/ */
export default function formatTitle(title: ?string): string { export default function formatTitle(title: ?string): string {
// flowlint-next-line sketchy-null:off
return [...(title ? [title] : []), 'wincent.com'].join(' · '); return [...(title ? [title] : []), 'wincent.com'].join(' · ');
} }
/** /**
* @flow * @flow strict
*/ */
import stableStringify from './stableStringify'; import stableStringify from './stableStringify';
......
/**
* @flow strict-local
*/
import Router from 'universal-router'; import Router from 'universal-router';
import routeConfig from './routeConfig'; import routeConfig from './routeConfig';
...@@ -25,7 +29,7 @@ function getRouteMap() { ...@@ -25,7 +29,7 @@ function getRouteMap() {
/** /**
* Matches paths only. * Matches paths only.
*/ */
export default function matchRoute(path) { export default function matchRoute(path: string) {
for (let [regexp, route] of getRouteMap()) { for (let [regexp, route] of getRouteMap()) {
if (regexp.test(path)) { if (regexp.test(path)) {
return route; return route;
......
/**
* @flow
*/
import React from 'react'; import React from 'react';
import HTTPError from '../client/components/HTTPError'; import HTTPError from '../client/components/HTTPError';
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
...@@ -27,7 +31,7 @@ export default buildRoute( ...@@ -27,7 +31,7 @@ export default buildRoute(
if (node) { if (node) {
return <Page data={node} />; return <Page data={node} />;
} else { } else {
throw makeNotFoundError( throw makeNotFound(
`No page found with id: ${id}`, `No page found with id: ${id}`,
<p> <p>
Try inspecting <Link to="/tags/pages">the pages index</Link> and{' '} Try inspecting <Link to="/tags/pages">the pages index</Link> and{' '}
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @noflow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
import Link from '../../client/components/Link'; import Link from '../../client/components/Link';
import Snippet from '../../client/components/Snippet'; import Snippet from '../../client/components/Snippet';
import makeNotFound from '../NotFoundError'; import {makeNotFound} from '../NotFoundError';
import buildRoute from '../buildRoute'; import buildRoute from '../buildRoute';
export default buildRoute( export default buildRoute(
......
/**
* @flow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
...@@ -34,15 +38,11 @@ export default buildRoute( ...@@ -34,15 +38,11 @@ export default buildRoute(
`, `,
{ {
variables: ({format, id}) => { variables: ({format, id}) => {
format = FORMAT_TO_MARKUP_TYPE.get(format.toLowerCase()); const markupType = FORMAT_TO_MARKUP_TYPE.get(format.toLowerCase());
if (format !== 'TXT') { return {
return {format, id}; format: markupType !== 'TXT' ? markupType : null,
} else { id,
return { };
format: null,
id,
};
}
}, },
render: ({node}, {format, id}) => { render: ({node}, {format, id}) => {
if (node && node.source !== null) { if (node && node.source !== null) {
......
/**
* @flow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @flow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/**
* @flow
*/
import React from 'react'; import React from 'react';
import {graphql} from 'react-relay'; import {graphql} from 'react-relay';
......
/** /**
* @flow * @flow strict
*/ */
export default function stripTrailingSlash(path: string): string { export default function stripTrailingSlash(path: string): string {
......
/** /**
* @flow * @flow strict
*/ */
import inBrowser from './inBrowser'; import inBrowser from './inBrowser';
......
/**
* @flow
*/
import inBrowser from './inBrowser'; import inBrowser from './inBrowser';
if (!inBrowser) { if (!inBrowser) {
......
/**
* @noflow
*/
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
......
/** /**
* @flow * @flow strict
*/ */
import Memcached from 'memcached'; import Memcached from 'memcached';
...@@ -30,8 +30,8 @@ function getCacheBreaker(): string { ...@@ -30,8 +30,8 @@ function getCacheBreaker(): string {
// TODO: degrade more gracefully if memcached goes down (currently we just wait // TODO: degrade more gracefully if memcached goes down (currently we just wait
// forever(?)) // forever(?))
const Cache = { const Cache = {
set(key: string, value: mixed): Promise<mixed> { set(inKey: string, value: mixed): Promise<mixed> {
key = key + getCacheBreaker(); const key = inKey + getCacheBreaker();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
memcached.set(key, value, 0, error => { memcached.set(key, value, 0, error => {
...@@ -44,8 +44,8 @@ const Cache = { ...@@ -44,8 +44,8 @@ const Cache = {
}); });
}, },
get(key: string, missCallback: () => Promise<mixed>): Promise<mixed> { get(inKey: string, missCallback: () => Promise<mixed>): Promise<mixed> {
key = key + getCacheBreaker(); const key = inKey + getCacheBreaker();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
memcached.get(key, (error, data) => { memcached.get(key, (error, data) => {
......
/** /**
* @flow * @flow strict
*/ */
export const Extensions = { export const Extensions = {
......
/** /**
* @flow * @flow strict
*/ */
import getIndexNameForContentType from './getIndexNameForContentType'; import getIndexNameForContentType from './getIndexNameForContentType';
......
/** /**
* @flow * @flow strict
*/ */
export default function delay(ms: number): Promise<void> { export default function delay(ms: number): Promise<void> {
......
/** /**
* @flow * @flow strict
*/ */
// Prepared regular expressions to eek out a couple % more perf; see: // Prepared regular expressions to eek out a couple % more perf; see:
......
/** /**
* @flow * @flow strict
*/ */
type RouteConfig = Array<{ type RouteConfig = $ReadOnlyArray<{
path: string, path: string,
}>; }>;
...@@ -10,7 +10,7 @@ type RouteConfig = Array<{ ...@@ -10,7 +10,7 @@ type RouteConfig = Array<{
* Parses a RouteConfig object and returns a list of Express-style path * Parses a RouteConfig object and returns a list of Express-style path
* patterns ("/", "/blog", "/blog/*" etc). * patterns ("/", "/blog", "/blog/*" etc).
*/ */
export default function gatherPaths(config: RouteConfig): Array<string> { export default function gatherPaths(config: RouteConfig): $ReadOnlyArray<string> {
const paths = []; const paths = [];
config.forEach(route => { config.forEach(route => {
if (route.path === '*') { if (route.path === '*') {
......
/** /**
* @flow * @flow strict
*/ */
import hashString from './hashString'; import hashString from './hashString';
......
/** /**
* @flow * @flow strict
*/ */
import getURLForContentPath from './getURLForContentPath'; import getURLForContentPath from './getURLForContentPath';
......
/** /**
* @flow * @flow strict
*/ */
import getURLForContentPath from './getURLForContentPath'; import getURLForContentPath from './getURLForContentPath';
......
/** /**
* @flow * @flow strict
*/ */
/** /**
......
/** /**
* @flow * @flow strict
*/ */
export default function getURLForContentPath( export default function getURLForContentPath(
......
/** /**
* @flow * @flow strict-local
*/ */
import path from 'path'; import path from 'path';
......
/** /**
* @flow * @flow strict
*/ */
/** /**
......
'use strict'; // eslint-disable-line 'use strict'; // eslint-disable-line
/**
* @noflow
*/
import '../common/unhandledRejection'; import '../common/unhandledRejection';
import '../server/configureNpm'; import '../server/configureNpm';
......
/** /**
* @flow * @flow strict
*/ */
import {spawn} from 'child_process'; import {spawn} from 'child_process';
......
/** /**
* @flow * @flow strict
*/ */
export default function raw(string: string): {|__safe: string|} { export default function raw(string: string): {|__safe: string|} {
......
/** /**
* @flow * @flow strict
*/ */
import pipe from './pipe'; import pipe from './pipe';
......
/**
* @noflow
*/
import { import {
GraphQLNonNull, GraphQLNonNull,
GraphQLObjectType, GraphQLObjectType,
......
/** /**
* @flow * @flow strict
*/ */
/** /**
......
...@@ -101,7 +101,7 @@ export default function template( ...@@ -101,7 +101,7 @@ export default function template(
} else { } else {
// User passed 0, false, NaN, or something truthy // User passed 0, false, NaN, or something truthy
// that didn't get caught by duck-typing checks; coerce to string. // that didn't get caught by duck-typing checks; coerce to string.
const string = '' + (item: any); const string = String('');
if (!this.push(string)) { if (!this.push(string)) {
return; return;
} }
......