Flow API 服务器有语法错误

Flow API server with syntax errors

所以我得到了我所理解的 React 的 Flow 服务器和客户端应用程序。

我对 Flow 没有太多经验,但是当我 运行 npm run flow 时,我收到以下错误:

Launching Flow server for /Users/danale/Projects/engage-application.framework
Spawned flow server (pid=82774)
Logs will go to /private/tmp/flow/zSUserszSdanalezSProjectszSengage-application.framework.log
Error: lib/utils/call-api/index.js.flow:86
 86:   url: string = '',
                   ^ Unexpected token =

Error: src/utils/call-api/index.js:86
 86:   url: string = '',
                   ^ Unexpected token =

它引用了这两个文件:

// @flow
import 'whatwg-fetch';
import { RequestInit } from 'whatwg-fetch';
import { merge } from 'lodash/fp';
import { camelCase } from 'lodash';
import urlLib from 'url';

export const DEFAULT_URL = 'http://localhost';

const normalizeCasing = object => {
  if (!object || typeof object !== 'object') {
    return object;
  }
  if (Array.isArray(object)) {
    return object.map(normalizeCasing);
  }

  return Object.keys(object).reduce((acc, key) => {
    return {
      ...acc,
      [camelCase(key)]: normalizeCasing(object[key]),
    };
  }, {});
};

export const defaultFetchHeaders: { [key: string]: any } = {
  compress: false,
  credentials: 'same-origin',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
};

const cleanBody = entity =>
  Object.keys(entity).reduce((acc, key: string) => {
    const value = entity[key];
    if (value == null || (typeof value === 'string' && !value.trim().length)) {
      return acc;
    }
    if (typeof value === 'object') {
      if (!Object.keys(value).length) {
        return acc;
      }
      return {
        ...acc,
        [key]: cleanBody(value),
      };
    }
    return {
      ...acc,
      [key]: value,
    };
  }, {});

export const isServerError = (status: number) => {
  if (status >= 500 && status < 600) {
    return true;
  }
  return false;
};

type CallApiInit = RequestInit & {
  params?: { [key: string]: string | number },
};

type CallApiOptions = {
  normalize: boolean,
};

const isAbsolutePath = (url: string) => {
  return /https?:\/\//.test(url);
};

export const resolveUrl = (baseUrl: string, url?: string = '') => {
  if (!url) {
    return baseUrl;
  }
  if (baseUrl && isAbsolutePath(baseUrl) && !isAbsolutePath(url)) {
    return urlLib.resolve(baseUrl, url);
  }
  return url;
};

export const callApi = (
  url: string = '',
  options?: CallApiInit = {},
  { normalize = true }?: CallApiOptions = { normalize: true }
) => {
  const apiUrl = resolveUrl(DEFAULT_URL, url);
  const { params, ...restOptions } = options;
  const urlObj = urlLib.parse(apiUrl);
  urlObj.query = urlObj.query || params || '';
  const urlString = urlLib.format(urlObj);
  const fetchOptions = merge(defaultFetchHeaders)(restOptions);
  return fetch(urlString, cleanBody(fetchOptions)).then(resp => {
    if (resp.status !== 204) {
      return resp.text().then(text => {
        try {
          return { resp, json: JSON.parse(text) };
        } catch (e) {
          return { resp, json: { message: text } };
        }
      }).then(obj => {
        const results = {
          ...obj,
          json: normalize ? normalizeCasing(obj.json) : obj.json,
        };
        return isServerError(results.resp.status) ? Promise.reject(results) : results;
      });
    }
    return { json: null, resp };
  });
};

export const callApiFactory = (
  baseUrl: string = '',
  baseOptions?: CallApiInit = {}
) => (url: string = '', options?: CallApiInit = {}, ...rest) => {
  return callApi(
    resolveUrl(baseUrl, url),
    merge(baseOptions)(options),
    ...rest
  );
};

export default callApiFactory;

// @flow
import 'whatwg-fetch';
import { RequestInit } from 'whatwg-fetch';
import { merge } from 'lodash/fp';
import { camelCase } from 'lodash';
import urlLib from 'url';

export const DEFAULT_URL = 'http://localhost';

const normalizeCasing = object => {
  if (!object || typeof object !== 'object') {
    return object;
  }
  if (Array.isArray(object)) {
    return object.map(normalizeCasing);
  }

  return Object.keys(object).reduce((acc, key) => {
    return {
      ...acc,
      [camelCase(key)]: normalizeCasing(object[key]),
    };
  }, {});
};

export const defaultFetchHeaders: { [key: string]: any } = {
  compress: false,
  credentials: 'same-origin',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
};

const cleanBody = entity =>
  Object.keys(entity).reduce((acc, key: string) => {
    const value = entity[key];
    if (value == null || (typeof value === 'string' && !value.trim().length)) {
      return acc;
    }
    if (typeof value === 'object') {
      if (!Object.keys(value).length) {
        return acc;
      }
      return {
        ...acc,
        [key]: cleanBody(value),
      };
    }
    return {
      ...acc,
      [key]: value,
    };
  }, {});

