From d72b72c5c6e0d7f4c9d816e9ba496e5a2484061a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vladim=C3=ADr=20Gorej?=
Date: Fri, 9 Jun 2023 15:34:39 +0200
Subject: [PATCH] feat(samples): add support for custom formats, encoders and
media types (#8905)
This change is specific to JSON Schema 2020-12
and OpenAPI 3.1.0.
Refs #8577
---
src/core/plugins/json-schema-2020-12/index.js | 8 +-
.../samples-extensions/fn/api/encoderAPI.js | 20 +
.../samples-extensions/fn/api/formatAPI.js | 19 +
.../samples-extensions/fn/api/mediaTypeAPI.js | 27 ++
.../fn/class/EncoderRegistry.js | 31 ++
.../fn/class/MediaTypeRegistry.js | 27 ++
.../samples-extensions/fn/class/Registry.js | 24 ++
.../samples-extensions/fn/core/random.js | 22 +
.../samples-extensions/fn/core/utils.js | 10 +
.../samples-extensions/fn/encoders/7bit.js | 6 +
.../samples-extensions/fn/encoders/8bit.js | 6 +
.../samples-extensions/fn/encoders/base16.js | 6 +
.../samples-extensions/fn/encoders/base32.js | 34 ++
.../samples-extensions/fn/encoders/base64.js | 6 +
.../samples-extensions/fn/encoders/binary.js | 6 +
.../fn/encoders/quoted-printable.js | 38 ++
.../fn/generators/date-time.js | 6 +
.../samples-extensions/fn/generators/date.js | 6 +
.../fn/generators/double.js | 6 +
.../fn/generators/duration.js | 6 +
.../samples-extensions/fn/generators/email.js | 6 +
.../samples-extensions/fn/generators/float.js | 6 +
.../fn/generators/hostname.js | 6 +
.../fn/generators/idn-email.js | 6 +
.../fn/generators/idn-hostname.js | 6 +
.../samples-extensions/fn/generators/int32.js | 6 +
.../samples-extensions/fn/generators/int64.js | 6 +
.../samples-extensions/fn/generators/ipv4.js | 6 +
.../samples-extensions/fn/generators/ipv6.js | 6 +
.../fn/generators/iri-reference.js | 6 +
.../samples-extensions/fn/generators/iri.js | 6 +
.../fn/generators/json-pointer.js | 6 +
.../fn/generators/media-types/application.js | 17 +
.../fn/generators/media-types/audio.js | 10 +
.../fn/generators/media-types/image.js | 10 +
.../fn/generators/media-types/text.js | 17 +
.../fn/generators/media-types/video.js | 10 +
.../fn/generators/password.js | 6 +
.../samples-extensions/fn/generators/regex.js | 6 +
.../fn/generators/relative-json-pointer.js | 6 +
.../samples-extensions/fn/generators/time.js | 6 +
.../fn/generators/uri-reference.js | 6 +
.../fn/generators/uri-template.js | 7 +
.../samples-extensions/fn/generators/uri.js | 6 +
.../samples-extensions/fn/generators/uuid.js | 6 +
.../samples-extensions/fn/index.js | 13 +
.../samples-extensions/{fn.js => fn/main.js} | 379 +-----------------
.../samples-extensions/fn/types/array.js | 52 +++
.../samples-extensions/fn/types/boolean.js | 9 +
.../samples-extensions/fn/types/index.js | 22 +
.../samples-extensions/fn/types/integer.js | 38 ++
.../samples-extensions/fn/types/null.js | 9 +
.../samples-extensions/fn/types/number.js | 76 ++++
.../samples-extensions/fn/types/object.js | 9 +
.../samples-extensions/fn/types/string.js | 142 +++++++
55 files changed, 877 insertions(+), 371 deletions(-)
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/encoderAPI.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/formatAPI.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/mediaTypeAPI.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/EncoderRegistry.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/MediaTypeRegistry.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/Registry.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/random.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/utils.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/7bit.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/8bit.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base16.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base32.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base64.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/binary.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/quoted-printable.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date-time.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/double.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/duration.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/email.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/float.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/hostname.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-email.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-hostname.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int32.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int64.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv4.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv6.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri-reference.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/json-pointer.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/application.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/audio.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/image.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/text.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/video.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/password.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/regex.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/relative-json-pointer.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/time.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-reference.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-template.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uuid.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/index.js
rename src/core/plugins/json-schema-2020-12/samples-extensions/{fn.js => fn/main.js} (61%)
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/array.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/boolean.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/index.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/integer.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/null.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/number.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/object.js
create mode 100644 src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/string.js
diff --git a/src/core/plugins/json-schema-2020-12/index.js b/src/core/plugins/json-schema-2020-12/index.js
index a92bfa8eef3..aceee751acf 100644
--- a/src/core/plugins/json-schema-2020-12/index.js
+++ b/src/core/plugins/json-schema-2020-12/index.js
@@ -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"
@@ -113,6 +116,9 @@ const JSONSchema202012Plugin = () => ({
useIsExpandedDeeply,
sampleFromSchema,
sampleFromSchemaGeneric,
+ sampleEncoderAPI: encoderAPI,
+ sampleFormatAPI: formatAPI,
+ sampleMediaTypeAPI: mediaTypeAPI,
createXMLExample,
memoizedSampleFromSchema,
memoizedCreateXMLExample,
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/encoderAPI.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/encoderAPI.js
new file mode 100644
index 00000000000..4d4ee996d12
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/encoderAPI.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/formatAPI.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/formatAPI.js
new file mode 100644
index 00000000000..9d1cd6b1d63
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/formatAPI.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/mediaTypeAPI.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/mediaTypeAPI.js
new file mode 100644
index 00000000000..9fac528bcc4
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/api/mediaTypeAPI.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/EncoderRegistry.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/EncoderRegistry.js
new file mode 100644
index 00000000000..f9c575adf9a
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/EncoderRegistry.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/MediaTypeRegistry.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/MediaTypeRegistry.js
new file mode 100644
index 00000000000..26be49ec2b7
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/MediaTypeRegistry.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/Registry.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/Registry.js
new file mode 100644
index 00000000000..e47f95074a4
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/class/Registry.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/random.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/random.js
new file mode 100644
index 00000000000..cd2ec61efad
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/random.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/utils.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/utils.js
new file mode 100644
index 00000000000..6d6f5a18a3c
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/core/utils.js
@@ -0,0 +1,10 @@
+/**
+ * @prettier
+ */
+export const isURI = (uri) => {
+ try {
+ return new URL(uri) && true
+ } catch {
+ return false
+ }
+}
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/7bit.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/7bit.js
new file mode 100644
index 00000000000..ac690cdd5fa
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/7bit.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const encode7bit = (content) => Buffer.from(content).toString("ascii")
+
+export default encode7bit
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/8bit.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/8bit.js
new file mode 100644
index 00000000000..5f7e7cc80c0
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/8bit.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const encode8bit = (content) => Buffer.from(content).toString("utf8")
+
+export default encode8bit
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base16.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base16.js
new file mode 100644
index 00000000000..eca3a35a710
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base16.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const encodeBase16 = (content) => Buffer.from(content).toString("hex")
+
+export default encodeBase16
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base32.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base32.js
new file mode 100644
index 00000000000..583a5a02865
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base32.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base64.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base64.js
new file mode 100644
index 00000000000..bb6378d1df3
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/base64.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const encodeBase64 = (content) => Buffer.from(content).toString("base64")
+
+export default encodeBase64
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/binary.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/binary.js
new file mode 100644
index 00000000000..0b1dd143f36
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/binary.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const encodeBinary = (content) => Buffer.from(content).toString("binary")
+
+export default encodeBinary
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/quoted-printable.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/quoted-printable.js
new file mode 100644
index 00000000000..2beb4465b9e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/encoders/quoted-printable.js
@@ -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
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date-time.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date-time.js
new file mode 100644
index 00000000000..30cee3a3a2d
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date-time.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const dateTimeGenerator = () => new Date().toISOString()
+
+export default dateTimeGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date.js
new file mode 100644
index 00000000000..a1c217dbe50
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/date.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const dateGenerator = () => new Date().toISOString().substring(0, 10)
+
+export default dateGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/double.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/double.js
new file mode 100644
index 00000000000..ec0e871097e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/double.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const doubleGenerator = () => 0.1
+
+export default doubleGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/duration.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/duration.js
new file mode 100644
index 00000000000..ae5a8d73535
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/duration.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const durationGenerator = () => "P3D" // expresses a duration of 3 days
+
+export default durationGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/email.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/email.js
new file mode 100644
index 00000000000..61ac4baab18
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/email.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const emailGenerator = () => "user@example.com"
+
+export default emailGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/float.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/float.js
new file mode 100644
index 00000000000..5b2f9c2acdc
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/float.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const floatGenerator = () => 0.1
+
+export default floatGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/hostname.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/hostname.js
new file mode 100644
index 00000000000..a1a65ff446a
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/hostname.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const hostnameGenerator = () => "example.com"
+
+export default hostnameGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-email.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-email.js
new file mode 100644
index 00000000000..948a89b8924
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-email.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const idnEmailGenerator = () => "실례@example.com"
+
+export default idnEmailGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-hostname.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-hostname.js
new file mode 100644
index 00000000000..7c50a026432
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/idn-hostname.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const idnHostnameGenerator = () => "실례.com"
+
+export default idnHostnameGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int32.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int32.js
new file mode 100644
index 00000000000..5c31cb0047e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int32.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const int32Generator = () => (2 ** 30) >>> 0
+
+export default int32Generator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int64.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int64.js
new file mode 100644
index 00000000000..611d1c593cb
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/int64.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const int64Generator = () => 2 ** 53 - 1
+
+export default int64Generator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv4.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv4.js
new file mode 100644
index 00000000000..8a18d45ce2b
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv4.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const ipv4Generator = () => "198.51.100.42"
+
+export default ipv4Generator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv6.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv6.js
new file mode 100644
index 00000000000..d933b87552c
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/ipv6.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const ipv6Generator = () => "2001:0db8:5b96:0000:0000:426f:8e17:642a"
+
+export default ipv6Generator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri-reference.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri-reference.js
new file mode 100644
index 00000000000..9cfe9e3395b
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri-reference.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const iriReferenceGenerator = () => "path/실례.html"
+
+export default iriReferenceGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri.js
new file mode 100644
index 00000000000..7930babd2fa
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/iri.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const iriGenerator = () => "https://실례.com/"
+
+export default iriGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/json-pointer.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/json-pointer.js
new file mode 100644
index 00000000000..0f14a483206
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/json-pointer.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const jsonPointerGenerator = () => "/a/b/c"
+
+export default jsonPointerGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/application.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/application.js
new file mode 100644
index 00000000000..b6ad219803d
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/application.js
@@ -0,0 +1,17 @@
+/**
+ * @prettier
+ */
+import { bytes } from "../../core/random"
+
+// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
+const applicationMediaTypesGenerators = {
+ "application/json": () => '{"key":"value"}',
+ "application/ld+json": () => '{"name": "John Doe"}',
+ "application/x-httpd-php": () => "Hello World!
'; ?>",
+ "application/rtf": () => String.raw`{\rtf1\adeflang1025\ansi\ansicpg1252\uc1`,
+ "application/x-sh": () => 'echo "Hello World!"',
+ "application/xhtml+xml": () => "content
",
+ "application/*": () => bytes(25).toString("binary"),
+}
+
+export default applicationMediaTypesGenerators
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/audio.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/audio.js
new file mode 100644
index 00000000000..8cc505e2c55
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/audio.js
@@ -0,0 +1,10 @@
+/**
+ * @prettier
+ */
+import { bytes } from "../../core/random"
+
+const audioMediaTypesGenerators = {
+ "audio/*": () => bytes(25).toString("binary"),
+}
+
+export default audioMediaTypesGenerators
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/image.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/image.js
new file mode 100644
index 00000000000..5c54e30ce85
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/image.js
@@ -0,0 +1,10 @@
+/**
+ * @prettier
+ */
+import { bytes } from "../../core/random"
+
+const imageMediaTypesGenerators = {
+ "image/*": () => bytes(25).toString("binary"),
+}
+
+export default imageMediaTypesGenerators
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/text.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/text.js
new file mode 100644
index 00000000000..6d5a1201138
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/text.js
@@ -0,0 +1,17 @@
+/**
+ * @prettier
+ */
+
+// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
+const textMediaTypesGenerators = {
+ "text/plain": () => "string",
+ "text/css": () => ".selector { border: 1px solid red }",
+ "text/csv": () => "value1,value2,value3",
+ "text/html": () => "content
",
+ "text/calendar": () => "BEGIN:VCALENDAR",
+ "text/javascript": () => "console.dir('Hello world!');",
+ "text/xml": () => 'John Doe',
+ "text/*": () => "string",
+}
+
+export default textMediaTypesGenerators
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/video.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/video.js
new file mode 100644
index 00000000000..d17f8c63eb1
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/media-types/video.js
@@ -0,0 +1,10 @@
+/**
+ * @prettier
+ */
+import { bytes } from "../../core/random"
+
+const videoMediaTypesGenerators = {
+ "video/*": () => bytes(25).toString("binary"),
+}
+
+export default videoMediaTypesGenerators
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/password.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/password.js
new file mode 100644
index 00000000000..c8272d64a8d
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/password.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const passwordGenerator = () => "********"
+
+export default passwordGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/regex.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/regex.js
new file mode 100644
index 00000000000..6419f2ac237
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/regex.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const regexGenerator = () => "^[a-z]+$"
+
+export default regexGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/relative-json-pointer.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/relative-json-pointer.js
new file mode 100644
index 00000000000..3ba5c4068d2
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/relative-json-pointer.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const relativeJsonPointerGenerator = () => "1/0"
+
+export default relativeJsonPointerGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/time.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/time.js
new file mode 100644
index 00000000000..5b583fe7f3e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/time.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const timeGenerator = () => new Date().toISOString().substring(11)
+
+export default timeGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-reference.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-reference.js
new file mode 100644
index 00000000000..cac8183d66c
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-reference.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const uriReferenceGenerator = () => "path/index.html"
+
+export default uriReferenceGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-template.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-template.js
new file mode 100644
index 00000000000..7191b909ecf
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri-template.js
@@ -0,0 +1,7 @@
+/**
+ * @prettier
+ */
+const uriTemplateGenerator = () =>
+ "https://example.com/dictionary/{term:1}/{term}"
+
+export default uriTemplateGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri.js
new file mode 100644
index 00000000000..1ef9850d338
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uri.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const uriGenerator = () => "https://example.com/"
+
+export default uriGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uuid.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uuid.js
new file mode 100644
index 00000000000..a725771c50e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/generators/uuid.js
@@ -0,0 +1,6 @@
+/**
+ * @prettier
+ */
+const uuidGenerator = () => "3fa85f64-5717-4562-b3fc-2c963f66afa6"
+
+export default uuidGenerator
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/index.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/index.js
new file mode 100644
index 00000000000..b6a34c0f64e
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/index.js
@@ -0,0 +1,13 @@
+/**
+ * @prettier
+ */
+export {
+ sampleFromSchema,
+ sampleFromSchemaGeneric,
+ createXMLExample,
+ memoizedSampleFromSchema,
+ memoizedCreateXMLExample,
+} from "./main"
+export { default as encoderAPI } from "./api/encoderAPI"
+export { default as formatAPI } from "./api/formatAPI"
+export { default as mediaTypeAPI } from "./api/mediaTypeAPI"
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/main.js
similarity index 61%
rename from src/core/plugins/json-schema-2020-12/samples-extensions/fn.js
rename to src/core/plugins/json-schema-2020-12/samples-extensions/fn/main.js
index ddb02e84980..e0775be5bfc 100644
--- a/src/core/plugins/json-schema-2020-12/samples-extensions/fn.js
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/main.js
@@ -2,378 +2,23 @@
* @prettier
*/
import XML from "xml"
-import RandExp from "randexp"
import isEmpty from "lodash/isEmpty"
-import randomBytes from "randombytes"
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils"
-import memoizeN from "../../../../helpers/memoizeN"
-
-const twentyFiveRandomBytesString = randomBytes(25).toString("binary")
-
-const stringFromRegex = (pattern) => {
- try {
- const randexp = new RandExp(pattern)
- return randexp.gen()
- } catch {
- // invalid regex should not cause a crash (regex syntax varies across languages)
- return "string"
- }
-}
-
-const contentEncodings = {
- "7bit": (content) => Buffer.from(content).toString("ascii"),
- "8bit": (content) => Buffer.from(content).toString("utf8"),
- binary: (content) => Buffer.from(content).toString("binary"),
- "quoted-printable": (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
- },
- base16: (content) => Buffer.from(content).toString("hex"),
- base32: (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
- },
- base64: (content) => Buffer.from(content).toString("base64"),
-}
-
-const encodeContent = (content, encoding) => {
- if (typeof contentEncodings[encoding] === "function") {
- return contentEncodings[encoding](content)
- }
- return content
-}
-
-// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
-const contentMediaTypes = {
- // text media type subtypes
- "text/plain": () => "string",
- "text/css": () => ".selector { border: 1px solid red }",
- "text/csv": () => "value1,value2,value3",
- "text/html": () => "content
",
- "text/calendar": () => "BEGIN:VCALENDAR",
- "text/javascript": () => "console.dir('Hello world!');",
- "text/xml": () => 'John Doe',
- "text/*": () => "string",
- // image media type subtypes
- "image/*": () => twentyFiveRandomBytesString,
- // audio media type subtypes
- "audio/*": () => twentyFiveRandomBytesString,
- // video media type subtypes
- "video/*": () => twentyFiveRandomBytesString,
- // application media type subtypes
- "application/json": () => '{"key":"value"}',
- "application/ld+json": () => '{"name": "John Doe"}',
- "application/x-httpd-php": () => "Hello World!'; ?>",
- "application/rtf": () => String.raw`{\rtf1\adeflang1025\ansi\ansicpg1252\uc1`,
- "application/x-sh": () => 'echo "Hello World!"',
- "application/xhtml+xml": () => "content
",
- "application/*": () => twentyFiveRandomBytesString,
-}
-
-const contentFromMediaType = (mediaType) => {
- const mediaTypeNoParams = mediaType.split(";").at(0)
- const topLevelMediaType = `${mediaTypeNoParams.split("/").at(0)}/*`
-
- if (typeof contentMediaTypes[mediaTypeNoParams] === "function") {
- return contentMediaTypes[mediaTypeNoParams]()
- }
- if (typeof contentMediaTypes[topLevelMediaType] === "function") {
- return contentMediaTypes[topLevelMediaType]()
- }
-
- return "string"
-}
-
-/* eslint-disable camelcase */
-const primitives = {
- string: (schema) => {
- const { pattern, contentEncoding, contentMediaType } = schema
- const content =
- typeof pattern === "string"
- ? stringFromRegex(pattern)
- : typeof contentMediaType === "string"
- ? contentFromMediaType(contentMediaType)
- : "string"
- return encodeContent(content, contentEncoding)
- },
- string_email: (schema) => {
- const { contentEncoding } = schema
- const content = "user@example.com"
- return encodeContent(content, contentEncoding)
- },
- "string_idn-email": (schema) => {
- const { contentEncoding } = schema
- const content = "실례@example.com"
- return encodeContent(content, contentEncoding)
- },
- string_hostname: (schema) => {
- const { contentEncoding } = schema
- const content = "example.com"
- return encodeContent(content, contentEncoding)
- },
- "string_idn-hostname": (schema) => {
- const { contentEncoding } = schema
- const content = "실례.com"
- return encodeContent(content, contentEncoding)
- },
- string_ipv4: (schema) => {
- const { contentEncoding } = schema
- const content = "198.51.100.42"
- return encodeContent(content, contentEncoding)
- },
- string_ipv6: (schema) => {
- const { contentEncoding } = schema
- const content = "2001:0db8:5b96:0000:0000:426f:8e17:642a"
- return encodeContent(content, contentEncoding)
- },
- string_uri: (schema) => {
- const { contentEncoding } = schema
- const content = "https://example.com/"
- return encodeContent(content, contentEncoding)
- },
- "string_uri-reference": (schema) => {
- const { contentEncoding } = schema
- const content = "path/index.html"
- return encodeContent(content, contentEncoding)
- },
- string_iri: (schema) => {
- const { contentEncoding } = schema
- const content = "https://실례.com/"
- return encodeContent(content, contentEncoding)
- },
- "string_iri-reference": (schema) => {
- const { contentEncoding } = schema
- const content = "path/실례.html"
- return encodeContent(content, contentEncoding)
- },
- string_uuid: (schema) => {
- const { contentEncoding } = schema
- const content = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
- return encodeContent(content, contentEncoding)
- },
- "string_uri-template": (schema) => {
- const { contentEncoding } = schema
- const content = "https://example.com/dictionary/{term:1}/{term}"
- return encodeContent(content, contentEncoding)
- },
- "string_json-pointer": (schema) => {
- const { contentEncoding } = schema
- const content = "/a/b/c"
- return encodeContent(content, contentEncoding)
- },
- "string_relative-json-pointer": (schema) => {
- const { contentEncoding } = schema
- const content = "1/0"
- return encodeContent(content, contentEncoding)
- },
- "string_date-time": (schema) => {
- const { contentEncoding } = schema
- const content = new Date().toISOString()
- return encodeContent(content, contentEncoding)
- },
- string_date: (schema) => {
- const { contentEncoding } = schema
- const content = new Date().toISOString().substring(0, 10)
- return encodeContent(content, contentEncoding)
- },
- string_time: (schema) => {
- const { contentEncoding } = schema
- const content = new Date().toISOString().substring(11)
- return encodeContent(content, contentEncoding)
- },
- string_duration: (schema) => {
- const { contentEncoding } = schema
- const content = "P3D" // expresses a duration of 3 days
- return encodeContent(content, contentEncoding)
- },
- string_password: (schema) => {
- const { contentEncoding } = schema
- const content = "********"
- return encodeContent(content, contentEncoding)
- },
- string_regex: (schema) => {
- const { contentEncoding } = schema
- const content = "^[a-z]+$"
- return encodeContent(content, contentEncoding)
- },
- number: () => 0,
- number_float: () => 0.1,
- number_double: () => 0.1,
- integer: () => 0,
- integer_int32: () => (2 ** 30) >>> 0,
- integer_int64: () => 2 ** 53 - 1,
- boolean: (schema) =>
- typeof schema.default === "boolean" ? schema.default : true,
- null: () => null,
-}
-/* eslint-enable camelcase */
+import memoizeN from "../../../../../helpers/memoizeN"
+import typeMap from "./types/index"
+import { isURI } from "./core/utils"
const primitive = (schema) => {
schema = objectify(schema)
- const { type: typeList, format } = schema
+ const { type: typeList } = schema
const type = Array.isArray(typeList) ? typeList.at(0) : typeList
- const fn = primitives[`${type}_${format}`] || primitives[type]
-
- return typeof fn === "function" ? fn(schema) : `Unknown Type: ${schema.type}`
-}
-
-const isURI = (uri) => {
- try {
- return new URL(uri) && true
- } catch {
- return false
- }
-}
-
-const applyArrayConstraints = (array, constraints = {}) => {
- const { minItems, maxItems, uniqueItems } = constraints
- const { contains, minContains, maxContains } = constraints
- let constrainedArray = [...array]
-
- if (contains != null && typeof contains === "object") {
- if (Number.isInteger(minContains) && minContains > 1) {
- const containsItem = constrainedArray.at(0)
- for (let i = 1; i < minContains; i += 1) {
- constrainedArray.unshift(containsItem)
- }
- }
- if (Number.isInteger(maxContains) && maxContains > 0) {
- /**
- * This is noop. `minContains` already generate minimum required
- * number of items that satisfies `contains`. `maxContains` would
- * have no effect.
- */
- }
- }
-
- if (Number.isInteger(maxItems) && maxItems > 0) {
- constrainedArray = array.slice(0, maxItems)
- }
- if (Number.isInteger(minItems) && minItems > 0) {
- for (let i = 0; constrainedArray.length < minItems; i += 1) {
- constrainedArray.push(constrainedArray[i % constrainedArray.length])
- }
- }
-
- if (uniqueItems === true) {
- /**
- * If uniqueItems is true, it implies that every item in the array must be unique.
- * This overrides any minItems constraint that cannot be satisfied with unique items.
- * So if minItems is greater than the number of unique items,
- * it should be reduced to the number of unique items.
- */
- constrainedArray = Array.from(new Set(constrainedArray))
+ if (Object.hasOwn(typeMap, type)) {
+ return typeMap[type](schema)
}
- return constrainedArray
-}
-
-const applyNumberConstraints = (number, constraints = {}) => {
- const { minimum, maximum, exclusiveMinimum, exclusiveMaximum } = constraints
- const { multipleOf } = constraints
- const epsilon = Number.isInteger(number) ? 1 : Number.EPSILON
- let minValue = typeof minimum === "number" ? minimum : null
- let maxValue = typeof maximum === "number" ? maximum : null
- let constrainedNumber = number
-
- if (typeof exclusiveMinimum === "number") {
- minValue =
- minValue !== null
- ? Math.max(minValue, exclusiveMinimum + epsilon)
- : exclusiveMinimum + epsilon
- }
- if (typeof exclusiveMaximum === "number") {
- maxValue =
- maxValue !== null
- ? Math.min(maxValue, exclusiveMaximum - epsilon)
- : exclusiveMaximum - epsilon
- }
- constrainedNumber =
- (minValue > maxValue && number) || minValue || maxValue || constrainedNumber
-
- if (typeof multipleOf === "number" && multipleOf > 0) {
- const remainder = constrainedNumber % multipleOf
- constrainedNumber =
- remainder === 0
- ? constrainedNumber
- : constrainedNumber + multipleOf - remainder
- }
-
- return constrainedNumber
-}
-
-const applyStringConstraints = (string, constraints = {}) => {
- const { maxLength, minLength } = constraints
- let constrainedString = string
-
- if (Number.isInteger(maxLength) && maxLength > 0) {
- constrainedString = constrainedString.slice(0, maxLength)
- }
- if (Number.isInteger(minLength) && minLength > 0) {
- let i = 0
- while (constrainedString.length < minLength) {
- constrainedString += constrainedString[i++ % constrainedString.length]
- }
- }
-
- return constrainedString
+ return `Unknown Type: ${type}`
}
/**
@@ -823,7 +468,7 @@ export const sampleFromSchemaGeneric = (
]
}
- itemSamples = applyArrayConstraints(itemSamples, schema)
+ itemSamples = typeMap.array(schema, itemSamples)
if (xml.wrapped) {
res[displayName] = itemSamples
if (!isEmpty(_attr)) {
@@ -961,7 +606,7 @@ export const sampleFromSchemaGeneric = (
}
}
- sampleArray = applyArrayConstraints(sampleArray, schema)
+ sampleArray = typeMap.array(schema, sampleArray)
if (respectXML && xml.wrapped) {
res[displayName] = sampleArray
if (!isEmpty(_attr)) {
@@ -1055,12 +700,6 @@ export const sampleFromSchemaGeneric = (
} else if (schema) {
// display schema default
value = primitive(schema)
- if (typeof value === "number") {
- value = applyNumberConstraints(value, schema)
- }
- if (typeof value === "string") {
- value = applyStringConstraints(value, schema)
- }
} else {
return
}
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/array.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/array.js
new file mode 100644
index 00000000000..abef5fc8ca4
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/array.js
@@ -0,0 +1,52 @@
+/**
+ * @prettier
+ */
+
+export const applyArrayConstraints = (array, constraints = {}) => {
+ const { minItems, maxItems, uniqueItems } = constraints
+ const { contains, minContains, maxContains } = constraints
+ let constrainedArray = [...array]
+
+ if (contains != null && typeof contains === "object") {
+ if (Number.isInteger(minContains) && minContains > 1) {
+ const containsItem = constrainedArray.at(0)
+ for (let i = 1; i < minContains; i += 1) {
+ constrainedArray.unshift(containsItem)
+ }
+ }
+ if (Number.isInteger(maxContains) && maxContains > 0) {
+ /**
+ * This is noop. `minContains` already generate minimum required
+ * number of items that satisfies `contains`. `maxContains` would
+ * have no effect.
+ */
+ }
+ }
+
+ if (Number.isInteger(maxItems) && maxItems > 0) {
+ constrainedArray = array.slice(0, maxItems)
+ }
+ if (Number.isInteger(minItems) && minItems > 0) {
+ for (let i = 0; constrainedArray.length < minItems; i += 1) {
+ constrainedArray.push(constrainedArray[i % constrainedArray.length])
+ }
+ }
+
+ if (uniqueItems === true) {
+ /**
+ * If uniqueItems is true, it implies that every item in the array must be unique.
+ * This overrides any minItems constraint that cannot be satisfied with unique items.
+ * So if minItems is greater than the number of unique items,
+ * it should be reduced to the number of unique items.
+ */
+ constrainedArray = Array.from(new Set(constrainedArray))
+ }
+
+ return constrainedArray
+}
+
+const arrayType = (schema, sampleArray) => {
+ return applyArrayConstraints(sampleArray, schema)
+}
+
+export default arrayType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/boolean.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/boolean.js
new file mode 100644
index 00000000000..e506215ff9f
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/boolean.js
@@ -0,0 +1,9 @@
+/**
+ * @prettier
+ */
+
+const booleanType = (schema) => {
+ return typeof schema.default === "boolean" ? schema.default : true
+}
+
+export default booleanType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/index.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/index.js
new file mode 100644
index 00000000000..dbd05c34768
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/index.js
@@ -0,0 +1,22 @@
+/**
+ * @prettier
+ */
+import arrayType from "./array"
+import objectType from "./object"
+import stringType from "./string"
+import numberType from "./number"
+import integerType from "./integer"
+import booleanType from "./boolean"
+import nullType from "./null"
+
+const typeMap = {
+ array: arrayType,
+ object: objectType,
+ string: stringType,
+ number: numberType,
+ integer: integerType,
+ boolean: booleanType,
+ null: nullType,
+}
+
+export default typeMap
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/integer.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/integer.js
new file mode 100644
index 00000000000..f5159a46789
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/integer.js
@@ -0,0 +1,38 @@
+/**
+ * @prettier
+ */
+import { integer as randomInteger } from "../core/random"
+import formatAPI from "../api/formatAPI"
+import int32Generator from "../generators/int32"
+import int64Generator from "../generators/int64"
+
+const generateFormat = (schema) => {
+ const { format } = schema
+
+ const formatGenerator = formatAPI(format)
+ if (typeof formatGenerator === "function") {
+ return formatGenerator(schema)
+ }
+
+ switch (format) {
+ case "int32": {
+ return int32Generator()
+ }
+ case "int64": {
+ return int64Generator()
+ }
+ }
+
+ return randomInteger()
+}
+const integerType = (schema) => {
+ const { format } = schema
+
+ if (typeof format === "string") {
+ return generateFormat(schema)
+ }
+
+ return randomInteger()
+}
+
+export default integerType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/null.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/null.js
new file mode 100644
index 00000000000..f7fd20d2bb8
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/null.js
@@ -0,0 +1,9 @@
+/**
+ * @prettier
+ */
+
+const nullType = () => {
+ return null
+}
+
+export default nullType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/number.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/number.js
new file mode 100644
index 00000000000..afc6720e0e9
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/number.js
@@ -0,0 +1,76 @@
+/**
+ * @prettier
+ */
+import { number as randomNumber } from "../core/random"
+import formatAPI from "../api/formatAPI"
+import floatGenerator from "../generators/float"
+import doubleGenerator from "../generators/double"
+
+const generateFormat = (schema) => {
+ const { format } = schema
+
+ const formatGenerator = formatAPI(format)
+ if (typeof formatGenerator === "function") {
+ return formatGenerator(schema)
+ }
+
+ switch (format) {
+ case "float": {
+ return floatGenerator()
+ }
+ case "double": {
+ return doubleGenerator()
+ }
+ }
+
+ return randomNumber()
+}
+
+const applyNumberConstraints = (number, constraints = {}) => {
+ const { minimum, maximum, exclusiveMinimum, exclusiveMaximum } = constraints
+ const { multipleOf } = constraints
+ const epsilon = Number.isInteger(number) ? 1 : Number.EPSILON
+ let minValue = typeof minimum === "number" ? minimum : null
+ let maxValue = typeof maximum === "number" ? maximum : null
+ let constrainedNumber = number
+
+ if (typeof exclusiveMinimum === "number") {
+ minValue =
+ minValue !== null
+ ? Math.max(minValue, exclusiveMinimum + epsilon)
+ : exclusiveMinimum + epsilon
+ }
+ if (typeof exclusiveMaximum === "number") {
+ maxValue =
+ maxValue !== null
+ ? Math.min(maxValue, exclusiveMaximum - epsilon)
+ : exclusiveMaximum - epsilon
+ }
+ constrainedNumber =
+ (minValue > maxValue && number) || minValue || maxValue || constrainedNumber
+
+ if (typeof multipleOf === "number" && multipleOf > 0) {
+ const remainder = constrainedNumber % multipleOf
+ constrainedNumber =
+ remainder === 0
+ ? constrainedNumber
+ : constrainedNumber + multipleOf - remainder
+ }
+
+ return constrainedNumber
+}
+
+const numberType = (schema) => {
+ const { format } = schema
+ let generatedNumber
+
+ if (typeof format === "string") {
+ generatedNumber = generateFormat(schema)
+ } else {
+ generatedNumber = randomNumber()
+ }
+
+ return applyNumberConstraints(generatedNumber, schema)
+}
+
+export default numberType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/object.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/object.js
new file mode 100644
index 00000000000..bc76c580e8c
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/object.js
@@ -0,0 +1,9 @@
+/**
+ * @prettier
+ */
+
+const objectType = () => {
+ throw new Error("Not implemented")
+}
+
+export default objectType
diff --git a/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/string.js b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/string.js
new file mode 100644
index 00000000000..0db8dd999d1
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/samples-extensions/fn/types/string.js
@@ -0,0 +1,142 @@
+/**
+ * @prettier
+ */
+import identity from "lodash/identity"
+
+import { string as randomString, randexp } from "../core/random"
+import emailGenerator from "../generators/email"
+import idnEmailGenerator from "../generators/idn-email"
+import hostnameGenerator from "../generators/hostname"
+import idnHostnameGenerator from "../generators/idn-hostname"
+import ipv4Generator from "../generators/ipv4"
+import ipv6Generator from "../generators/ipv6"
+import uriGenerator from "../generators/uri"
+import uriReferenceGenerator from "../generators/uri-reference"
+import iriGenerator from "../generators/iri"
+import iriReferenceGenerator from "../generators/iri-reference"
+import uuidGenerator from "../generators/uuid"
+import uriTemplateGenerator from "../generators/uri-template"
+import jsonPointerGenerator from "../generators/json-pointer"
+import relativeJsonPointerGenerator from "../generators/relative-json-pointer"
+import dateTimeGenerator from "../generators/date-time"
+import dateGenerator from "../generators/date"
+import timeGenerator from "../generators/time"
+import durationGenerator from "../generators/duration"
+import passwordGenerator from "../generators/password"
+import regexGenerator from "../generators/regex"
+import formatAPI from "../api/formatAPI"
+import encoderAPI from "../api/encoderAPI"
+import mediaTypeAPI from "../api/mediaTypeAPI"
+
+const generateFormat = (schema) => {
+ const { format } = schema
+
+ const formatGenerator = formatAPI(format)
+ if (typeof formatGenerator === "function") {
+ return formatGenerator(schema)
+ }
+
+ switch (format) {
+ case "email": {
+ return emailGenerator()
+ }
+ case "idn-email": {
+ return idnEmailGenerator()
+ }
+ case "hostname": {
+ return hostnameGenerator()
+ }
+ case "idn-hostname": {
+ return idnHostnameGenerator()
+ }
+ case "ipv4": {
+ return ipv4Generator()
+ }
+ case "ipv6": {
+ return ipv6Generator()
+ }
+ case "uri": {
+ return uriGenerator()
+ }
+ case "uri-reference": {
+ return uriReferenceGenerator()
+ }
+ case "iri": {
+ return iriGenerator()
+ }
+ case "iri-reference": {
+ return iriReferenceGenerator()
+ }
+ case "uuid": {
+ return uuidGenerator()
+ }
+ case "uri-template": {
+ return uriTemplateGenerator()
+ }
+ case "json-pointer": {
+ return jsonPointerGenerator()
+ }
+ case "relative-json-pointer": {
+ return relativeJsonPointerGenerator()
+ }
+ case "date-time": {
+ return dateTimeGenerator()
+ }
+ case "date": {
+ return dateGenerator()
+ }
+ case "time": {
+ return timeGenerator()
+ }
+ case "duration": {
+ return durationGenerator()
+ }
+ case "password": {
+ return passwordGenerator()
+ }
+ case "regex": {
+ return regexGenerator()
+ }
+ }
+
+ return randomString()
+}
+
+const applyStringConstraints = (string, constraints = {}) => {
+ const { maxLength, minLength } = constraints
+ let constrainedString = string
+
+ if (Number.isInteger(maxLength) && maxLength > 0) {
+ constrainedString = constrainedString.slice(0, maxLength)
+ }
+ if (Number.isInteger(minLength) && minLength > 0) {
+ let i = 0
+ while (constrainedString.length < minLength) {
+ constrainedString += constrainedString[i++ % constrainedString.length]
+ }
+ }
+
+ return constrainedString
+}
+const stringType = (schema) => {
+ const { pattern, format, contentEncoding, contentMediaType } = schema
+ const encode = encoderAPI(contentEncoding) || identity
+ let generatedString
+
+ if (typeof pattern === "string") {
+ generatedString = randexp(pattern)
+ } else if (typeof format === "string") {
+ generatedString = generateFormat(schema)
+ } else if (typeof contentMediaType === "string") {
+ const mediaTypeGenerator = mediaTypeAPI(contentMediaType)
+ if (typeof mediaTypeGenerator === "function") {
+ generatedString = mediaTypeGenerator(schema)
+ }
+ } else {
+ generatedString = randomString()
+ }
+
+ return encode(applyStringConstraints(generatedString, schema))
+}
+
+export default stringType