Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(samples): add support for custom formats, encoders and media types #8905

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/core/plugins/json-schema-2020-12/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ import {
createXMLExample,
memoizedSampleFromSchema,
memoizedCreateXMLExample,
} from "./samples-extensions/fn"
encoderAPI,
mediaTypeAPI,
formatAPI,
} from "./samples-extensions/fn/index"
import { JSONSchemaDeepExpansionContext } from "./context"
import { useFn, useConfig, useComponent, useIsExpandedDeeply } from "./hooks"
import { withJSONSchemaContext } from "./hoc"
Expand Down Expand Up @@ -113,6 +116,9 @@ const JSONSchema202012Plugin = () => ({
useIsExpandedDeeply,
sampleFromSchema,
sampleFromSchemaGeneric,
sampleEncoderAPI: encoderAPI,
sampleFormatAPI: formatAPI,
sampleMediaTypeAPI: mediaTypeAPI,
createXMLExample,
memoizedSampleFromSchema,
memoizedCreateXMLExample,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @prettier
*/

import EncoderRegistry from "core/plugins/json-schema-2020-12/samples-extensions/fn/class/EncoderRegistry"

const registry = new EncoderRegistry()

const encoderAPI = (encodingName, encoder) => {
if (typeof encoder === "function") {
return registry.register(encodingName, encoder)
} else if (encoder === null) {
return registry.unregister(encodingName)
}

return registry.get(encodingName)
}
encoderAPI.getDefaults = () => registry.defaults

export default encoderAPI
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @prettier
*/

import Registry from "../class/Registry"

const registry = new Registry()

const formatAPI = (format, generator) => {
if (typeof generator === "function") {
return registry.register(format, generator)
} else if (generator === null) {
return registry.unregister(format)
}

return registry.get(format)
}

export default formatAPI
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @prettier
*/

import MediaTypeRegistry from "../class/MediaTypeRegistry"

const registry = new MediaTypeRegistry()

const mediaTypeAPI = (mediaType, generator) => {
if (typeof generator === "function") {
return registry.register(mediaType, generator)
} else if (generator === null) {
return registry.unregister(mediaType)
}

const mediaTypeNoParams = mediaType.split(";").at(0)
const topLevelMediaType = `${mediaTypeNoParams.split("/").at(0)}/*`

return (
registry.get(mediaType) ||
registry.get(mediaTypeNoParams) ||
registry.get(topLevelMediaType)
)
}
mediaTypeAPI.getDefaults = () => registry.defaults

export default mediaTypeAPI
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @prettier
*/
import Registry from "./Registry"
import encode7bit from "../encoders/7bit"
import encode8bit from "../encoders/8bit"
import encodeBinary from "../encoders/binary"
import encodeQuotedPrintable from "../encoders/quoted-printable"
import encodeBase16 from "../encoders/base16"
import encodeBase32 from "../encoders/base32"
import encodeBase64 from "../encoders/base64"

class EncoderRegistry extends Registry {
#defaults = {
"7bit": encode7bit,
"8bit": encode8bit,
binary: encodeBinary,
"quoted-printable": encodeQuotedPrintable,
base16: encodeBase16,
base32: encodeBase32,
base64: encodeBase64,
}

data = { ...this.#defaults }

get defaults() {
return { ...this.#defaults }
}
}

export default EncoderRegistry
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @prettier
*/
import Registry from "./Registry"
import textMediaTypesGenerators from "../generators/media-types/text"
import imageMediaTypesGenerators from "../generators/media-types/image"
import audioMediaTypesGenerators from "../generators/media-types/audio"
import videoMediaTypesGenerators from "../generators/media-types/video"
import applicationMediaTypesGenerators from "../generators/media-types/application"

class MediaTypeRegistry extends Registry {
#defaults = {
...textMediaTypesGenerators,
...imageMediaTypesGenerators,
...audioMediaTypesGenerators,
...videoMediaTypesGenerators,
...applicationMediaTypesGenerators,
}

data = { ...this.#defaults }

get defaults() {
return { ...this.#defaults }
}
}

export default MediaTypeRegistry
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @prettier
*/
class Registry {
data = {}

register(name, value) {
this.data[name] = value
}

unregister(name) {
if (typeof name === "undefined") {
this.data = {}
} else {
delete this.data[name]
}
}

get(name) {
return this.data[name]
}
}

export default Registry
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @prettier
*/
import randomBytes from "randombytes"
import RandExp from "randexp"
export const bytes = (length) => randomBytes(length)

export const randexp = (pattern) => {
try {
const randexpInstance = new RandExp(pattern)
return randexpInstance.gen()
} catch {
// invalid regex should not cause a crash (regex syntax varies across languages)
return "string"
}
}

export const string = () => "string"

export const number = () => 0

export const integer = () => 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @prettier
*/
export const isURI = (uri) => {
try {
return new URL(uri) && true
} catch {
return false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const encode7bit = (content) => Buffer.from(content).toString("ascii")

export default encode7bit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const encode8bit = (content) => Buffer.from(content).toString("utf8")

export default encode8bit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const encodeBase16 = (content) => Buffer.from(content).toString("hex")

export default encodeBase16
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @prettier
*/
const encodeBase32 = (content) => {
const utf8Value = Buffer.from(content).toString("utf8")
const base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
let paddingCount = 0
let base32Str = ""
let buffer = 0
let bufferLength = 0

for (let i = 0; i < utf8Value.length; i++) {
buffer = (buffer << 8) | utf8Value.charCodeAt(i)
bufferLength += 8

while (bufferLength >= 5) {
base32Str += base32Alphabet.charAt((buffer >>> (bufferLength - 5)) & 31)
bufferLength -= 5
}
}

if (bufferLength > 0) {
base32Str += base32Alphabet.charAt((buffer << (5 - bufferLength)) & 31)
paddingCount = (8 - ((utf8Value.length * 8) % 5)) % 5
}

for (let i = 0; i < paddingCount; i++) {
base32Str += "="
}

return base32Str
}

export default encodeBase32
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const encodeBase64 = (content) => Buffer.from(content).toString("base64")

export default encodeBase64
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const encodeBinary = (content) => Buffer.from(content).toString("binary")

export default encodeBinary
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @prettier
*/
const encodeQuotedPrintable = (content) => {
let quotedPrintable = ""

for (let i = 0; i < content.length; i++) {
const charCode = content.charCodeAt(i)

if (charCode === 61) {
// ASCII content of "="
quotedPrintable += "=3D"
} else if (
(charCode >= 33 && charCode <= 60) ||
(charCode >= 62 && charCode <= 126) ||
charCode === 9 ||
charCode === 32
) {
quotedPrintable += content.charAt(i)
} else if (charCode === 13 || charCode === 10) {
quotedPrintable += "\r\n"
} else if (charCode > 126) {
// convert non-ASCII characters to UTF-8 and encode each byte
const utf8 = unescape(encodeURIComponent(content.charAt(i)))
for (let j = 0; j < utf8.length; j++) {
quotedPrintable +=
"=" + ("0" + utf8.charCodeAt(j).toString(16)).slice(-2).toUpperCase()
}
} else {
quotedPrintable +=
"=" + ("0" + charCode.toString(16)).slice(-2).toUpperCase()
}
}

return quotedPrintable
}

export default encodeQuotedPrintable
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const dateTimeGenerator = () => new Date().toISOString()

export default dateTimeGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const dateGenerator = () => new Date().toISOString().substring(0, 10)

export default dateGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const doubleGenerator = () => 0.1

export default doubleGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const durationGenerator = () => "P3D" // expresses a duration of 3 days

export default durationGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const emailGenerator = () => "user@example.com"

export default emailGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const floatGenerator = () => 0.1

export default floatGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const hostnameGenerator = () => "example.com"

export default hostnameGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const idnEmailGenerator = () => "실례@example.com"

export default idnEmailGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const idnHostnameGenerator = () => "실례.com"

export default idnHostnameGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const int32Generator = () => (2 ** 30) >>> 0

export default int32Generator
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @prettier
*/
const int64Generator = () => 2 ** 53 - 1

export default int64Generator
Loading