export const isServerError = (status: number) => {
  if (status >= 500 && status < 600) {
    return true;
  }
  return false;
};

type CallApiInit = RequestInit & {
  params?: { [key: string]: string | number },
};

type CallApiOptions = {
  normalize: boolean,
};

const isAbsolutePath = (url: string) => {
  return /https?:\/\//.test(url);
};

export const resolveUrl = (baseUrl: string, url?: string = '') => {
  if (!url) {
    return baseUrl;
  }
  if (baseUrl && isAbsolutePath(baseUrl) && !isAbsolutePath(url)) {
    return urlLib.resolve(baseUrl, url);
  }
  return url;
};

export const callApi = (
  url: string = '',
  options?: CallApiInit = {},
  { normalize = true }?: CallApiOptions = { normalize: true }
) => {
  const apiUrl = resolveUrl(DEFAULT_URL, url);
  const { params, ...restOptions } = options;
  const urlObj = urlLib.parse(apiUrl);
  urlObj.query = urlObj.query || params || '';
  const urlString = urlLib.format(urlObj);
  const fetchOptions = merge(defaultFetchHeaders)(restOptions);
  return fetch(urlString, cleanBody(fetchOptions)).then(resp => {
    if (resp.status !== 204) {
      return resp.text().then(text => {
        try {
          return { resp, json: JSON.parse(text) };
        } catch (e) {
          return { resp, json: { message: text } };
        }
      }).then(obj => {
        const results = {
          ...obj,
          json: normalize ? normalizeCasing(obj.json) : obj.json,
        };
        return isServerError(results.resp.status) ? Promise.reject(results) : results;
      });
    }
    return { json: null, resp };
  });
};

export const callApiFactory = (
  baseUrl: string = '',
  baseOptions?: CallApiInit = {}
) => (url: string = '', options?: CallApiInit = {}, ...rest) => {
  return callApi(
    resolveUrl(baseUrl, url),
    merge(baseOptions)(options),
    ...rest
  );
};

export default callApiFactory;

这是否意味着 Flow 不支持这个:url: string = '',?我是 Flow 的新手,通常不会在大多数项目中使用它。我对 TypeScript 中的类型注释有一些了解,但我不认为它与这里发生的事情有任何关系。

这是 package.json 文件:

{
  "name": "@nfib/engage-framework",
  "version": "1.2.13",
  "files": [
    "lib"
  ],
  "main": "lib/index.js",
  "scripts": {
    "check": "npm run lint && npm run test",
    "test": "jest",
    "lint": "eslint src/",
    "prebuild": "rimraf lib",
    "flow": "flow",
    "build": "npm run build:lib && npm run build:flow",
    "build:lib": "babel src/ -d lib/ --ignore '**/*.spec.js,__mocks__,__snapshots__'",
    "build:flow": "flow-copy-source src/ lib/ -v --ignore '**/*.spec.js,__mocks__,__snapshots__'"
  },
  "keywords": [],
  "author": "NFIB ITPE",
  "license": "UNLICENSED",
  "description": "Common application framework for the engage project",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-eslint": "^7.2.3",
    "babel-jest": "^20.0.3",
    "babel-plugin-lodash": "^3.2.11",
    "babel-preset-env": "^1.3.3",
    "babel-preset-flow": "^6.23.0",
    "babel-preset-stage-2": "^6.24.1",
    "eslint": "^4.4.1",
    "eslint-plugin-flow": "^2.29.1",
    "eslint-plugin-react": "^7.2.0",
    "flow-bin": "^0.52.0",
    "flow-copy-source": "^1.2.0",
    "jest-cli": "^20.0.4",
    "jest-fetch-mock": "^1.2.1",
    "rimraf": "^2.6.1"
  },
  "dependencies": {
    "body-parser": "^1.17.2",
    "camelcase-keys": "^4.1.0",
    "lodash.merge": "^4.6.0",
    "url": "^0.11.0",
    "http-proxy-middleware": "^0.17.4",
    "express": "^4.15.4",
    "express-redirect": "^1.2.2",
    "express-session": "^1.15.5",
    "cheerio": "^0.22.0",
    "cors": "^2.8.4",
    "helmet": "^3.8.1",
    "morgan": "^1.8.2",
    "lodash": "^4.17.4",
    "whatwg-fetch": "^2.0.3"
  }
}

Does this mean Flow does not support this: url: string = '',?

Flow支持这个,没问题

问题出在这一行:

{ normalize = true }?: CallApiOptions = { normalize: true }

flow(我认为人类也是)几乎认不出这里是什么,结果是这个解析错误。

如果您减少此行中的逻辑,例如:

extraOpts?: CallApiOptions = { normalize: true }

它使流量快乐,check