Skip to content

Commit

Permalink
feat: prettify XML response (hoppscotch#3079)
Browse files Browse the repository at this point in the history
  • Loading branch information
nivedin authored May 30, 2023
1 parent 385a587 commit 26e5642
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 63 deletions.
1 change: 1 addition & 0 deletions packages/hoppscotch-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"vuedraggable-es": "^4.1.1",
"wonka": "^4.0.15",
"workbox-window": "^6.5.4",
"xml-formatter": "^3.4.1",
"yargs-parser": "^21.1.1"
},
"devDependencies": {
Expand Down
27 changes: 6 additions & 21 deletions packages/hoppscotch-common/src/components/http/RawBody.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import { useToast } from "@composables/toast"
import { isJSONContentType } from "~/helpers/utils/contenttypes"
import jsonLinter from "~/helpers/editor/linting/json"
import { readFileAsText } from "~/helpers/functional/files"
import xmlFormat from "xml-formatter"
type PossibleContentTypes = Exclude<
ValidContentTypes,
Expand Down Expand Up @@ -197,26 +198,10 @@ const prettifyRequestBody = () => {
}
const prettifyXML = (xml: string) => {
const PADDING = " ".repeat(2) // set desired indent size here
const reg = /(>)(<)(\/*)/g
let pad = 0
xml = xml.replace(reg, "$1\r\n$2$3")
return xml
.split("\r\n")
.map((node) => {
let indent = 0
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0
} else if (node.match(/^<\/\w/) && pad > 0) {
pad -= 1
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
indent = 1
} else {
indent = 0
}
pad += indent
return PADDING.repeat(pad - indent) + node
})
.join("\r\n")
return xmlFormat(xml, {
indentation: " ",
collapseContent: true,
lineSeparator: "\n",
})
}
</script>
24 changes: 23 additions & 1 deletion packages/hoppscotch-common/src/composables/codemirror.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
baseHighlightStyle,
} from "@helpers/editor/themes/baseTheme"
import { HoppEnvironmentPlugin } from "@helpers/editor/extensions/HoppEnvironment"
import xmlFormat from "xml-formatter"
import { platform } from "~/platform"
// TODO: Migrate from legacy mode

Expand Down Expand Up @@ -152,6 +153,27 @@ const getLanguage = (langMime: string): Language | null => {
return null
}

/**
* Uses xml-formatter to format the XML document
* @param doc Document to parse
* @param langMime Language mime type
* @returns Parsed document if mime type is xml, else returns the original document
*/
const parseDoc = (
doc: string | undefined,
langMime: string
): string | undefined => {
if (langMime === "application/xml" && doc) {
return xmlFormat(doc, {
indentation: " ",
collapseContent: true,
lineSeparator: "\n",
})
} else {
return doc
}
}

const getEditorLanguage = (
langMime: string,
linter: LinterDefinition | undefined,
Expand Down Expand Up @@ -261,7 +283,7 @@ export function useCodemirror(
view.value = new EditorView({
parent: el,
state: EditorState.create({
doc: value.value,
doc: parseDoc(value.value, options.extendedEditorConfig.mode ?? ""),
extensions,
}),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { pipe, flow } from "fp-ts/function"
import { tupleToRecord } from "~/helpers/functional/record"
import { safeParseJSON } from "~/helpers/functional/json"
import { optionChoose } from "~/helpers/functional/option"
import xmlFormat from "xml-formatter"

const isJSON = flow(safeParseJSON, O.isSome)

Expand Down Expand Up @@ -213,45 +214,18 @@ export function parseBody(
*/

/**
* Prettifies XML string
* Prettifies XML string using xml-formatter
* @param sourceXml The string to format
* @returns Indented XML string (uses spaces)
*/
function prettifyXml(sourceXml: string) {
return pipe(
O.tryCatch(() => {
const xmlDoc = new DOMParser().parseFromString(
sourceXml,
"application/xml"
)

if (xmlDoc.querySelector("parsererror")) {
throw new Error("Unstructured Body")
}

const xsltDoc = new DOMParser().parseFromString(
[
// describes how we want to modify the XML - indent everything
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
' <xsl:strip-space elements="*"/>',
' <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
' <xsl:value-of select="normalize-space(.)"/>',
" </xsl:template>",
' <xsl:template match="node()|@*">',
' <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
" </xsl:template>",
' <xsl:output indent="yes"/>',
"</xsl:stylesheet>",
].join("\n"),
"application/xml"
)

const xsltProcessor = new XSLTProcessor()
xsltProcessor.importStylesheet(xsltDoc)
const resultDoc = xsltProcessor.transformToDocument(xmlDoc)
const resultXml = new XMLSerializer().serializeToString(resultDoc)

return resultXml
return xmlFormat(sourceXml, {
indentation: " ",
collapseContent: true,
lineSeparator: "\n",
})
})
)
}
Expand Down
31 changes: 23 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 26e5642

Please sign in to comment.