housekeeping: bundle size reductions (#4713)
* set new bundlesize goal * preserve `GeneratorFunction` instead of all function names * use js-yaml fork that doesn't require esprima * set HTML content directly, instead of using React-Markdown * use remarkable for all Markdown rendering * add babel-plugin-transform-react-remove-prop-types * remove SplitPaneMode plugin * remove react-collapse * remove AST plugin, and yaml-js * trim Markdown HTML string output before rendering * disable obsolete function name preservation * add `getComponent` to propTypes
This commit is contained in:
@@ -9,7 +9,7 @@ export default class AuthorizationPopup extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let { authSelectors, authActions, getComponent, errSelectors, specSelectors, fn: { AST } } = this.props
|
||||
let { authSelectors, authActions, getComponent, errSelectors, specSelectors, fn: { AST = {} } } = this.props
|
||||
let definitions = authSelectors.shownDefinitions()
|
||||
const Auths = getComponent("auths")
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Collapse } from "react-collapse"
|
||||
import { presets } from "react-motion"
|
||||
import ObjectInspector from "react-inspector"
|
||||
import Perf from "react-addons-perf"
|
||||
@@ -25,10 +24,12 @@ export default class Debug extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
let { getState } = this.props
|
||||
let { getState, getComponent } = this.props
|
||||
|
||||
window.props = this.props
|
||||
|
||||
const Collapse = getComponent("Collapse")
|
||||
|
||||
return (
|
||||
<div className="info">
|
||||
<h3><a onClick={this.toggleJsonDump}> {this.plusOrMinus(this.state.jsonDumpOpen)} App </a></h3>
|
||||
@@ -47,6 +48,7 @@ export default class Debug extends React.Component {
|
||||
}
|
||||
|
||||
Debug.propTypes = {
|
||||
getState: PropTypes.func.isRequired
|
||||
getState: PropTypes.func.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { List } from "immutable"
|
||||
import { Collapse } from "react-collapse"
|
||||
|
||||
export default class Errors extends React.Component {
|
||||
|
||||
@@ -9,11 +8,14 @@ export default class Errors extends React.Component {
|
||||
editorActions: PropTypes.object,
|
||||
errSelectors: PropTypes.object.isRequired,
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
getComponent: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
let { editorActions, errSelectors, layoutSelectors, layoutActions } = this.props
|
||||
let { editorActions, errSelectors, layoutSelectors, layoutActions, getComponent } = this.props
|
||||
|
||||
const Collapse = getComponent("Collapse")
|
||||
|
||||
if(editorActions && editorActions.jumpToLine) {
|
||||
var jumpToLine = editorActions.jumpToLine
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Collapse as OriCollapse } from "react-collapse"
|
||||
|
||||
function xclass(...args) {
|
||||
return args.filter(a => !!a).join(" ").trim()
|
||||
@@ -243,11 +242,9 @@ export class Collapse extends React.Component {
|
||||
|
||||
children = isOpened ? children : null
|
||||
return (
|
||||
<OriCollapse isOpened={isOpened}>
|
||||
<NoMargin>
|
||||
{children}
|
||||
</NoMargin>
|
||||
</OriCollapse>
|
||||
<NoMargin>
|
||||
{children}
|
||||
</NoMargin>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
import YAML from "yaml-js"
|
||||
import isArray from "lodash/isArray"
|
||||
import lodashFind from "lodash/find"
|
||||
import { memoize } from "core/utils"
|
||||
|
||||
let cachedCompose = memoize(YAML.compose) // TODO: build a custom cache based on content
|
||||
|
||||
var MAP_TAG = "tag:yaml.org,2002:map"
|
||||
var SEQ_TAG = "tag:yaml.org,2002:seq"
|
||||
|
||||
export function getLineNumberForPath(yaml, path) {
|
||||
|
||||
// Type check
|
||||
if (typeof yaml !== "string") {
|
||||
throw new TypeError("yaml should be a string")
|
||||
}
|
||||
if (!isArray(path)) {
|
||||
throw new TypeError("path should be an array of strings")
|
||||
}
|
||||
|
||||
var i = 0
|
||||
|
||||
let ast = cachedCompose(yaml)
|
||||
|
||||
// simply walks the tree using current path recursively to the point that
|
||||
// path is empty
|
||||
|
||||
return find(ast, path)
|
||||
|
||||
function find(current, path, last) {
|
||||
if(!current) {
|
||||
// something has gone quite wrong
|
||||
// return the last start_mark as a best-effort
|
||||
if(last && last.start_mark)
|
||||
return last.start_mark.line
|
||||
return 0
|
||||
}
|
||||
|
||||
if (path.length && current.tag === MAP_TAG) {
|
||||
for (i = 0; i < current.value.length; i++) {
|
||||
var pair = current.value[i]
|
||||
var key = pair[0]
|
||||
var value = pair[1]
|
||||
|
||||
if (key.value === path[0]) {
|
||||
return find(value, path.slice(1), current)
|
||||
}
|
||||
|
||||
if (key.value === path[0].replace(/\[.*/, "")) {
|
||||
// access the array at the index in the path (example: grab the 2 in "tags[2]")
|
||||
var index = parseInt(path[0].match(/\[(.*)\]/)[1])
|
||||
if(value.value.length === 1 && index !== 0 && !!index) {
|
||||
var nextVal = lodashFind(value.value[0], { value: index.toString() })
|
||||
} else { // eslint-disable-next-line no-redeclare
|
||||
var nextVal = value.value[index]
|
||||
}
|
||||
return find(nextVal, path.slice(1), value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path.length && current.tag === SEQ_TAG) {
|
||||
var item = current.value[path[0]]
|
||||
|
||||
if (item && item.tag) {
|
||||
return find(item, path.slice(1), current.value)
|
||||
}
|
||||
}
|
||||
|
||||
if (current.tag === MAP_TAG && !Array.isArray(last)) {
|
||||
return current.start_mark.line
|
||||
} else {
|
||||
return current.start_mark.line + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a position object with given
|
||||
* @param {string} yaml
|
||||
* YAML or JSON string
|
||||
* @param {array} path
|
||||
* an array of stings that constructs a
|
||||
* JSON Path similar to JSON Pointers(RFC 6901). The difference is, each
|
||||
* component of path is an item of the array instead of being separated with
|
||||
* slash(/) in a string
|
||||
*/
|
||||
export function positionRangeForPath(yaml, path) {
|
||||
|
||||
// Type check
|
||||
if (typeof yaml !== "string") {
|
||||
throw new TypeError("yaml should be a string")
|
||||
}
|
||||
if (!isArray(path)) {
|
||||
throw new TypeError("path should be an array of strings")
|
||||
}
|
||||
|
||||
var invalidRange = {
|
||||
start: {line: -1, column: -1},
|
||||
end: {line: -1, column: -1}
|
||||
}
|
||||
var i = 0
|
||||
|
||||
let ast = cachedCompose(yaml)
|
||||
|
||||
// simply walks the tree using astValue path recursively to the point that
|
||||
// path is empty.
|
||||
return find(ast)
|
||||
|
||||
function find(astValue, astKeyValue) {
|
||||
if (astValue.tag === MAP_TAG) {
|
||||
for (i = 0; i < astValue.value.length; i++) {
|
||||
var pair = astValue.value[i]
|
||||
var key = pair[0]
|
||||
var value = pair[1]
|
||||
|
||||
if (key.value === path[0]) {
|
||||
path.shift()
|
||||
return find(value, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (astValue.tag === SEQ_TAG) {
|
||||
var item = astValue.value[path[0]]
|
||||
|
||||
if (item && item.tag) {
|
||||
path.shift()
|
||||
return find(item, astKeyValue)
|
||||
}
|
||||
}
|
||||
|
||||
// if path is still not empty we were not able to find the node
|
||||
if (path.length) {
|
||||
return invalidRange
|
||||
}
|
||||
|
||||
const range = {
|
||||
start: {
|
||||
line: astValue.start_mark.line,
|
||||
column: astValue.start_mark.column,
|
||||
pointer: astValue.start_mark.pointer,
|
||||
},
|
||||
end: {
|
||||
line: astValue.end_mark.line,
|
||||
column: astValue.end_mark.column,
|
||||
pointer: astValue.end_mark.pointer,
|
||||
}
|
||||
}
|
||||
|
||||
if(astKeyValue) {
|
||||
// eslint-disable-next-line camelcase
|
||||
range.key_start = {
|
||||
line: astKeyValue.start_mark.line,
|
||||
column: astKeyValue.start_mark.column,
|
||||
pointer: astKeyValue.start_mark.pointer,
|
||||
}
|
||||
// eslint-disable-next-line camelcase
|
||||
range.key_end = {
|
||||
line: astKeyValue.end_mark.line,
|
||||
column: astKeyValue.end_mark.column,
|
||||
pointer: astKeyValue.end_mark.pointer,
|
||||
}
|
||||
}
|
||||
|
||||
return range
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON Path for position object in the spec
|
||||
* @param {string} yaml
|
||||
* YAML or JSON string
|
||||
* @param {object} position
|
||||
* position in the YAML or JSON string with `line` and `column` properties.
|
||||
* `line` and `column` number are zero indexed
|
||||
*/
|
||||
export function pathForPosition(yaml, position) {
|
||||
|
||||
// Type check
|
||||
if (typeof yaml !== "string") {
|
||||
throw new TypeError("yaml should be a string")
|
||||
}
|
||||
if (typeof position !== "object" || typeof position.line !== "number" ||
|
||||
typeof position.column !== "number") {
|
||||
throw new TypeError("position should be an object with line and column" +
|
||||
" properties")
|
||||
}
|
||||
|
||||
try {
|
||||
var ast = cachedCompose(yaml)
|
||||
} catch (e) {
|
||||
console.error("Error composing AST", e)
|
||||
console.error(`Problem area:\n`, yaml.split("\n").slice(position.line - 5, position.line + 5).join("\n"))
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
var path = []
|
||||
|
||||
return find(ast)
|
||||
|
||||
/**
|
||||
* recursive find function that finds the node matching the position
|
||||
* @param {object} current - AST object to serach into
|
||||
*/
|
||||
function find(current) {
|
||||
|
||||
// algorythm:
|
||||
// is current a promitive?
|
||||
// // finish recursion without modifying the path
|
||||
// is current a hash?
|
||||
// // find a key or value that position is in their range
|
||||
// // if key is in range, terminate recursion with exisiting path
|
||||
// // if a value is in range push the corresponding key to the path
|
||||
// // andcontinue recursion
|
||||
// is current an array
|
||||
// // find the item that position is in it"s range and push the index
|
||||
// // of the item to the path and continue recursion with that item.
|
||||
|
||||
var i = 0
|
||||
|
||||
if (!current || [MAP_TAG, SEQ_TAG].indexOf(current.tag) === -1) {
|
||||
return path
|
||||
}
|
||||
|
||||
if (current.tag === MAP_TAG) {
|
||||
for (i = 0; i < current.value.length; i++) {
|
||||
var pair = current.value[i]
|
||||
var key = pair[0]
|
||||
var value = pair[1]
|
||||
|
||||
if (isInRange(key)) {
|
||||
return path
|
||||
} else if (isInRange(value)) {
|
||||
path.push(key.value)
|
||||
return find(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current.tag === SEQ_TAG) {
|
||||
for (i = 0; i < current.value.length; i++) {
|
||||
var item = current.value[i]
|
||||
|
||||
if (isInRange(item)) {
|
||||
path.push(i.toString())
|
||||
return find(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
|
||||
/**
|
||||
* Determines if position is in node"s range
|
||||
* @param {object} node - AST node
|
||||
* @return {Boolean} true if position is in node"s range
|
||||
*/
|
||||
function isInRange(node) {
|
||||
/* jshint camelcase: false */
|
||||
|
||||
// if node is in a single line
|
||||
if (node.start_mark.line === node.end_mark.line) {
|
||||
|
||||
return (position.line === node.start_mark.line) &&
|
||||
(node.start_mark.column <= position.column) &&
|
||||
(node.end_mark.column >= position.column)
|
||||
}
|
||||
|
||||
// if position is in the same line as start_mark
|
||||
if (position.line === node.start_mark.line) {
|
||||
return position.column >= node.start_mark.column
|
||||
}
|
||||
|
||||
// if position is in the same line as end_mark
|
||||
if (position.line === node.end_mark.line) {
|
||||
return position.column <= node.end_mark.column
|
||||
}
|
||||
|
||||
// if position is between start and end lines return true, otherwise
|
||||
// return false.
|
||||
return (node.start_mark.line < position.line) &&
|
||||
(node.end_mark.line > position.line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utility fns
|
||||
|
||||
|
||||
export let pathForPositionAsync = promisifySyncFn(pathForPosition)
|
||||
export let positionRangeForPathAsync = promisifySyncFn(positionRangeForPath)
|
||||
export let getLineNumberForPathAsync = promisifySyncFn(getLineNumberForPath)
|
||||
|
||||
function promisifySyncFn(fn) {
|
||||
return function(...args) {
|
||||
return new Promise((resolve) => resolve(fn(...args)))
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as AST from "./ast"
|
||||
import JumpToPath from "./jump-to-path"
|
||||
|
||||
export default function() {
|
||||
return {
|
||||
fn: { AST },
|
||||
components: { JumpToPath }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import YAML from "js-yaml"
|
||||
import YAML from "@kyleshockey/js-yaml"
|
||||
|
||||
export const parseYamlConfig = (yaml, system) => {
|
||||
try {
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import cx from "classnames"
|
||||
import { Parser, HtmlRenderer } from "commonmark"
|
||||
import Remarkable from "remarkable"
|
||||
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||
import { sanitizer } from "core/components/providers/markdown"
|
||||
|
||||
const parser = new Remarkable("commonmark")
|
||||
|
||||
export const Markdown = ({ source, className = "" }) => {
|
||||
if ( source ) {
|
||||
const parser = new Parser()
|
||||
const writer = new HtmlRenderer()
|
||||
const html = writer.render(parser.parse(source || ""))
|
||||
const html = parser.render(source)
|
||||
const sanitized = sanitizer(html)
|
||||
|
||||
if ( !source || !html || !sanitized ) {
|
||||
return null
|
||||
let trimmed
|
||||
|
||||
if(typeof sanitized === "string") {
|
||||
trimmed = sanitized.trim()
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
source={sanitized}
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: trimmed
|
||||
}}
|
||||
className={cx(className, "renderedMarkdown")}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import YAML from "js-yaml"
|
||||
import YAML from "@kyleshockey/js-yaml"
|
||||
import { Map } from "immutable"
|
||||
import parseUrl from "url-parse"
|
||||
import serializeError from "serialize-error"
|
||||
@@ -80,7 +80,7 @@ export const parseToJson = (str) => ({specActions, specSelectors, errActions}) =
|
||||
|
||||
let hasWarnedAboutResolveSpecDeprecation = false
|
||||
|
||||
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST }, getConfigs}) => {
|
||||
export const resolveSpec = (json, url) => ({specActions, specSelectors, errActions, fn: { fetch, resolve, AST = {} }, getConfigs}) => {
|
||||
if(!hasWarnedAboutResolveSpecDeprecation) {
|
||||
console.warn(`specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!`)
|
||||
hasWarnedAboutResolveSpecDeprecation = true
|
||||
@@ -100,7 +100,7 @@ export const resolveSpec = (json, url) => ({specActions, specSelectors, errActio
|
||||
url = specSelectors.url()
|
||||
}
|
||||
|
||||
let { getLineNumberForPath } = AST
|
||||
let getLineNumberForPath = AST.getLineNumberForPath ? AST.getLineNumberForPath : () => undefined
|
||||
|
||||
let specStr = specSelectors.specStr()
|
||||
|
||||
@@ -149,7 +149,7 @@ const debResolveSubtrees = debounce(async () => {
|
||||
errSelectors,
|
||||
fn: {
|
||||
resolveSubtree,
|
||||
AST: { getLineNumberForPath }
|
||||
AST = {}
|
||||
},
|
||||
specSelectors,
|
||||
specActions,
|
||||
@@ -160,6 +160,8 @@ const debResolveSubtrees = debounce(async () => {
|
||||
return
|
||||
}
|
||||
|
||||
let getLineNumberForPath = AST.getLineNumberForPath ? AST.getLineNumberForPath : () => undefined
|
||||
|
||||
const specStr = specSelectors.specStr()
|
||||
|
||||
const {
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import SplitPane from "react-split-pane"
|
||||
|
||||
const MODE_KEY = ["split-pane-mode"]
|
||||
const MODE_LEFT = "left"
|
||||
const MODE_RIGHT = "right"
|
||||
const MODE_BOTH = "both" // or anything other than left/right
|
||||
|
||||
export default class SplitPaneMode extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
threshold: PropTypes.number,
|
||||
|
||||
children: PropTypes.array,
|
||||
|
||||
layoutSelectors: PropTypes.object.isRequired,
|
||||
layoutActions: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
threshold: 100, // in pixels
|
||||
children: [],
|
||||
};
|
||||
|
||||
initializeComponent = (c) => {
|
||||
this.splitPane = c
|
||||
}
|
||||
|
||||
onDragFinished = () => {
|
||||
let { threshold, layoutActions } = this.props
|
||||
let { position, draggedSize } = this.splitPane.state
|
||||
this.draggedSize = draggedSize
|
||||
|
||||
let nearLeftEdge = position <= threshold
|
||||
let nearRightEdge = draggedSize <= threshold
|
||||
|
||||
layoutActions
|
||||
.changeMode(MODE_KEY, (
|
||||
nearLeftEdge
|
||||
? MODE_RIGHT : nearRightEdge
|
||||
? MODE_LEFT : MODE_BOTH
|
||||
))
|
||||
}
|
||||
|
||||
sizeFromMode = (mode, defaultSize) => {
|
||||
if(mode === MODE_LEFT) {
|
||||
this.draggedSize = null
|
||||
return "0px"
|
||||
} else if (mode === MODE_RIGHT) {
|
||||
this.draggedSize = null
|
||||
return "100%"
|
||||
}
|
||||
// mode === "both"
|
||||
return this.draggedSize || defaultSize
|
||||
}
|
||||
|
||||
render() {
|
||||
let { children, layoutSelectors } = this.props
|
||||
|
||||
const mode = layoutSelectors.whatMode(MODE_KEY)
|
||||
const left = mode === MODE_RIGHT ? <noscript/> : children[0]
|
||||
const right = mode === MODE_LEFT ? <noscript/> : children[1]
|
||||
const size = this.sizeFromMode(mode, "50%")
|
||||
|
||||
return (
|
||||
<SplitPane
|
||||
disabledClass={""}
|
||||
ref={this.initializeComponent}
|
||||
split='vertical'
|
||||
defaultSize={"50%"}
|
||||
primary="second"
|
||||
minSize={0}
|
||||
size={size}
|
||||
onDragFinished={this.onDragFinished}
|
||||
allowResize={mode !== MODE_LEFT && mode !== MODE_RIGHT }
|
||||
resizerStyle={{"flex": "0 0 auto", "position": "relative"}}
|
||||
>
|
||||
{ left }
|
||||
{ right }
|
||||
</SplitPane>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import SplitPaneMode from "./components/split-pane-mode"
|
||||
export default function SplitPaneModePlugin() {
|
||||
return {
|
||||
// statePlugins: {
|
||||
// layout: {
|
||||
// actions,
|
||||
// selectors,
|
||||
// }
|
||||
// },
|
||||
|
||||
components: {
|
||||
SplitPaneMode
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@ import spec from "core/plugins/spec"
|
||||
import view from "core/plugins/view"
|
||||
import samples from "core/plugins/samples"
|
||||
import logs from "core/plugins/logs"
|
||||
import ast from "core/plugins/ast"
|
||||
import swaggerJs from "core/plugins/swagger-js"
|
||||
import auth from "core/plugins/auth"
|
||||
import util from "core/plugins/util"
|
||||
import SplitPaneModePlugin from "core/plugins/split-pane-mode"
|
||||
import downloadUrlPlugin from "core/plugins/download-url"
|
||||
import configsPlugin from "core/plugins/configs"
|
||||
import deepLinkingPlugin from "core/plugins/deep-linking"
|
||||
@@ -55,6 +53,7 @@ import Info, {
|
||||
InfoBasePath
|
||||
} from "core/components/info"
|
||||
import InfoContainer from "core/containers/info"
|
||||
import JumpToPath from "core/components/jump-to-path"
|
||||
import Footer from "core/components/footer"
|
||||
import FilterContainer from "core/containers/filter"
|
||||
import ParamBody from "core/components/param-body"
|
||||
@@ -102,6 +101,7 @@ export default function() {
|
||||
liveResponse: LiveResponse,
|
||||
info: Info,
|
||||
InfoContainer,
|
||||
JumpToPath,
|
||||
onlineValidatorBadge: OnlineValidatorBadge,
|
||||
operations: Operations,
|
||||
operation: Operation,
|
||||
@@ -174,8 +174,6 @@ export default function() {
|
||||
swaggerJs,
|
||||
jsonSchemaComponents,
|
||||
auth,
|
||||
ast,
|
||||
SplitPaneModePlugin,
|
||||
downloadUrlPlugin,
|
||||
deepLinkingPlugin,
|
||||
filter,
|
||||
|
||||
Reference in New Issue
Block a user